From 20314c64b22df5792233e9216f8b0ff1010b14ca Mon Sep 17 00:00:00 2001
From: Thatsaphorn Atchariyaphap
Date: Tue, 1 Jul 2025 17:37:30 +0900
Subject: [PATCH] Add theme integration and shadcn setup in `internal_frontend`
---
internal_frontend/app/globals.css | 124 ++++++++++++++++--
internal_frontend/app/layout.tsx | 48 ++++---
internal_frontend/components.json | 21 +++
.../components/theme-provider.tsx | 11 ++
internal_frontend/lib/utils.ts | 6 +
internal_frontend/package-lock.json | 68 +++++++++-
internal_frontend/package.json | 16 ++-
7 files changed, 254 insertions(+), 40 deletions(-)
create mode 100644 internal_frontend/components.json
create mode 100644 internal_frontend/components/theme-provider.tsx
create mode 100644 internal_frontend/lib/utils.ts
diff --git a/internal_frontend/app/globals.css b/internal_frontend/app/globals.css
index a2dc41e..4fced5d 100644
--- a/internal_frontend/app/globals.css
+++ b/internal_frontend/app/globals.css
@@ -1,26 +1,122 @@
@import "tailwindcss";
+@import "tw-animate-css";
-:root {
- --background: #ffffff;
- --foreground: #171717;
-}
+@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
+ --color-sidebar-ring: var(--sidebar-ring);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar: var(--sidebar);
+ --color-chart-5: var(--chart-5);
+ --color-chart-4: var(--chart-4);
+ --color-chart-3: var(--chart-3);
+ --color-chart-2: var(--chart-2);
+ --color-chart-1: var(--chart-1);
+ --color-ring: var(--ring);
+ --color-input: var(--input);
+ --color-border: var(--border);
+ --color-destructive: var(--destructive);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-accent: var(--accent);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-muted: var(--muted);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-secondary: var(--secondary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-primary: var(--primary);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-popover: var(--popover);
+ --color-card-foreground: var(--card-foreground);
+ --color-card: var(--card);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
}
-@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
+:root {
+ --radius: 0.625rem;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.13 0.028 261.692);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.13 0.028 261.692);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.13 0.028 261.692);
+ --primary: oklch(0.21 0.034 264.665);
+ --primary-foreground: oklch(0.985 0.002 247.839);
+ --secondary: oklch(0.967 0.003 264.542);
+ --secondary-foreground: oklch(0.21 0.034 264.665);
+ --muted: oklch(0.967 0.003 264.542);
+ --muted-foreground: oklch(0.551 0.027 264.364);
+ --accent: oklch(0.967 0.003 264.542);
+ --accent-foreground: oklch(0.21 0.034 264.665);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.928 0.006 264.531);
+ --input: oklch(0.928 0.006 264.531);
+ --ring: oklch(0.707 0.022 261.325);
+ --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.002 247.839);
+ --sidebar-foreground: oklch(0.13 0.028 261.692);
+ --sidebar-primary: oklch(0.21 0.034 264.665);
+ --sidebar-primary-foreground: oklch(0.985 0.002 247.839);
+ --sidebar-accent: oklch(0.967 0.003 264.542);
+ --sidebar-accent-foreground: oklch(0.21 0.034 264.665);
+ --sidebar-border: oklch(0.928 0.006 264.531);
+ --sidebar-ring: oklch(0.707 0.022 261.325);
+}
+
+.dark {
+ --background: oklch(0.13 0.028 261.692);
+ --foreground: oklch(0.985 0.002 247.839);
+ --card: oklch(0.21 0.034 264.665);
+ --card-foreground: oklch(0.985 0.002 247.839);
+ --popover: oklch(0.21 0.034 264.665);
+ --popover-foreground: oklch(0.985 0.002 247.839);
+ --primary: oklch(0.928 0.006 264.531);
+ --primary-foreground: oklch(0.21 0.034 264.665);
+ --secondary: oklch(0.278 0.033 256.848);
+ --secondary-foreground: oklch(0.985 0.002 247.839);
+ --muted: oklch(0.278 0.033 256.848);
+ --muted-foreground: oklch(0.707 0.022 261.325);
+ --accent: oklch(0.278 0.033 256.848);
+ --accent-foreground: oklch(0.985 0.002 247.839);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.551 0.027 264.364);
+ --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.21 0.034 264.665);
+ --sidebar-foreground: oklch(0.985 0.002 247.839);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0.002 247.839);
+ --sidebar-accent: oklch(0.278 0.033 256.848);
+ --sidebar-accent-foreground: oklch(0.985 0.002 247.839);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.551 0.027 264.364);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+ body {
+ @apply bg-background text-foreground;
}
}
-
-body {
- background: var(--background);
- color: var(--foreground);
- font-family: Arial, Helvetica, sans-serif;
-}
diff --git a/internal_frontend/app/layout.tsx b/internal_frontend/app/layout.tsx
index f7fa87e..f8d3976 100644
--- a/internal_frontend/app/layout.tsx
+++ b/internal_frontend/app/layout.tsx
@@ -1,34 +1,42 @@
-import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
+import type {Metadata} from "next";
+import {Geist, Geist_Mono} from "next/font/google";
import "./globals.css";
+import {ThemeProvider} from "@/components/theme-provider";
const geistSans = Geist({
- variable: "--font-geist-sans",
- subsets: ["latin"],
+ variable: "--font-geist-sans",
+ subsets: ["latin"],
});
const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
- subsets: ["latin"],
+ variable: "--font-geist-mono",
+ subsets: ["latin"],
});
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "Create Next App",
+ description: "Generated by create next app",
};
export default function RootLayout({
- children,
-}: Readonly<{
- children: React.ReactNode;
+ children,
+ }: Readonly<{
+ children: React.ReactNode;
}>) {
- return (
-
-
- {children}
-
-
- );
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ );
}
diff --git a/internal_frontend/components.json b/internal_frontend/components.json
new file mode 100644
index 0000000..8de3dce
--- /dev/null
+++ b/internal_frontend/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "app/globals.css",
+ "baseColor": "gray",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
\ No newline at end of file
diff --git a/internal_frontend/components/theme-provider.tsx b/internal_frontend/components/theme-provider.tsx
new file mode 100644
index 0000000..307725e
--- /dev/null
+++ b/internal_frontend/components/theme-provider.tsx
@@ -0,0 +1,11 @@
+"use client"
+
+import * as React from "react"
+import {ThemeProvider as NextThemesProvider} from "next-themes"
+
+export function ThemeProvider({
+ children,
+ ...props
+ }: Readonly>) {
+ return {children}
+}
\ No newline at end of file
diff --git a/internal_frontend/lib/utils.ts b/internal_frontend/lib/utils.ts
new file mode 100644
index 0000000..bd0c391
--- /dev/null
+++ b/internal_frontend/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/internal_frontend/package-lock.json b/internal_frontend/package-lock.json
index 86b97f7..fb18b75 100644
--- a/internal_frontend/package-lock.json
+++ b/internal_frontend/package-lock.json
@@ -8,9 +8,14 @@
"name": "internal_frontend",
"version": "0.1.0",
"dependencies": {
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.525.0",
"next": "15.3.4",
+ "next-themes": "^0.4.6",
"react": "^19.0.0",
- "react-dom": "^19.0.0"
+ "react-dom": "^19.0.0",
+ "tailwind-merge": "^3.3.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
@@ -21,6 +26,7 @@
"eslint": "^9",
"eslint-config-next": "15.3.4",
"tailwindcss": "^4",
+ "tw-animate-css": "^1.3.4",
"typescript": "^5"
}
},
@@ -2315,12 +2321,33 @@
"node": ">=18"
}
},
+ "node_modules/class-variance-authority": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "clsx": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://polar.sh/cva"
+ }
+ },
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
@@ -4499,6 +4526,15 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/lucide-react": {
+ "version": "0.525.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.525.0.tgz",
+ "integrity": "sha512-Tm1txJ2OkymCGkvwoHt33Y2JpN5xucVq1slHcgE6Lk0WjDfjgKWor5CdVER8U6DvcfMwh4M8XxmpTiyzfmfDYQ==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
@@ -4707,6 +4743,16 @@
}
}
},
+ "node_modules/next-themes": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
+ "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -5722,6 +5768,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tailwind-merge": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
+ "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
"node_modules/tailwindcss": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz",
@@ -5847,6 +5903,16 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
+ "node_modules/tw-animate-css": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.4.tgz",
+ "integrity": "sha512-dd1Ht6/YQHcNbq0znIT6dG8uhO7Ce+VIIhZUhjsryXsMPJQz3bZg7Q2eNzLwipb25bRZslGb2myio5mScd1TFg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Wombosvideo"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/internal_frontend/package.json b/internal_frontend/package.json
index 866b649..7894672 100644
--- a/internal_frontend/package.json
+++ b/internal_frontend/package.json
@@ -9,19 +9,25 @@
"lint": "next lint"
},
"dependencies": {
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.525.0",
+ "next": "15.3.4",
+ "next-themes": "^0.4.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
- "next": "15.3.4"
+ "tailwind-merge": "^3.3.1"
},
"devDependencies": {
- "typescript": "^5",
+ "@eslint/eslintrc": "^3",
+ "@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
- "@tailwindcss/postcss": "^4",
- "tailwindcss": "^4",
"eslint": "^9",
"eslint-config-next": "15.3.4",
- "@eslint/eslintrc": "^3"
+ "tailwindcss": "^4",
+ "tw-animate-css": "^1.3.4",
+ "typescript": "^5"
}
}