refactor: Consolidate global styling with Tailwind and HeroUI theme variables and refactor devtools integration.

This commit is contained in:
Jrodenas
2026-03-04 20:23:03 +01:00
parent 841f43285e
commit b4a6555e5e
16 changed files with 3702 additions and 1102 deletions

View File

@@ -1,23 +0,0 @@
{
"projectName": "findyourpilot",
"mode": "file-router",
"typescript": true,
"tailwind": true,
"packageManager": "npm",
"git": true,
"install": true,
"addOnOptions": {},
"includeExamples": true,
"envVarValues": {},
"routerOnly": false,
"version": 1,
"framework": "react-cra",
"chosenAddOns": [
"tanstack-query",
"shadcn",
"railway",
"sentry",
"biome",
"paraglide"
]
}

View File

@@ -20,10 +20,3 @@ Sentry.startSpan({ name: 'Requesting all the pokemon' }, async () => {
await fetch('https://api.pokemon.com/data/') await fetch('https://api.pokemon.com/data/')
}) })
``` ```
# shadcn instructions
Use the latest version of Shadcn to install new components, like this command to add a button component:
```bash
pnpm dlx shadcn@latest add button
```

View File

@@ -36,7 +36,7 @@
"formatter": { "formatter": {
"quoteStyle": "double", "quoteStyle": "double",
"semicolons": "asNeeded", "semicolons": "asNeeded",
"trailingCommas": "es5" "trailingCommas": "none"
} }
} }
} }

4276
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,45 +13,41 @@
"check": "biome check" "check": "biome check"
}, },
"dependencies": { "dependencies": {
"@heroui/react": "3.0.0-beta.7", "@heroui/react": "^3.0.0-beta.8",
"@heroui/styles": "3.0.0-beta.7", "@heroui/styles": "^3.0.0-beta.8",
"@sentry/tanstackstart-react": "^10.34.0", "@sentry/tanstackstart-react": "^10.42.0",
"@supabase/ssr": "^0.8.0", "@supabase/ssr": "^0.9.0",
"@supabase/supabase-js": "^2.98.0", "@supabase/supabase-js": "^2.98.0",
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.2.1",
"@tanstack/react-devtools": "^0.7.0", "@tanstack/react-query": "^5.90.21",
"@tanstack/react-query": "^5.66.5", "@tanstack/react-router": "^1.163.3",
"@tanstack/react-query-devtools": "^5.84.2", "@tanstack/react-router-ssr-query": "^1.163.3",
"@tanstack/react-router": "^1.132.0", "@tanstack/react-start": "^1.166.1",
"@tanstack/react-router-devtools": "^1.132.0", "@tanstack/router-plugin": "^1.164.0",
"@tanstack/react-router-ssr-query": "^1.131.7", "lucide-react": "^0.577.0",
"@tanstack/react-start": "^1.132.0", "nitro": "^3.0.1-alpha.2",
"@tanstack/router-plugin": "^1.132.0", "react": "^19.2.4",
"class-variance-authority": "^0.7.1", "react-dom": "^19.2.4",
"clsx": "^2.1.1", "tailwindcss": "^4.2.1",
"dotenv-cli": "^11.0.0", "tw-animate-css": "^1.4.0"
"lucide-react": "^0.561.0",
"nitro": "npm:nitro-nightly@latest",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.1.18",
"tw-animate-css": "^1.3.6"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.4.4", "@biomejs/biome": "^2.4.5",
"@inlang/paraglide-js": "^2.8.0", "@inlang/paraglide-js": "^2.13.1",
"@tanstack/devtools-vite": "^0.3.11", "@tanstack/devtools-vite": "^0.5.3",
"@testing-library/dom": "^10.4.0", "@tanstack/react-devtools": "^0.9.9",
"@testing-library/react": "^16.2.0", "@tanstack/react-router-devtools": "^1.163.3",
"@tanstack/react-query-devtools": "^5.91.3",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.2",
"@types/node": "^22.10.2", "@types/node": "^22.10.2",
"@types/react": "^19.2.0", "@types/react": "^19.2.14",
"@types/react-dom": "^19.2.0", "@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.0.4", "@vitejs/plugin-react": "^5.1.4",
"jsdom": "^27.0.0", "jsdom": "^28.1.0",
"typescript": "^5.7.2", "typescript": "^5.9.3",
"vite": "^7.1.7", "vite": "^7.3.1",
"vite-tsconfig-paths": "^5.1.4", "vite-tsconfig-paths": "^6.1.1",
"vitest": "^3.0.5" "vitest": "^3.2.4"
} }
} }

View File

