1
0

Compare commits

...

4 Commits

Author SHA1 Message Date
4fccc793bb docs: Fix url
All checks were successful
Remote Deploy / deploy (push) Successful in 2m0s
2026-02-22 17:34:46 +01:00
7c75a8a485 chore: Remove
All checks were successful
Remote Deploy / deploy (push) Successful in 1m28s
2026-02-12 20:21:20 +01:00
df9fa7c605 chore: Some minor website modification changes
All checks were successful
Remote Deploy / deploy (push) Successful in 1m5s
2026-02-12 20:18:37 +01:00
793cce4ae7 chore: Idk
All checks were successful
Remote Deploy / deploy (push) Successful in 20s
2026-02-12 18:17:01 +01:00
10 changed files with 94 additions and 72 deletions

View File

@@ -2,12 +2,6 @@
Jednoduchý parser pro SPŠE Ječná tabulku suplování. Jednoduchý parser pro SPŠE Ječná tabulku suplování.
## Environmental variables ## Self-hosting
- `SHAREPOINT_URL` - URL adresa sharepointu dané tabulky (volitelné, využije hard-coded URL) [Dokumentace zde](https://jecnarozvrh.jzitnik.dev/posts/self-hosting/)
- `EMAIL` - SPŠE Ječná account email (povinné, username@spsejecna.cz)
- `PASSWORD` - Heslo k SPŠE Ječná účtu
## Spouštění serveru
Just `npm start` 💀

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,8 @@
"build-noweb": "tsc", "build-noweb": "tsc",
"serve": "concurrently \"node dist/server.js\" \"node dist/cron-runner.js\"", "serve": "concurrently \"node dist/server.js\" \"node dist/cron-runner.js\"",
"dev-web": "cd web && hugo serve", "dev-web": "cd web && hugo serve",
"parse-timetable": "node scripts/load_static_schedule.js" "parse-timetable": "node scripts/load_static_schedule.js",
"dev-preview": "tsx server.ts"
}, },
"dependencies": { "dependencies": {
"axios": "^1.13.5", "axios": "^1.13.5",

View File

@@ -134,7 +134,7 @@ if (SERVE_WEB) {
// @ts-ignore // @ts-ignore
const nextApp = next({ const nextApp = next({
dev, dev,
dir: path.join(__dirname, '../viewer') dir: dev ? path.join(__dirname, 'viewer') : path.join(__dirname, '../viewer')
}) })
const handle = nextApp.getRequestHandler() const handle = nextApp.getRequestHandler()

View File

@@ -1,36 +0,0 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

View File

@@ -49,11 +49,11 @@ export default function RootLayout({
</AlertDescription> </AlertDescription>
</Alert> </Alert>
</div> </div>
<footer className="text-center text-xs text-white/70 pb-4"> <footer className="text-center text-xs text-foreground/70 pb-4">
&copy; 2026{" "} &copy; 2026{" "}
<a href="https://jzitnik.dev" target="_blank" className="underline hover:text-white/90">Jakub Žitník</a>{" "} <a href="https://jzitnik.dev" target="_blank" className="underline hover:text-foreground/90">Jakub Žitník</a>{" "}
{" "} {" "}
<a href="https://www.gnu.org/licenses/gpl-3.0.html" target="_blank" className="underline hover:text-white/90">Licencováno pod GNU GPL v3.0</a> <a href="https://www.gnu.org/licenses/gpl-3.0.html" target="_blank" className="underline hover:text-foreground/90">Licencováno pod GNU GPL v3.0</a>
</footer> </footer>
</div> </div>
<Toaster /> <Toaster />

View File

@@ -7,6 +7,15 @@ import { LocalData, SubstitutionData, ChangeEntry, Hour } from '@/lib/types';
import { Card } from '@/components/ui/card'; import { Card } from '@/components/ui/card';
import { capitalizeFirstLetter } from '@/lib/utils'; import { capitalizeFirstLetter } from '@/lib/utils';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
interface ScheduleViewerProps { interface ScheduleViewerProps {
localData: LocalData; localData: LocalData;
substitutionData: SubstitutionData | null; substitutionData: SubstitutionData | null;
@@ -133,11 +142,58 @@ export default function ScheduleViewer({ localData, substitutionData, hideSubsti
); );
} }
function LessonDialog({ lesson, children }: { lesson: Hour, children: React.ReactNode }) {
return (
<Dialog>
<DialogTrigger asChild className="cursor-pointer hover:bg-accent hover:text-accent-foreground transition-colors">
{children}
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{lesson.title || lesson.subject}</DialogTitle>
<DialogDescription>
Detailní informace o hodině
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<span className="font-bold text-right col-span-1">Předmět:</span>
<span className="col-span-3">{lesson.title} ({lesson.subject})</span>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<span className="font-bold text-right col-span-1">Učitel:</span>
<a
href={`https://spsejecna.cz/ucitel/${lesson.teacher.code}`}
target="_blank"
rel="noopener noreferrer"
className="col-span-3 text-primary underline-offset-4 hover:underline"
>
{lesson.teacher.name}
</a>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<span className="font-bold text-right col-span-1">Místnost:</span>
<a
href={`https://spsejecna.cz/ucebna/${lesson.room}`}
target="_blank"
rel="noopener noreferrer"
className="col-span-3 text-primary underline-offset-4 hover:underline"
>
{lesson.room}
</a>
</div>
</div>
</DialogContent>
</Dialog>
)
}
function CellContent({ staticLessons, change }: { staticLessons: Hour[], change: ChangeEntry | null | undefined }) { function CellContent({ staticLessons, change }: { staticLessons: Hour[], change: ChangeEntry | null | undefined }) {
if (change) { if (change) {
return ( return (
<div <div
className="w-full h-full p-2 text-xs flex items-center justify-center text-center font-medium shadow-sm" className="w-full h-full p-2 text-xs flex items-center justify-center text-center font-medium"
style={{ style={{
backgroundColor: change.backgroundColor || '#f0f0f0', backgroundColor: change.backgroundColor || '#f0f0f0',
color: change.foregroundColor ? "#" + change.foregroundColor.substring(3, 6) : '#000', color: change.foregroundColor ? "#" + change.foregroundColor.substring(3, 6) : '#000',
@@ -156,7 +212,8 @@ function CellContent({ staticLessons, change }: { staticLessons: Hour[], change:
return ( return (
<div className="flex flex-col min-h-[80px] h-full"> <div className="flex flex-col min-h-[80px] h-full">
{staticLessons.map((lesson, idx) => ( {staticLessons.map((lesson, idx) => (
<div key={idx} className="flex-1 flex flex-col justify-between p-1 text-[10px] border-b min-h-[40px]"> <LessonDialog key={idx} lesson={lesson}>
<div role="button" tabIndex={0} className="flex-1 flex flex-col justify-between p-1 text-[10px] border-b min-h-[40px] text-left">
<div className='flex justify-between'> <div className='flex justify-between'>
<div className="font-bold truncate">{lesson.subject}</div> <div className="font-bold truncate">{lesson.subject}</div>
<span className="truncate opacity-70">{capitalizeFirstLetter(lesson.teacher.code)}</span> <span className="truncate opacity-70">{capitalizeFirstLetter(lesson.teacher.code)}</span>
@@ -166,6 +223,7 @@ function CellContent({ staticLessons, change }: { staticLessons: Hour[], change:
<span className="truncate opacity-70">{lesson.group}</span> <span className="truncate opacity-70">{lesson.group}</span>
</div> </div>
</div> </div>
</LessonDialog>
))} ))}
</div> </div>
); );
@@ -173,12 +231,14 @@ function CellContent({ staticLessons, change }: { staticLessons: Hour[], change:
const lesson = staticLessons[0]; const lesson = staticLessons[0];
return ( return (
<div className="w-full min-h-[80px] h-full p-2 border-b flex flex-col justify-between text-xs hover:shadow-md transition-shadow"> <LessonDialog lesson={lesson}>
<div role="button" tabIndex={0} className="w-full min-h-[80px] h-full p-2 border-b flex flex-col justify-between text-xs text-left">
<div className="font-bold text-lg text-primary">{lesson.subject}</div> <div className="font-bold text-lg text-primary">{lesson.subject}</div>
<div className="flex justify-between items-end mt-1"> <div className="flex justify-between items-end mt-1">
<div className="font-mono font-medium">{lesson.room}</div> <div className="font-mono font-medium">{lesson.room}</div>
<div className="text-[10px] opacity-80" title={lesson.teacher.name}>{capitalizeFirstLetter(lesson.teacher.code)}</div> <div className="text-[10px] opacity-80" title={lesson.teacher.name}>{capitalizeFirstLetter(lesson.teacher.code)}</div>
</div> </div>
</div> </div>
</LessonDialog>
); );
} }

View File

@@ -1,10 +1,11 @@
import type { NextConfig } from "next"; import type { NextConfig } from "next";
import path from "path";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
reactCompiler: true, reactCompiler: true,
basePath: '/viewer', basePath: '/viewer',
turbopack: { turbopack: {
root: __dirname, root: process.env.NODE_ENV == "development" ? path.resolve(__dirname) : path.resolve(__dirname, '..'),
}, },
}; };

View File

@@ -23,7 +23,7 @@ Použití Dockeru je nejjednodušší způsob, jak projekt spustit, protože aut
1. **Klonování repozitáře**: 1. **Klonování repozitáře**:
```bash ```bash
git clone https://github.com/zitnik/jecnarozvrh.git git clone https://gitea.local.jzitnik.dev/jzitnik/jecnarozvrh.git
cd jecnarozvrh cd jecnarozvrh
``` ```

View File

@@ -22,15 +22,18 @@ pagination:
menu: menu:
main: main:
- name: Online client
url: /viewer
weight: 10
- name: Status - name: Status
url: https://status.jzitnik.dev url: https://status.jzitnik.dev
weight: 10 weight: 20
- name: Autor - name: Autor
url: https://jzitnik.dev url: https://jzitnik.dev
weight: 20 weight: 30
- name: Zdrojový kód - name: Zdrojový kód
url: https://gitea.jzitnik.dev/jzitnik/jecnarozvrh url: https://gitea.jzitnik.dev/jzitnik/jecnarozvrh
weight: 30 weight: 40
outputs: outputs:
home: home: