Explorar el Código

chore(dashboard): Set up tailwind v4 + Shadcn ui

Michael Bromley hace 11 meses
padre
commit
66ac2b67cc

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 355 - 91
package-lock.json


+ 21 - 0
packages/dashboard/components.json

@@ -0,0 +1,21 @@
+{
+  "$schema": "https://ui.shadcn.com/schema.json",
+  "style": "new-york",
+  "rsc": false,
+  "tsx": true,
+  "tailwind": {
+    "config": "",
+    "css": "src/styles.css",
+    "baseColor": "neutral",
+    "cssVariables": true,
+    "prefix": ""
+  },
+  "aliases": {
+    "components": "@/components",
+    "utils": "@/lib/utils",
+    "ui": "@/components/ui",
+    "lib": "@/lib",
+    "hooks": "@/hooks"
+  },
+  "iconLibrary": "lucide"
+}

+ 1 - 1
packages/dashboard/index.html

@@ -2,7 +2,7 @@
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+    <link rel="icon" type="image/svg+xml" href="/favicon.png" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>Vite + React</title>
   </head>

+ 9 - 1
packages/dashboard/package.json

@@ -10,9 +10,17 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@radix-ui/react-slot": "^1.1.2",
+    "@tailwindcss/vite": "^4.0.6",
     "@tanstack/react-router": "^1.105.0",
+    "class-variance-authority": "^0.7.1",
+    "clsx": "^2.1.1",
+    "lucide-react": "^0.475.0",
     "react": "^19.0.0",