@@ -1,9 +1,8 @@
import { Link } from '@tanstack/react-router' import { Link } from "@tanstack/react-router"
import { Globe, Home, Languages, Menu, Network, X } from "lucide-react"
import ParaglideLocaleSwitcher from './LocaleSwitcher.tsx' import { useState } from "react"
import ParaglideLocaleSwitcher from "./LocaleSwitcher.tsx"
import { useState } from 'react'
import { Globe, Home, Languages, Menu, Network, X } from 'lucide-react'
export default function Header() { export default function Header() {
const [isOpen, setIsOpen] = useState(false) const [isOpen, setIsOpen] = useState(false)
@@ -31,7 +30,7 @@ export default function Header() {
<aside <aside
className={`fixed top-0 left-0 h-full w-80 bg-gray-900 text-white shadow-2xl z-50 transform transition-transform duration-300 ease-in-out flex flex-col ${ className={`fixed top-0 left-0 h-full w-80 bg-gray-900 text-white shadow-2xl z-50 transform transition-transform duration-300 ease-in-out flex flex-col ${
isOpen ? 'translate-x-0' : '-translate-x-full' isOpen ? "translate-x-0" : "-translate-x-full"
}`} }`}
> >
<div className="flex items-center justify-between p-4 border-b border-gray-700"> <div className="flex items-center justify-between p-4 border-b border-gray-700">
@@ -52,7 +51,7 @@ export default function Header() {
className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2" className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2"
activeProps={{ activeProps={{
className: className:
'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', "flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2"
}} }}
> >
<Home size={20} /> <Home size={20} />
@@ -67,7 +66,7 @@ export default function Header() {
className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2" className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2"
activeProps={{ activeProps={{
className: className:
'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', "flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2"
}} }}
> >
<Network size={20} /> <Network size={20} />
@@ -80,7 +79,7 @@ export default function Header() {
className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2" className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2"
activeProps={{ activeProps={{
className: className:
'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', "flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2"
}} }}
> >
<Globe size={20} /> <Globe size={20} />
@@ -93,7 +92,7 @@ export default function Header() {
className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2" className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-2"
activeProps={{ activeProps={{
className: className:
'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', "flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2"
}} }}
> >
<Languages size={20} /> <Languages size={20} />

View File

@@ -0,0 +1,14 @@
import { TanStackDevtools } from "@tanstack/react-devtools"
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"
export const Devtools = () => {
return (
<TanStackDevtools
plugins={[
{ name: "TanStack Router", render: <TanStackRouterDevtools /> },
{ name: "TanStack Query", render: <ReactQueryDevtools /> }
]}
/>
)
}

View File

@@ -1,6 +1,6 @@
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools' import { ReactQueryDevtoolsPanel } from "@tanstack/react-query-devtools"
export default { export default {
name: 'Tanstack Query', name: "Tanstack Query",
render: <ReactQueryDevtoolsPanel />, render: <ReactQueryDevtoolsPanel />
} }

View File

@@ -1,34 +0,0 @@
import type { ReactNode } from 'react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
let context:
| {
queryClient: QueryClient
}
| undefined
export function getContext() {
if (context) {
return context
}
const queryClient = new QueryClient()
context = {
queryClient,
}
return context
}
export default function TanStackQueryProvider({
children,
}: {
children: ReactNode
}) {
const { queryClient } = getContext()
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
}

View File

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

View File

@@ -1,23 +1,29 @@
import { createRouter as createTanStackRouter } from '@tanstack/react-router' import { QueryClient } from "@tanstack/react-query"
import { routeTree } from './routeTree.gen' import { createRouter as createTanStackRouter } from "@tanstack/react-router"
import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"
import { getContext } from './integrations/tanstack-query/root-provider' import { routeTree } from "./routeTree.gen"
export function getRouter() { export function getRouter() {
const queryClient = new QueryClient()
const router = createTanStackRouter({ const router = createTanStackRouter({
routeTree, routeTree,
context: {
context: getContext(), queryClient
},
scrollRestoration: true, scrollRestoration: true,
defaultPreload: 'intent', defaultPreload: "intent",
defaultPreloadStaleTime: 0, defaultPreloadStaleTime: 0
})
setupRouterSsrQueryIntegration({
router,
queryClient
}) })
return router return router
} }
declare module '@tanstack/react-router' { declare module "@tanstack/react-router" {
interface Register { interface Register {
router: ReturnType<typeof getRouter> router: ReturnType<typeof getRouter>
} }

View File

@@ -1,19 +1,16 @@
import { TanStackDevtools } from "@tanstack/react-devtools"; import type { QueryClient } from "@tanstack/react-query"
import type { QueryClient } from "@tanstack/react-query";
import { import {
createRootRouteWithContext, createRootRouteWithContext,
HeadContent, HeadContent,
Scripts, Scripts
} from "@tanstack/react-router"; } from "@tanstack/react-router"
import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools"; import { Devtools } from "@/integrations/devtools"
import { getLocale } from "@/paraglide/runtime"; import { getLocale } from "@/paraglide/runtime"
import Header from "../components/Header"; import appCss from "@/styles/globals.css?url"
import TanStackQueryDevtools from "../integrations/tanstack-query/devtools"; import Header from "../components/Header"
import TanStackQueryProvider from "../integrations/tanstack-query/root-provider";
import appCss from "../styles.css?url";
interface MyRouterContext { interface MyRouterContext {
queryClient: QueryClient; queryClient: QueryClient
} }
export const Route = createRootRouteWithContext<MyRouterContext>()({ export const Route = createRootRouteWithContext<MyRouterContext>()({
@@ -21,32 +18,32 @@ export const Route = createRootRouteWithContext<MyRouterContext>()({
// Other redirect strategies are possible; see // Other redirect strategies are possible; see
// https://github.com/TanStack/router/tree/main/examples/react/i18n-paraglide#offline-redirect // https://github.com/TanStack/router/tree/main/examples/react/i18n-paraglide#offline-redirect
if (typeof document !== "undefined") { if (typeof document !== "undefined") {
document.documentElement.setAttribute("lang", getLocale()); document.documentElement.setAttribute("lang", getLocale())
} }
}, },
head: () => ({ head: () => ({
meta: [ meta: [
{ {
charSet: "utf-8", charSet: "utf-8"
}, },
{ {
name: "viewport", name: "viewport",
content: "width=device-width, initial-scale=1", content: "width=device-width, initial-scale=1"
}, },
{ {
title: "TanStack Start Starter", title: "TanStack Start Starter"
}, }
], ],
links: [ links: [
{ {
rel: "stylesheet", rel: "stylesheet",
href: appCss, href: appCss
}, }
], ]
}), }),
shellComponent: RootDocument, shellComponent: RootDocument
}); })
function RootDocument({ children }: { children: React.ReactNode }) { function RootDocument({ children }: { children: React.ReactNode }) {
return ( return (
@@ -55,24 +52,11 @@ function RootDocument({ children }: { children: React.ReactNode }) {
<HeadContent /> <HeadContent />
</head> </head>
<body> <body>
<TanStackQueryProvider>
<Header /> <Header />
{children} {children}
<TanStackDevtools <Devtools />
config={{
position: "bottom-right",
}}
plugins={[
{
name: "Tanstack Router",
render: <TanStackRouterDevtoolsPanel />,
},
TanStackQueryDevtools,
]}
/>
</TanStackQueryProvider>
<Scripts /> <Scripts />
</body> </body>
</html> </html>
); )
} }

View File

@@ -1,10 +1,10 @@
import { createFileRoute } from "@tanstack/react-router"; import { createFileRoute } from "@tanstack/react-router"
import { m } from "@/paraglide/messages"; import { m } from "@/paraglide/messages"
import LocaleSwitcher from "../components/LocaleSwitcher"; import LocaleSwitcher from "../components/LocaleSwitcher"
export const Route = createFileRoute("/demo/i18n")({ export const Route = createFileRoute("/demo/i18n")({
component: App, component: App
}); })
function App() { function App() {
return ( return (
@@ -24,5 +24,5 @@ function App() {
</div> </div>
</header> </header>
</div> </div>
); )
} }

View File

@@ -6,7 +6,7 @@ import {
Shield, Shield,
Sparkles, Sparkles,
Waves, Waves,
Zap, Zap
} from "lucide-react" } from "lucide-react"
export const Route = createFileRoute("/")({ component: App }) export const Route = createFileRoute("/")({ component: App })
@@ -17,45 +17,45 @@ function App() {
icon: <Zap className="w-12 h-12 text-cyan-400" />, icon: <Zap className="w-12 h-12 text-cyan-400" />,
title: "Powerful Server Functions", title: "Powerful Server Functions",
description: description:
"Write server-side code that seamlessly integrates with your client components. Type-safe, secure, and simple.", "Write server-side code that seamlessly integrates with your client components. Type-safe, secure, and simple."
}, },
{ {
icon: <Server className="w-12 h-12 text-cyan-400" />, icon: <Server className="w-12 h-12 text-cyan-400" />,
title: "Flexible Server Side Rendering", title: "Flexible Server Side Rendering",
description: description:
"Full-document SSR, streaming, and progressive enhancement out of the box. Control exactly what renders where.", "Full-document SSR, streaming, and progressive enhancement out of the box. Control exactly what renders where."
}, },
{ {
icon: <RouteIcon className="w-12 h-12 text-cyan-400" />, icon: <RouteIcon className="w-12 h-12 text-cyan-400" />,
title: "API Routes", title: "API Routes",
description: description:
"Build type-safe API endpoints alongside your application. No separate backend needed.", "Build type-safe API endpoints alongside your application. No separate backend needed."
}, },
{ {
icon: <Shield className="w-12 h-12 text-cyan-400" />, icon: <Shield className="w-12 h-12 text-cyan-400" />,
title: "Strongly Typed Everything", title: "Strongly Typed Everything",
description: description:
"End-to-end type safety from server to client. Catch errors before they reach production.", "End-to-end type safety from server to client. Catch errors before they reach production."
}, },
{ {
icon: <Waves className="w-12 h-12 text-cyan-400" />, icon: <Waves className="w-12 h-12 text-cyan-400" />,
title: "Full Streaming Support", title: "Full Streaming Support",
description: description:
"Stream data from server to client progressively. Perfect for AI applications and real-time updates.", "Stream data from server to client progressively. Perfect for AI applications and real-time updates."
}, },
{ {
icon: <Sparkles className="w-12 h-12 text-cyan-400" />, icon: <Sparkles className="w-12 h-12 text-cyan-400" />,
title: "Next Generation Ready", title: "Next Generation Ready",
description: description:
"Built from the ground up for modern web applications. Deploy anywhere JavaScript runs.", "Built from the ground up for modern web applications. Deploy anywhere JavaScript runs."
}, }
] ]
return ( return (
<div className="min-h-screen bg-gradient-to-b from-slate-900 via-slate-800 to-slate-900"> <div className="min-h-screen bg-linear-to-b from-slate-900 via-slate-800 to-slate-900">
<Button> Hola</Button> <Button> Hola</Button>
<section className="relative py-20 px-6 text-center overflow-hidden"> <section className="relative py-20 px-6 text-center overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-cyan-500/10 via-blue-500/10 to-purple-500/10"></div> <div className="absolute inset-0 bg-linear-to-r from-cyan-500/10 via-blue-500/10 to-purple-500/10"></div>
<div className="relative max-w-5xl mx-auto"> <div className="relative max-w-5xl mx-auto">
<div className="flex items-center justify-center gap-6 mb-6"> <div className="flex items-center justify-center gap-6 mb-6">
<img <img
@@ -63,9 +63,9 @@ function App() {
alt="TanStack Logo" alt="TanStack Logo"
className="w-24 h-24 md:w-32 md:h-32" className="w-24 h-24 md:w-32 md:h-32"
/> />
<h1 className="text-6xl md:text-7xl font-black text-white [letter-spacing:-0.08em]"> <h1 className="text-6xl md:text-7xl font-black text-white tracking-[-0.08em]">
<span className="text-gray-300">TANSTACK</span>{" "} <span className="text-gray-300">TANSTACK</span>{" "}
<span className="bg-gradient-to-r from-cyan-400 to-blue-400 bg-clip-text text-transparent"> <span className="bg-linear-to-r from-cyan-400 to-blue-400 bg-clip-text text-transparent">
START START
</span> </span>
</h1> </h1>

View File

@@ -1,26 +1,24 @@
import { paraglideVitePlugin } from "@inlang/paraglide-js"; import { paraglideVitePlugin } from "@inlang/paraglide-js"
import tailwindcss from "@tailwindcss/vite"; import tailwindcss from "@tailwindcss/vite"
import { devtools } from "@tanstack/devtools-vite"; import { devtools } from "@tanstack/devtools-vite"
import { tanstackStart } from "@tanstack/react-start/plugin/vite"; import { tanstackStart } from "@tanstack/react-start/plugin/vite"
import viteReact from "@vitejs/plugin-react"; import viteReact from "@vitejs/plugin-react"
import { nitro } from "nitro/vite"; import { nitro } from "nitro/vite"
import { defineConfig } from "vite"; import { defineConfig } from "vite"
import tsconfigPaths from "vite-tsconfig-paths"; import tsconfigPaths from "vite-tsconfig-paths"
const config = defineConfig({ export default defineConfig({
plugins: [ plugins: [
devtools(), devtools(),
paraglideVitePlugin({ paraglideVitePlugin({
project: "./project.inlang", project: "./project.inlang",
outdir: "./src/paraglide", outdir: "./src/paraglide",
strategy: ["url", "baseLocale"], strategy: ["url", "baseLocale"]
}), }),
nitro({ rollupConfig: { external: [/^@sentry\//] } }), nitro({ rollupConfig: { external: [/^@sentry\//] } }),
tsconfigPaths({ projects: ["./tsconfig.json"] }), tsconfigPaths({ projects: ["./tsconfig.json"] }),
tailwindcss(), tailwindcss(),
tanstackStart(), tanstackStart(),
viteReact(), viteReact()
], ]
}); })
export default config;