Compare commits

..

No commits in common. "ad4a9f0e7082677a65eeb9069cae95105d2e2e26" and "96412d49f7b19e119ed716484acea696e6c9b24f" have entirely different histories.

13 changed files with 51 additions and 361 deletions

View File

@ -1,17 +0,0 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/shadcn/components",
"utils": "@/lib/utils"
}
}

View File

@ -15,22 +15,17 @@
"@mantine/form": "^7.10.2",
"@mantine/hooks": "^7.10.2",
"@mantine/notifications": "^7.10.2",
"@radix-ui/react-slot": "^1.1.0",
"@tanstack/react-query": "^5.45.0",
"@tanstack/react-router": "^1.38.1",
"@tanstack/react-table": "^8.17.3",
"backend": "workspace:*",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"dayjs": "^1.11.11",
"hono": "^4.4.6",
"lucide-react": "^0.414.0",
"mantine-form-zod-resolver": "^1.1.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.2.1",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.23.8"
},
"devDependencies": {

View File

@ -6,23 +6,23 @@ import Event from "./types/Event";
dayjs.extend(isoWeek);
dayjs.extend(customParseFormat);
type Props<T extends Record<string, unknown> & Event> = {
type Props = {
day: dayjs.Dayjs;
startTime: dayjs.Dayjs;
endTime: dayjs.Dayjs;
events: T[];
renderCell?: (date: dayjs.Dayjs) => JSX.Element;
renderEvent?: (event: T) => JSX.Element;
events: Event[];
renderCell?: (events: Event[]) => JSX.Element;
renderEvent?: (event: Event) => JSX.Element;
};
export default function DayColumn<T extends Record<string, unknown> & Event>({
export default function DayColumn({
day,
startTime,
endTime,
events,
renderCell,
renderEvent,
}: Props<T>) {
}: Props) {
const isToday = day.isSame(dayjs(), "day");
return (
@ -30,7 +30,7 @@ export default function DayColumn<T extends Record<string, unknown> & Event>({
{/* Column Header */}
<div className="flex flex-col h-20 p-2 relative">
{isToday && (
<div className="w-full h-1 bg-primary-500 top-0 left-0 absolute rounded-t-lg" />
<div className="w-full h-1 bg-primary-500 top-0 left-0 absolute" />
)}
<p className="text-2xl font-bold">{day.date()}</p>
<p>{day.format("dddd")}</p>
@ -45,7 +45,27 @@ export default function DayColumn<T extends Record<string, unknown> & Event>({
<div key={i} className="border-t h-20 relative">
{renderCell ? (
<div className="w-full h-full relative">
{renderCell(currentDateTime)}
{renderCell(
events.filter((event) => {
// return event.start.isSame(
// startTime.add(i, "h"),
// "hour"
// );
return (
currentDateTime.isSame(
event.start,
"hour"
) ||
(currentDateTime.isAfter(
event.start
) &&
currentDateTime.isBefore(
event.end
))
);
})
)}
</div>
) : (
<button className="flex pr-1.5 w-full gap-1 relative hover:bg-gray-100 h-full"></button>

View File

@ -1,5 +1,5 @@
import dayjs, { Dayjs } from "dayjs";
import { useEffect, useMemo, useState } from "react";
import dayjs from "dayjs";
import { useMemo, useState } from "react";
import isoWeek from "dayjs/plugin/isoWeek";
import customParseFormat from "dayjs/plugin/customParseFormat";
@ -12,23 +12,15 @@ import WeekPicker from "./WeekPicker";
dayjs.extend(isoWeek);
dayjs.extend(customParseFormat);
type Props<T extends Record<string, unknown> & Event> = {
type Props = {
startTime?: dayjs.Dayjs;
endTime?: dayjs.Dayjs;
events: T[];
renderCell?: (date: dayjs.Dayjs) => JSX.Element;
renderEvent?: (event: T) => JSX.Element;
onDateChange?: (date: Dayjs) => void;
header?: {
center?: JSX.Element;
right?: JSX.Element;
};
events: Event[];
renderCell?: (events: Event[]) => JSX.Element;
renderEvent?: (event: Event) => JSX.Element;
};
export default function Timetable<T extends Record<string, unknown> & Event>({
events,
...props
}: Props<T>) {
export default function Timetable({ events, ...props }: Props) {
const [currentDate, setCurrentDate] = useState(dayjs());
const startTime = props.startTime ?? dayjs("08:00", "HH:mm");
@ -55,10 +47,6 @@ export default function Timetable<T extends Record<string, unknown> & Event>({
});
}, [currentDate, events]);
useEffect(() => {
props.onDateChange?.(currentDate);
}, [currentDate, props]);
return (
<div className="w-full h-full flex flex-col gap-4">
{/* Header */}
@ -94,16 +82,6 @@ export default function Timetable<T extends Record<string, unknown> & Event>({
onChange={(date) => setCurrentDate(dayjs(date))}
/>
</div>
{/* Center */}
<div className="">
{props.header?.center && props.header.center}
</div>
{/* Right */}
<div className="">
{props.header?.right && props.header.right}
</div>
</div>
{/* The Table */}
<div className="flex">

View File

@ -1,69 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

View File

@ -1,6 +0,0 @@
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

View File

@ -222,7 +222,6 @@ export default function UserFormModal() {
type: "password",
label: "Password",
hidden: formType !== "create",
...form.getInputProps("password"),
},
{
type: "multi-select",

View File

@ -1,56 +0,0 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }

View File

@ -1,77 +1,14 @@
import colors from "tailwindcss/colors";
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class"],
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],
prefix: "",
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [require("tailwindcss-animate")],
}
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
colors: {
primary: colors.blue,
},
},
},
plugins: [],
};

View File

@ -22,9 +22,7 @@
"paths": {
"@/*": ["./src/*"]
},
"baseUrl": ".",
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]

View File

@ -5,13 +5,7 @@
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true,
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
"strict": true
},
"include": ["vite.config.ts"]
}

View File

@ -1,14 +1,13 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import { TanStackRouterVite } from "@tanstack/router-vite-plugin";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), TanStackRouterVite()],
resolve: {
alias: {
"@": path.resolve(__dirname,"/src"),
"@": "/src",
},
},
});

View File

@ -102,9 +102,6 @@ importers:
'@mantine/notifications':
specifier: ^7.10.2
version: 7.10.2(@mantine/core@7.10.2(@mantine/hooks@7.10.2(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.10.2(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot':
specifier: ^1.1.0
version: 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@tanstack/react-query':
specifier: ^5.45.0
version: 5.45.0(react@18.3.1)
@ -117,9 +114,6 @@ importers:
backend:
specifier: workspace:*
version: link:../backend
class-variance-authority:
specifier: ^0.7.0
version: 0.7.0
clsx:
specifier: ^2.1.1
version: 2.1.1
@ -129,9 +123,6 @@ importers:
hono:
specifier: ^4.4.6
version: 4.4.6
lucide-react:
specifier: ^0.414.0
version: 0.414.0(react@18.3.1)
mantine-form-zod-resolver:
specifier: ^1.1.0
version: 1.1.0(@mantine/form@7.10.2(react@18.3.1))(zod@3.23.8)
@ -144,12 +135,6 @@ importers:
react-icons:
specifier: ^5.2.1
version: 5.2.1(react@18.3.1)
tailwind-merge:
specifier: ^2.4.0
version: 2.4.0
tailwindcss-animate:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@3.4.4(ts-node@10.9.1(@types/node@20.14.2)(typescript@5.4.5)))
zod:
specifier: ^3.23.8
version: 3.23.8
@ -1431,24 +1416,6 @@ packages:
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
'@radix-ui/react-compose-refs@1.1.0':
resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-slot@1.1.0':
resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@rollup/rollup-android-arm-eabi@4.18.0':
resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==}
cpu: [arm]
@ -2376,9 +2343,6 @@ packages:
cjs-module-lexer@1.3.1:
resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==}
class-variance-authority@0.7.0:
resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==}
clean-regexp@1.0.0:
resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
engines: {node: '>=4'}
@ -2407,10 +2371,6 @@ packages:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'}
clsx@2.0.0:
resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
engines: {node: '>=6'}
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
@ -3904,11 +3864,6 @@ packages:
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
engines: {node: '>=12'}
lucide-react@0.414.0:
resolution: {integrity: sha512-Krr/MHg9AWoJc52qx8hyJ64X9++JNfS1wjaJviLM1EP/68VNB7Tv0VMldLCB1aUe6Ka9QxURPhQm/eB6cqOM3A==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
make-dir@3.1.0:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
@ -4833,14 +4788,6 @@ packages:
tabbable@6.2.0:
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
tailwind-merge@2.4.0:
resolution: {integrity: sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==}
tailwindcss-animate@1.0.7:
resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
tailwindcss@3.4.4:
resolution: {integrity: sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==}
engines: {node: '>=14.0.0'}
@ -6471,19 +6418,6 @@ snapshots:
'@pkgr/core@0.1.1': {}
'@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.3)(react@18.3.1)':
dependencies:
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.3
'@radix-ui/react-slot@1.1.0(@types/react@18.3.3)(react@18.3.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.3
'@rollup/rollup-android-arm-eabi@4.18.0':
optional: true
@ -7638,10 +7572,6 @@ snapshots:
cjs-module-lexer@1.3.1:
optional: true
class-variance-authority@0.7.0:
dependencies:
clsx: 2.0.0
clean-regexp@1.0.0:
dependencies:
escape-string-regexp: 1.0.5
@ -7665,8 +7595,6 @@ snapshots:
clone@1.0.4: {}
clsx@2.0.0: {}
clsx@2.1.1: {}
co@4.6.0:
@ -9590,10 +9518,6 @@ snapshots:
lru-cache@7.18.3: {}
lucide-react@0.414.0(react@18.3.1):
dependencies:
react: 18.3.1
make-dir@3.1.0:
dependencies:
semver: 6.3.1
@ -10615,12 +10539,6 @@ snapshots:
tabbable@6.2.0: {}
tailwind-merge@2.4.0: {}
tailwindcss-animate@1.0.7(tailwindcss@3.4.4(ts-node@10.9.1(@types/node@20.14.2)(typescript@5.4.5))):
dependencies:
tailwindcss: 3.4.4(ts-node@10.9.1(@types/node@20.14.2)(typescript@5.4.5))
tailwindcss@3.4.4(ts-node@10.9.1(@types/node@20.14.2)(typescript@5.4.5)):
dependencies:
'@alloc/quick-lru': 5.2.0