-    "react-dom": "^19.0.0"
+    "react-dom": "^19.0.0",
+    "tailwind-merge": "^3.0.1",
+    "tailwindcss": "^4.0.6",
+    "tailwindcss-animate": "^1.0.7"
   },
   "devDependencies": {
     "@eslint/js": "^9.19.0",

+ 2 - 0
packages/dashboard/src/routes/index.tsx

@@ -1,3 +1,4 @@
+import { Button } from '@/components/ui/button.js';
 import * as React from 'react';
 import { createFileRoute } from '@tanstack/react-router';
 
@@ -9,6 +10,7 @@ function HomeComponent() {
     return (
         <div className="p-2">
             <h3>Welcome Home!</h3>
+            <Button>Click me</Button>
         </div>
     );
 }

+ 96 - 9
packages/dashboard/src/styles.css

@@ -1,13 +1,100 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+@import "tailwindcss";
+@import './tailwindcss-animate.css';
 
-html {
-    color-scheme: light dark;
+@custom-variant dark (&:is(.dark *));
+
+:root {
+  --background: hsl(0 0% 100%);
+  --foreground: hsl(0 0% 3.9%);
+  --card: hsl(0 0% 100%);
+  --card-foreground: hsl(0 0% 3.9%);
+  --popover: hsl(0 0% 100%);
+  --popover-foreground: hsl(0 0% 3.9%);
+  --primary: hsl(0 0% 9%);
+  --primary-foreground: hsl(0 0% 98%);
+  --secondary: hsl(0 0% 96.1%);
+  --secondary-foreground: hsl(0 0% 9%);
+  --muted: hsl(0 0% 96.1%);
+  --muted-foreground: hsl(0 0% 45.1%);
+  --accent: hsl(0 0% 96.1%);
+  --accent-foreground: hsl(0 0% 9%);
+  --destructive: hsl(0 84.2% 60.2%);
+  --destructive-foreground: hsl(0 0% 98%);
+  --border: hsl(0 0% 89.8%);
+  --input: hsl(0 0% 89.8%);
+  --ring: hsl(0 0% 3.9%);
+  --chart-1: hsl(12 76% 61%);
+  --chart-2: hsl(173 58% 39%);
+  --chart-3: hsl(197 37% 24%);
+  --chart-4: hsl(43 74% 66%);
+  --chart-5: hsl(27 87% 67%);
+  --radius: 0.6rem;
+}
+
+.dark {
+  --background: hsl(0 0% 3.9%);
+  --foreground: hsl(0 0% 98%);
+  --card: hsl(0 0% 3.9%);
+  --card-foreground: hsl(0 0% 98%);
+  --popover: hsl(0 0% 3.9%);
+  --popover-foreground: hsl(0 0% 98%);
+  --primary: hsl(0 0% 98%);
+  --primary-foreground: hsl(0 0% 9%);
+  --secondary: hsl(0 0% 14.9%);
+  --secondary-foreground: hsl(0 0% 98%);
+  --muted: hsl(0 0% 14.9%);
+  --muted-foreground: hsl(0 0% 63.9%);
+  --accent: hsl(0 0% 14.9%);
+  --accent-foreground: hsl(0 0% 98%);
+  --destructive: hsl(0 62.8% 30.6%);
+  --destructive-foreground: hsl(0 0% 98%);
+  --border: hsl(0 0% 14.9%);
+  --input: hsl(0 0% 14.9%);
+  --ring: hsl(0 0% 83.1%);
+  --chart-1: hsl(220 70% 50%);
+  --chart-2: hsl(160 60% 45%);
+  --chart-3: hsl(30 80% 55%);
+  --chart-4: hsl(280 65% 60%);
+  --chart-5: hsl(340 75% 55%);
 }
-* {
-    @apply border-gray-200 dark:border-gray-800;
+
+@theme inline {
+  --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-destructive-foreground: var(--destructive-foreground);
+  --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);
+  --radius-sm: calc(var(--radius) - 4px);
+  --radius-md: calc(var(--radius) - 2px);
+  --radius-lg: var(--radius);
+  --radius-xl: calc(var(--radius) + 4px);
 }
-body {
-    @apply bg-gray-50 text-gray-950 dark:bg-gray-900 dark:text-gray-200;
+
+@layer base {
+  * {
+    @apply border-border outline-ring/50;
+  }
+  body {
+    @apply bg-background text-foreground;
+  }
 }
+

+ 275 - 0
packages/dashboard/src/tailwindcss-animate.css

@@ -0,0 +1,275 @@
+/**
+ * TailwindCSS v4.0 compatible replacement for `tailwindcss-animate`.
+ *
+ * WARNING: The asterisks are not supported by some formatters and linters. You
+ * might want to exclude this file from formatters and linters for now.
+ *
+ * @author Luca Bosin <https://github.com/Wombosvideo>
+ * @license MIT
+ */
+
+@theme inline {
+    --animation-delay-0: 0s;
+    --animation-delay-75: 75ms;
+    --animation-delay-100: 0.1s;
+    --animation-delay-150: 0.15s;
+    --animation-delay-200: 0.2s;
+    --animation-delay-300: 0.3s;
+    --animation-delay-500: 0.5s;
+    --animation-delay-700: 0.7s;
+    --animation-delay-1000: 1s;
+
+    --animation-repeat-0: 0;
+    --animation-repeat-1: 1;
+    --animation-repeat-infinite: infinite;
+
+    --animation-direction-normal: normal;
+    --animation-direction-reverse: reverse;
+    --animation-direction-alternate: alternate;
+    --animation-direction-alternate-reverse: alternate-reverse;
+
+    --animation-fill-mode-none: none;
+    --animation-fill-mode-forwards: forwards;
+    --animation-fill-mode-backwards: backwards;
+    --animation-fill-mode-both: both;
+
+    --animate-in: var(--tw-duration, 150ms) var(--tw-ease, ease) enter;
+    --animate-out: var(--tw-duration, 150ms) var(--tw-ease, ease) exit;
+
+    --percentage-0: 0;
+    --percentage-5: 0.05;
+    --percentage-10: 0.1;
+    --percentage-15: 0.15;
+    --percentage-20: 0.2;
+    --percentage-25: 0.25;
+    --percentage-30: 0.3;
+    --percentage-35: 0.35;
+    --percentage-40: 0.4;
+    --percentage-45: 0.45;
+    --percentage-50: 0.5;
+    --percentage-55: 0.55;
+    --percentage-60: 0.6;
+    --percentage-65: 0.65;
+    --percentage-70: 0.7;
+    --percentage-75: 0.75;
+    --percentage-80: 0.8;
+    --percentage-85: 0.85;
+    --percentage-90: 0.9;
+    --percentage-95: 0.95;
+    --percentage-100: 1;
+
+    --translate-1/2: 50%;
+    --translate-1/3: 33.333333%;
+    --translate-2/3: 66.666667%;
+    --translate-1/4: 25%;
+    --translate-2/4: 50%;
+    --translate-3/4: 75%;
+    --translate-full: 100%;
+    --translate-px: 1px;
+    --translate-0: 0px;
+    --translate-0.5: 0.125rem;
+    --translate-1: 0.25rem;
+    --translate-1.5: 0.375rem;
+    --translate-2: 0.5rem;
+    --translate-2.5: 0.625rem;
+    --translate-3: 0.75rem;
+    --translate-3.5: 0.875rem;
+    --translate-4: 1rem;
+    --translate-5: 1.25rem;
+    --translate-6: 1.5rem;
+    --translate-7: 1.75rem;
+    --translate-8: 2rem;
+    --translate-9: 2.25rem;
+    --translate-10: 2.5rem;
+    --translate-11: 2.75rem;
+    --translate-12: 3rem;
+    --translate-14: 3.5rem;
+    --translate-16: 4rem;
+    --translate-20: 5rem;
+    --translate-24: 6rem;
+    --translate-28: 7rem;
+    --translate-32: 8rem;
+    --translate-36: 9rem;
+    --translate-40: 10rem;
+    --translate-44: 11rem;
+    --translate-48: 12rem;
+    --translate-52: 13rem;
+    --translate-56: 14rem;
+    --translate-60: 15rem;
+    --translate-64: 16rem;
+    --translate-72: 18rem;
+    --translate-80: 20rem;
+    --translate-96: 24rem;
+
+    @keyframes enter {
+        from {
+            opacity: var(--tw-enter-opacity, 1);
+            transform: translate3d(
+                var(--tw-enter-translate-x, 0),
+                var(--tw-enter-translate-y, 0),
+                0
+            )
+            scale3d(
+                var(--tw-enter-scale, 1),
+                var(--tw-enter-scale, 1),
+                var(--tw-enter-scale, 1)
+            )
+            rotate(var(--tw-enter-rotate, 0));
+        }
+    }
+
+    @keyframes exit {
+        to {
+            opacity: var(--tw-exit-opacity, 1);
+            transform: translate3d(
+                var(--tw-exit-translate-x, 0),
+                var(--tw-exit-translate-y, 0),
+                0
+            )
+            scale3d(
+                var(--tw-exit-scale, 1),
+                var(--tw-exit-scale, 1),
+                var(--tw-exit-scale, 1)
+            )
+            rotate(var(--tw-exit-rotate, 0));
+        }
+    }
+}
+
+/*
+ * Tailwind's default `duration` utility sets the `--tw-duration` variable, so
+ * can set `animation-duration` directly in the animation definition in the
+ * `@theme` section above. Same goes for the `animation-timing-function`, set
+ * with `--tw-ease`.
+ */
+
+@utility delay-* {
+    animation-delay: calc(--value(number) * 1ms);
+    animation-delay: --value(--animation-delay-*, [duration], [*]);
+}
+
+@utility repeat-* {
+    animation-iteration-count: --value(--animation-repeat-*, integer);
+}
+
+@utility direction-* {
+    animation-direction: --value(--animation-direction-*);
+}
+
+@utility fill-mode-* {
+    animation-fill-mode: --value(--animation-fill-mode-*);
+}
+
+@utility running {
+    animation-play-state: running;
+}
+@utility paused {
+    animation-play-state: paused;
+}
+
+@utility fade-in {
+    --tw-enter-opacity: 0;
+}
+@utility fade-in-* {
+    --tw-enter-opacity: --value(--percentage-*, [*]);
+}
+
+@utility fade-out {
+    --tw-exit-opacity: 0;
+}
+@utility fade-out-* {
+    --tw-exit-opacity: --value(--percentage-*, [*]);
+}
+
+@utility zoom-in {
+    --tw-enter-scale: 0;
+}
+@utility zoom-in-* {
+    --tw-enter-scale: calc(--value([percentage]) / 100%);
+    --tw-enter-scale: calc(--value([ratio], [number]));
+    --tw-enter-scale: --value(--percentage-*);
+}
+
+@utility zoom-out {
+    --tw-exit-scale: 0;
+}
+@utility zoom-out-* {
+    --tw-exit-scale: calc(--value([percentage]) / 100%);
+    --tw-exit-scale: calc(--value([ratio], [number]));
+    --tw-exit-scale: --value(--percentage-*);
+}
+
+@utility spin-in {
+    --tw-enter-rotate: 30deg;
+}
+@utility spin-in-* {
+    --tw-enter-rotate: calc(--value(number) * 1deg);
+    --tw-enter-rotate: --value(--rotate-*, [angle]);
+}
+
+@utility spin-out {
+    --tw-exit-rotate: 30deg;
+}
+@utility spin-out-* {
+    --tw-exit-rotate: calc(--value(number) * 1deg);
+    --tw-exit-rotate: --value(--rotate-*, [angle]);
+}
+
+@utility slide-in-from-top {
+    --tw-enter-translate-y: -100%;
+}
+@utility slide-in-from-top-* {
+    --tw-enter-translate-y: calc(--value(integer) * var(--spacing) * -1);
+    --tw-enter-translate-y: calc(--value(--translate-*, [percentage], ratio, [length]) * -1);
+}
+
+@utility slide-in-from-bottom {
+    --tw-enter-translate-y: 100%;
+}
+@utility slide-in-from-bottom-* {
+    --tw-enter-translate-y: calc(--value(integer) * var(--spacing));
+    --tw-enter-translate-y: --value(--translate-*, [percentage], ratio, [length]);
+}
+@utility slide-in-from-left {
+    --tw-enter-translate-x: -100%;
+}
+@utility slide-in-from-left-* {
+    --tw-enter-translate-x: calc(--value(integer) * var(--spacing) * -1);
+    --tw-enter-translate-x: calc(--value(--translate-*, [percentage], ratio, [length]) * -1);
+}
+@utility slide-in-from-right {
+    --tw-enter-translate-x: 100%;
+}
+@utility slide-in-from-right-* {
+    --tw-enter-translate-x: calc(--value(integer) * var(--spacing));
+    --tw-enter-translate-x: --value(--translate-*, [percentage], ratio, [length]);
+}
+
+@utility slide-out-to-top {
+    --tw-exit-translate-y: -100%;
+}
+@utility slide-out-to-top-* {
+    --tw-exit-translate-y: calc(--value(integer) * var(--spacing) * -1);
+    --tw-exit-translate-y: calc(--value(--translate-*, [percentage], ratio, [length]) * -1);
+}
+@utility slide-out-to-bottom {
+    --tw-exit-translate-y: 100%;
+}
+@utility slide-out-to-bottom-* {
+    --tw-exit-translate-y: calc(--value(integer) * var(--spacing));
+    --tw-exit-translate-y: --value(--translate-*, [percentage], ratio, [length]);
+}
+@utility slide-out-to-left {
+    --tw-exit-translate-x: -100%;
+}
+@utility slide-out-to-left-* {
+    --tw-exit-translate-x: calc(--value(integer) * var(--spacing) * -1);
+    --tw-exit-translate-x: calc(--value(--translate-*, [percentage], ratio, [length]) * -1);
+}
+@utility slide-out-to-right {
+    --tw-exit-translate-x: 100%;
+}
+@utility slide-out-to-right-* {
+    --tw-exit-translate-x: calc(--value(integer) * var(--spacing));
+    --tw-exit-translate-x: --value(--translate-*, [percentage], ratio, [length]);
+}

+ 6 - 1
packages/dashboard/tsconfig.json

@@ -2,6 +2,11 @@
   "extends": ["../../tsconfig.json"],
   "compilerOptions": {
     "lib": ["dom"],
-    "jsx": "react"
+    "types": ["node"],
+    "jsx": "react",
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
   }
 }

+ 8 - 1
packages/dashboard/vite.config.js

@@ -1,8 +1,15 @@
 import { defineConfig } from 'vite';
+import path from 'path';
 import react from '@vitejs/plugin-react';
 import { TanStackRouterVite } from '@tanstack/router-plugin/vite';
+import tailwindcss from '@tailwindcss/vite';
 
 // https://vite.dev/config/
 export default defineConfig({
-    plugins: [TanStackRouterVite({ autoCodeSplitting: true }), react()],
+    plugins: [TanStackRouterVite({ autoCodeSplitting: true }), react(), tailwindcss()],
+    resolve: {
+        alias: {
+            '@': path.resolve(__dirname, './src'),
+        },
+    },
 });

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio