From 673a80485fa37c97badfd9b87a903d86a13850a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenan=20Ali=C4=87?= Date: Tue, 23 Sep 2025 20:33:56 +0200 Subject: [PATCH] Added shadcn --- web/components.json | 22 +++++++ web/package.json | 6 ++ web/pnpm-lock.yaml | 79 +++++++++++++++++++--- web/src/lib/utils.ts | 6 ++ web/src/routes/RootRouter.tsx | 2 +- web/src/styles/tailwind.css | 119 ++++++++++++++++++++++++++++++++++ web/src/vite-root.tsx | 2 +- web/tsconfig.app.json | 6 +- web/tsconfig.json | 11 ++-- web/vite.config.ts | 4 ++ 10 files changed, 242 insertions(+), 15 deletions(-) create mode 100644 web/components.json create mode 100644 web/src/lib/utils.ts diff --git a/web/components.json b/web/components.json new file mode 100644 index 0000000..9b0e510 --- /dev/null +++ b/web/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/styles/tailwind.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/web/package.json b/web/package.json index 1b4dde0..7060c57 100644 --- a/web/package.json +++ b/web/package.json @@ -11,13 +11,18 @@ }, "dependencies": { "@tailwindcss/vite": "^4.1.13", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.544.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.13", "wouter": "^3.7.1" }, "devDependencies": { "@eslint/js": "^9.36.0", + "@types/node": "^24.5.2", "@types/react": "^19.1.13", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.3", @@ -26,6 +31,7 @@ "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.4.0", "prettier-plugin-tailwindcss": "^0.6.14", + "tw-animate-css": "^1.3.8", "typescript": "~5.8.3", "typescript-eslint": "^8.44.0", "vite": "npm:rolldown-vite@7.1.12" diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 11ff898..dee2290 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -13,13 +13,25 @@ importers: dependencies: '@tailwindcss/vite': specifier: ^4.1.13 - version: 4.1.13(rolldown-vite@7.1.12(jiti@2.6.0)) + version: 4.1.13(rolldown-vite@7.1.12(@types/node@24.5.2)(jiti@2.6.0)) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-react: + specifier: ^0.544.0 + version: 0.544.0(react@19.1.1) react: specifier: ^19.1.1 version: 19.1.1 react-dom: specifier: ^19.1.1 version: 19.1.1(react@19.1.1) + tailwind-merge: + specifier: ^3.3.1 + version: 3.3.1 tailwindcss: specifier: ^4.1.13 version: 4.1.13 @@ -30,6 +42,9 @@ importers: '@eslint/js': specifier: ^9.36.0 version: 9.36.0 + '@types/node': + specifier: ^24.5.2 + version: 24.5.2 '@types/react': specifier: ^19.1.13 version: 19.1.13 @@ -38,7 +53,7 @@ importers: version: 19.1.9(@types/react@19.1.13) '@vitejs/plugin-react': specifier: ^5.0.3 - version: 5.0.3(rolldown-vite@7.1.12(jiti@2.6.0)) + version: 5.0.3(rolldown-vite@7.1.12(@types/node@24.5.2)(jiti@2.6.0)) eslint: specifier: ^9.36.0 version: 9.36.0(jiti@2.6.0) @@ -54,6 +69,9 @@ importers: prettier-plugin-tailwindcss: specifier: ^0.6.14 version: 0.6.14(prettier@3.6.2) + tw-animate-css: + specifier: ^1.3.8 + version: 1.3.8 typescript: specifier: ~5.8.3 version: 5.8.3 @@ -62,7 +80,7 @@ importers: version: 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.8.3) vite: specifier: npm:rolldown-vite@7.1.12 - version: rolldown-vite@7.1.12(jiti@2.6.0) + version: rolldown-vite@7.1.12(@types/node@24.5.2)(jiti@2.6.0) packages: @@ -454,6 +472,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/node@24.5.2': + resolution: {integrity: sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==} + '@types/react-dom@19.1.9': resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==} peerDependencies: @@ -588,6 +609,13 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -913,6 +941,11 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.544.0: + resolution: {integrity: sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} @@ -1177,6 +1210,9 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + tailwind-merge@3.3.1: + resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} + tailwindcss@4.1.13: resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==} @@ -1205,6 +1241,9 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tw-animate-css@1.3.8: + resolution: {integrity: sha512-Qrk3PZ7l7wUcGYhwZloqfkWCmaXZAoqjkdbIDvzfGshwGtexa/DAs9koXxIkrpEasyevandomzCBAV1Yyop5rw==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -1221,6 +1260,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + undici-types@7.12.0: + resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==} + update-browserslist-db@1.1.3: resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true @@ -1603,12 +1645,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13 '@tailwindcss/oxide-win32-x64-msvc': 4.1.13 - '@tailwindcss/vite@4.1.13(rolldown-vite@7.1.12(jiti@2.6.0))': + '@tailwindcss/vite@4.1.13(rolldown-vite@7.1.12(@types/node@24.5.2)(jiti@2.6.0))': dependencies: '@tailwindcss/node': 4.1.13 '@tailwindcss/oxide': 4.1.13 tailwindcss: 4.1.13 - vite: rolldown-vite@7.1.12(jiti@2.6.0) + vite: rolldown-vite@7.1.12(@types/node@24.5.2)(jiti@2.6.0) '@tybys/wasm-util@0.10.1': dependencies: @@ -1640,6 +1682,10 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/node@24.5.2': + dependencies: + undici-types: 7.12.0 + '@types/react-dom@19.1.9(@types/react@19.1.13)': dependencies: '@types/react': 19.1.13 @@ -1741,7 +1787,7 @@ snapshots: '@typescript-eslint/types': 8.44.1 eslint-visitor-keys: 4.2.1 - '@vitejs/plugin-react@5.0.3(rolldown-vite@7.1.12(jiti@2.6.0))': + '@vitejs/plugin-react@5.0.3(rolldown-vite@7.1.12(@types/node@24.5.2)(jiti@2.6.0))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) @@ -1749,7 +1795,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.35 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: rolldown-vite@7.1.12(jiti@2.6.0) + vite: rolldown-vite@7.1.12(@types/node@24.5.2)(jiti@2.6.0) transitivePeerDependencies: - supports-color @@ -1810,6 +1856,12 @@ snapshots: chownr@3.0.0: {} + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2092,6 +2144,10 @@ snapshots: dependencies: yallist: 3.1.1 + lucide-react@0.544.0(react@19.1.1): + dependencies: + react: 19.1.1 + magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2191,7 +2247,7 @@ snapshots: reusify@1.1.0: {} - rolldown-vite@7.1.12(jiti@2.6.0): + rolldown-vite@7.1.12(@types/node@24.5.2)(jiti@2.6.0): dependencies: '@oxc-project/runtime': 0.90.0 fdir: 6.5.0(picomatch@4.0.3) @@ -2201,6 +2257,7 @@ snapshots: rolldown: 1.0.0-beta.39 tinyglobby: 0.2.15 optionalDependencies: + '@types/node': 24.5.2 fsevents: 2.3.3 jiti: 2.6.0 @@ -2249,6 +2306,8 @@ snapshots: dependencies: has-flag: 4.0.0 + tailwind-merge@3.3.1: {} + tailwindcss@4.1.13: {} tapable@2.2.3: {} @@ -2277,6 +2336,8 @@ snapshots: tslib@2.8.1: optional: true + tw-animate-css@1.3.8: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -2294,6 +2355,8 @@ snapshots: typescript@5.8.3: {} + undici-types@7.12.0: {} + update-browserslist-db@1.1.3(browserslist@4.26.2): dependencies: browserslist: 4.26.2 diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts new file mode 100644 index 0000000..42c7369 --- /dev/null +++ b/web/src/lib/utils.ts @@ -0,0 +1,6 @@ +/* Shadcn */ +import { twMerge } from "tailwind-merge"; +import { clsx, type ClassValue } from "clsx"; + +const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs)); +export { cn }; diff --git a/web/src/routes/RootRouter.tsx b/web/src/routes/RootRouter.tsx index 158a531..78a65f4 100644 --- a/web/src/routes/RootRouter.tsx +++ b/web/src/routes/RootRouter.tsx @@ -3,7 +3,7 @@ import { Router, Switch, Route } from "wouter"; import { useHashLocation } from "wouter/use-hash-location"; /* Routes */ -import NotFound from "./NotFound"; +import NotFound from "@/routes/NotFound"; const RootRouter = () => ( diff --git a/web/src/styles/tailwind.css b/web/src/styles/tailwind.css index f1d8c73..f4c1e9b 100644 --- a/web/src/styles/tailwind.css +++ b/web/src/styles/tailwind.css @@ -1 +1,120 @@ @import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/web/src/vite-root.tsx b/web/src/vite-root.tsx index 180019f..878bf8a 100644 --- a/web/src/vite-root.tsx +++ b/web/src/vite-root.tsx @@ -6,7 +6,7 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; /* Route-related */ -import RootRouter from "./routes/RootRouter"; +import RootRouter from "@/routes/RootRouter"; createRoot(document.getElementById("root")!).render( diff --git a/web/tsconfig.app.json b/web/tsconfig.app.json index a9b5a59..1992014 100644 --- a/web/tsconfig.app.json +++ b/web/tsconfig.app.json @@ -22,7 +22,11 @@ "noUnusedParameters": true, "erasableSyntaxOnly": true, "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true + "noUncheckedSideEffectImports": true, + + /* Shadcn */ + "baseUrl": ".", + "paths": { "@/*": ["./src/*"] } }, "include": ["src"] } diff --git a/web/tsconfig.json b/web/tsconfig.json index 1ffef60..4c8c5ca 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -1,7 +1,10 @@ { "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }], + + /* Shadcn */ + "compilerOptions": { + "baseUrl": ".", + "paths": { "@/*": ["./src/*"] } + } } diff --git a/web/vite.config.ts b/web/vite.config.ts index 2f37223..722cdd5 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -1,4 +1,5 @@ /* Vite config */ +import path from "path"; import { defineConfig } from "vite"; /* Vite plugins */ @@ -7,4 +8,7 @@ import tailwindcss from "@tailwindcss/vite"; export default defineConfig({ plugins: [react(), tailwindcss()], + + /* Shadcn */ + resolve: { alias: { "@": path.resolve(__dirname, "./src") } }, });