diff --git a/gs/frontend/aro/components.json b/gs/frontend/aro/components.json new file mode 100644 index 000000000..2b0833f09 --- /dev/null +++ b/gs/frontend/aro/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.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/gs/frontend/aro/package-lock.json b/gs/frontend/aro/package-lock.json index 9eba93f62..d59e9cef0 100644 --- a/gs/frontend/aro/package-lock.json +++ b/gs/frontend/aro/package-lock.json @@ -12,12 +12,16 @@ "@tanstack/react-query": "^5.90.2", "@tanstack/react-table": "^8.21.3", "@types/react-router-dom": "^5.3.3", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "leaflet": "^1.9.4", + "lucide-react": "^0.553.0", "react": "^19.2.0", "react-dom": "^19.1.1", "react-leaflet": "^5.0.0", "react-router-dom": "^7.9.2", "react-toastify": "^11.0.5", + "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.13" }, "devDependencies": { @@ -27,6 +31,7 @@ "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/leaflet": "^1.9.20", + "@types/node": "^24.10.1", "@types/react": "^19.1.13", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.3", @@ -35,6 +40,7 @@ "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.4.0", "jsdom": "^27.0.0", + "tw-animate-css": "^1.4.0", "typescript": "~5.8.3", "typescript-eslint": "^8.44.0", "vite": "^7.2.2", @@ -2076,6 +2082,17 @@ "@types/geojson": "*" } }, + "node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, "node_modules/@types/react": { "version": "19.2.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", @@ -2810,6 +2827,18 @@ "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/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -3781,7 +3810,8 @@ "version": "1.9.4", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "peer": true }, "node_modules/levn": { "version": "0.4.1", @@ -4065,6 +4095,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.553.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.553.0.tgz", + "integrity": "sha512-BRgX5zrWmNy/lkVAe0dXBgd7XQdZ3HTf+Hwe3c9WK6dqgnj9h+hxV+MDncM88xDWlCq27+TKvHGE70ViODNILw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -4811,6 +4850,16 @@ "dev": true, "license": "MIT" }, + "node_modules/tailwind-merge": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", + "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "4.1.14", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", @@ -5017,6 +5066,16 @@ "typescript": ">=4.8.4" } }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "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", @@ -5069,6 +5128,13 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", diff --git a/gs/frontend/aro/package.json b/gs/frontend/aro/package.json index d323b9ceb..6b883b144 100644 --- a/gs/frontend/aro/package.json +++ b/gs/frontend/aro/package.json @@ -15,12 +15,16 @@ "@tanstack/react-query": "^5.90.2", "@tanstack/react-table": "^8.21.3", "@types/react-router-dom": "^5.3.3", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "leaflet": "^1.9.4", + "lucide-react": "^0.553.0", "react": "^19.2.0", "react-dom": "^19.1.1", "react-leaflet": "^5.0.0", "react-router-dom": "^7.9.2", "react-toastify": "^11.0.5", + "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.13" }, "devDependencies": { @@ -30,6 +34,7 @@ "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/leaflet": "^1.9.20", + "@types/node": "^24.10.1", "@types/react": "^19.1.13", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.3", @@ -38,6 +43,7 @@ "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.4.0", "jsdom": "^27.0.0", + "tw-animate-css": "^1.4.0", "typescript": "~5.8.3", "typescript-eslint": "^8.44.0", "vite": "^7.2.2", diff --git a/gs/frontend/aro/src/index.css b/gs/frontend/aro/src/index.css index 4756baebe..3505c802e 100644 --- a/gs/frontend/aro/src/index.css +++ b/gs/frontend/aro/src/index.css @@ -1,21 +1,131 @@ @import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;700&display=swap'); @import "tailwindcss"; +@import "tw-animate-css"; + +* { + border-color: var(--border); + outline-color: color-mix(in oklch, var(--ring) 50%, transparent); +} + +body { + background-color: var(--background); + color: var(--foreground); + overflow: hidden; + display: flex; + font-family: var(--font-geist); +} + +#root { + height: 100%; + width: 100%; + overflow: hidden; + --font-geist: 'Geist', sans-serif; +} + +@custom-variant dark (&:is(.dark *)); @theme inline { - --font-geist: var(--font-geist) + --font-geist: var(--font-geist); + --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); + --color-foreground: var(--foreground); + --color-background: var(--background); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); } -@layer base { - body { - overflow: hidden; - display: flex; - font-family: var(--font-geist); - } +:root { + --radius: 0.625rem; + --background: #040910; + --foreground: #FFFFFF; + --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);} - #root { - height: 100%; - width: 100%; - overflow: hidden; - --font-geist: 'Geist', sans-serif; - } -} \ No newline at end of file +.dark { + --background: #040910; + --foreground: #FFFFFF; + --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);} diff --git a/gs/frontend/aro/src/lib/utils.ts b/gs/frontend/aro/src/lib/utils.ts new file mode 100644 index 000000000..bd0c391dd --- /dev/null +++ b/gs/frontend/aro/src/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/gs/frontend/aro/src/main.tsx b/gs/frontend/aro/src/main.tsx index bd6d400f8..e8d763753 100644 --- a/gs/frontend/aro/src/main.tsx +++ b/gs/frontend/aro/src/main.tsx @@ -3,14 +3,8 @@ import ReactDOM from "react-dom/client"; import App from "./App.tsx"; import "./index.css"; // default styles are applied here import { BrowserRouter } from "react-router-dom"; -import { CSS_VARIABLES } from "./utils/themes.ts"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -// Inject CSS variables from themes.ts into the document root -Object.entries(CSS_VARIABLES).forEach(([property, value]) => { - document.documentElement.style.setProperty(property, value); -}); - const queryClient = new QueryClient(); /** * @brief Main component displaying the main application, which is linked to the index.html file diff --git a/gs/frontend/aro/src/utils/themes.ts b/gs/frontend/aro/src/utils/themes.ts deleted file mode 100644 index 161ae83f9..000000000 --- a/gs/frontend/aro/src/utils/themes.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Styling constants for the ARO frontend - colors and font - */ - -const COLORS = { - // Background colors - DEFAULT_BACKGROUND_COLOR: "#040910", - - // Text colors - DEFAULT_FONT_COLOR: "#FFFFFF", -}; - -const FONT = { - DEFAULT_FONT: "Jaldi", -}; - -const FONT_WEIGHT = { - DEFAULT_FONT_WEIGHT: "400", - BOLD_FONT_WEIGHT: "700", -}; - -// exported CSS variables for use in html styling -export const CSS_VARIABLES = { - "--color-background": COLORS.DEFAULT_BACKGROUND_COLOR, - "--color-font": COLORS.DEFAULT_FONT_COLOR, - "--font-default": FONT.DEFAULT_FONT, - "--font-weight-default": FONT_WEIGHT.DEFAULT_FONT_WEIGHT, - "--font-weight-bold": FONT_WEIGHT.BOLD_FONT_WEIGHT, -}; \ No newline at end of file diff --git a/gs/frontend/aro/tsconfig.app.json b/gs/frontend/aro/tsconfig.app.json index a9b5a59ca..572734872 100644 --- a/gs/frontend/aro/tsconfig.app.json +++ b/gs/frontend/aro/tsconfig.app.json @@ -24,5 +24,11 @@ "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true }, - "include": ["src"] + "include": ["src"], + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } } diff --git a/gs/frontend/aro/tsconfig.json b/gs/frontend/aro/tsconfig.json index 1ffef600d..fec8c8e5c 100644 --- a/gs/frontend/aro/tsconfig.json +++ b/gs/frontend/aro/tsconfig.json @@ -3,5 +3,11 @@ "references": [ { "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" } - ] + ], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } } diff --git a/gs/frontend/aro/vite.config.ts b/gs/frontend/aro/vite.config.ts index cb0003f29..5c0171f64 100644 --- a/gs/frontend/aro/vite.config.ts +++ b/gs/frontend/aro/vite.config.ts @@ -1,3 +1,4 @@ +import path from "path"; import tailwindcss from "@tailwindcss/vite"; import react from "@vitejs/plugin-react"; import { defineConfig, type UserConfig } from "vite"; @@ -5,6 +6,11 @@ import { defineConfig, type UserConfig } from "vite"; // https://vite.dev/config/ export default defineConfig({ plugins: [react(), tailwindcss()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, server: { port: 5173, host: "0.0.0.0",