From 37e6fc35f9c75249976530c5a898aa647afef58e Mon Sep 17 00:00:00 2001 From: Michelle Date: Fri, 2 Jan 2026 18:29:47 +0400 Subject: [PATCH 1/6] docs: reorganise x_docs folder structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Folder Restructure: - Move completed task notes to `x_docs/OLD/` - Move reference notes to `x_docs/my_notes/` - Move active task folder to `x_docs/` root - Delete obsolete/redundant notes (colours, flex_grid_layout, globals-compare, etc.) New Documentation: - Add `authentication.md` and `navigation.md` to `OLD/` for architecture reference - Add `textbook/url-state.md` for searchParams pattern documentation Configuration: - Add `Read(x_docs/OLD/**)` to Claude deny list to prevent reading archived docs Consolidates project documentation by separating active work from completed tasks and archived reference material. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .claude/settings.json | 2 +- .../2026-01-01-right-sidebar/current.jpg | Bin .../2026-01-01-right-sidebar/handover.md | 2 +- .../2026-01-01-right-sidebar/pic1-target.jpg | Bin .../2025-12-14-eval-auth-ui-customise.md | 0 .../2025-12-17-make-mobile-nav.md | 0 .../{mine => OLD}/2025-12-17-page-spacing.md | 0 .../2025-12-25-layout-refactor.md | 0 x_docs/OLD/authentication.md | 169 +++ x_docs/OLD/navigation.md | 265 +++++ x_docs/mine/colours.md | 76 -- x_docs/mine/flex_grid_layout.md | 349 ------- x_docs/mine/globals-compare.md | 983 ------------------ x_docs/mine/nav_mobile_sidebar-and-rail.md | 255 ----- x_docs/{mine => my_notes}/WORDS.md | 0 .../{mine => my_notes}/caching-explained-1.md | 0 .../{mine => my_notes}/caching-explained-2.md | 0 .../{mine => my_notes}/micro-interactions.md | 0 .../{mine => my_notes}/secrets-reference.md | 0 x_docs/{mine => my_notes}/theme_resources.md | 0 x_docs/{mine => my_notes}/zustand.md | 0 x_docs/quick_notes.md | 30 - x_docs/textbook/url-state.md | 38 + 23 files changed, 474 insertions(+), 1695 deletions(-) rename x_docs/{mine => }/2026-01-01-right-sidebar/current.jpg (100%) rename x_docs/{mine => }/2026-01-01-right-sidebar/handover.md (99%) rename x_docs/{mine => }/2026-01-01-right-sidebar/pic1-target.jpg (100%) rename x_docs/{mine => OLD}/2025-12-14-eval-auth-ui-customise.md (100%) rename x_docs/{mine => OLD}/2025-12-17-make-mobile-nav.md (100%) rename x_docs/{mine => OLD}/2025-12-17-page-spacing.md (100%) rename x_docs/{mine => OLD}/2025-12-25-layout-refactor.md (100%) create mode 100644 x_docs/OLD/authentication.md create mode 100644 x_docs/OLD/navigation.md delete mode 100644 x_docs/mine/colours.md delete mode 100644 x_docs/mine/flex_grid_layout.md delete mode 100644 x_docs/mine/globals-compare.md delete mode 100644 x_docs/mine/nav_mobile_sidebar-and-rail.md rename x_docs/{mine => my_notes}/WORDS.md (100%) rename x_docs/{mine => my_notes}/caching-explained-1.md (100%) rename x_docs/{mine => my_notes}/caching-explained-2.md (100%) rename x_docs/{mine => my_notes}/micro-interactions.md (100%) rename x_docs/{mine => my_notes}/secrets-reference.md (100%) rename x_docs/{mine => my_notes}/theme_resources.md (100%) rename x_docs/{mine => my_notes}/zustand.md (100%) delete mode 100644 x_docs/quick_notes.md create mode 100644 x_docs/textbook/url-state.md diff --git a/.claude/settings.json b/.claude/settings.json index 79f72e0..0ab2e46 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -71,7 +71,7 @@ "WebFetch(domain:vercel.com)", "WebFetch(domain:vitest.dev)" ], - "deny": ["Read(**/.env)", "Read(**/.envrc)"], + "deny": ["Read(**/.env)", "Read(**/.envrc)", "Read(x_docs/OLD/**)"], "ask": [] }, "enabledPlugins": { diff --git a/x_docs/mine/2026-01-01-right-sidebar/current.jpg b/x_docs/2026-01-01-right-sidebar/current.jpg similarity index 100% rename from x_docs/mine/2026-01-01-right-sidebar/current.jpg rename to x_docs/2026-01-01-right-sidebar/current.jpg diff --git a/x_docs/mine/2026-01-01-right-sidebar/handover.md b/x_docs/2026-01-01-right-sidebar/handover.md similarity index 99% rename from x_docs/mine/2026-01-01-right-sidebar/handover.md rename to x_docs/2026-01-01-right-sidebar/handover.md index 8f152c6..49c8157 100644 --- a/x_docs/mine/2026-01-01-right-sidebar/handover.md +++ b/x_docs/2026-01-01-right-sidebar/handover.md @@ -91,7 +91,7 @@ Replace the dated `hover:bg-accent/50` overlay with Linear-style microinteractio --- -## Later: Devicon Integration +## Now: Devicon Integration ### Goal diff --git a/x_docs/mine/2026-01-01-right-sidebar/pic1-target.jpg b/x_docs/2026-01-01-right-sidebar/pic1-target.jpg similarity index 100% rename from x_docs/mine/2026-01-01-right-sidebar/pic1-target.jpg rename to x_docs/2026-01-01-right-sidebar/pic1-target.jpg diff --git a/x_docs/mine/2025-12-14-eval-auth-ui-customise.md b/x_docs/OLD/2025-12-14-eval-auth-ui-customise.md similarity index 100% rename from x_docs/mine/2025-12-14-eval-auth-ui-customise.md rename to x_docs/OLD/2025-12-14-eval-auth-ui-customise.md diff --git a/x_docs/mine/2025-12-17-make-mobile-nav.md b/x_docs/OLD/2025-12-17-make-mobile-nav.md similarity index 100% rename from x_docs/mine/2025-12-17-make-mobile-nav.md rename to x_docs/OLD/2025-12-17-make-mobile-nav.md diff --git a/x_docs/mine/2025-12-17-page-spacing.md b/x_docs/OLD/2025-12-17-page-spacing.md similarity index 100% rename from x_docs/mine/2025-12-17-page-spacing.md rename to x_docs/OLD/2025-12-17-page-spacing.md diff --git a/x_docs/mine/2025-12-25-layout-refactor.md b/x_docs/OLD/2025-12-25-layout-refactor.md similarity index 100% rename from x_docs/mine/2025-12-25-layout-refactor.md rename to x_docs/OLD/2025-12-25-layout-refactor.md diff --git a/x_docs/OLD/authentication.md b/x_docs/OLD/authentication.md new file mode 100644 index 0000000..8827822 --- /dev/null +++ b/x_docs/OLD/authentication.md @@ -0,0 +1,169 @@ +# Authentication with Clerk + +Last updated: 2026-02-02 + +This document describes how authentication is implemented in DevFlow using Clerk. + +--- + +## Overview + +Clerk provides authentication via a hosted UI approach. The application wraps Clerk's pre-built components (``, ``) with custom wrapper components for branding, whilst Clerk handles all authentication logic, session management, and OAuth flows. + +--- + +## Environment Variables + +Required in `.env.local`: + +``` +NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_... +CLERK_SECRET_KEY=sk_... + +NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in +NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up +NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/ +NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/ +``` + +The `NEXT_PUBLIC_CLERK_*_URL` variables tell Clerk where to redirect users. The fallback URLs determine where users land after authentication. + +--- + +## Architecture + +### Provider Hierarchy + +The provider setup in `app/layout.tsx`: + +``` +ClerkProvider (authentication context) + └── html + └── body + └── ThemeProvider (next-themes) + └── {children} +``` + +`ClerkProvider` must wrap the entire app (including ``) because Clerk needs to inject authentication context before any rendering occurs. The custom wrapper at `components/providers/clerk-provider.tsx` applies global theming and localisation defaults. + +### Proxy (Route Protection) + +`proxy.ts` (renamed from middleware.ts in Next.js 16) runs Clerk's middleware on every request: + +```ts +import { clerkMiddleware } from "@clerk/nextjs/server"; +export default clerkMiddleware(); +``` + +The matcher config excludes static files and includes API routes. By default, `clerkMiddleware()` makes authentication available on all routes without blocking unauthenticated users. To protect specific routes, you would add route matchers or use `auth().protect()` in route handlers. + +### Auth Routes + +Clerk uses catch-all routes to handle its multi-step authentication flows: + +- `app/(auth)/sign-in/[[...sign-in]]/page.tsx` +- `app/(auth)/sign-up/[[...sign-up]]/page.tsx` + +The `[[...slug]]` pattern captures all sub-paths (e.g., `/sign-in/factor-one`, `/sign-in/sso-callback`), allowing Clerk to manage its internal routing. + +Both pages render custom wrapper components (`ClerkSignIn`, `ClerkSignUp`) that wrap Clerk's `` and `` components with appearance customisations. + +### Auth Layout + +`app/(auth)/layout.tsx` provides a centred, full-screen background for auth pages using theme-aware CSS variables (`--auth-bg`). + +--- + +## Custom Wrapper Components + +### Sign In (`components/auth/clerk-signin.tsx`) + +A **client component** that uses `useTheme()` from next-themes to detect the current theme and pass the appropriate logo URL to Clerk. This is necessary because Clerk's `logoImageUrl` prop requires a static URL string and cannot use CSS variables. + +The component also customises header alignment (left-aligned rather than centred). + +### Sign Up (`components/auth/clerk-signup.tsx`) + +A **server component** with a static logo. Theme detection isn't needed here because the icon-only logo (`site-logo.svg`) works on both light and dark backgrounds. + +--- + +## UI Customisation + +Clerk's appearance is customised at two levels: + +### Global (ClerkProvider) + +`components/providers/clerk-provider.tsx` applies defaults to all Clerk components: + +- **Theme**: Uses `@clerk/themes/shadcn` for shadcn/ui visual consistency +- **CSS Layer**: `cssLayerName: "clerk"` ensures Tailwind utilities override Clerk styles +- **Font**: References the app's Inter font via CSS variable +- **Button styling**: Primary buttons use the brand gradient (`--gradient-primary`) +- **Localisation**: Custom text for sign-in/sign-up titles, subtitles, and OAuth button labels + +### Per-Component + +Individual wrapper components can override globals via the `appearance` prop. For example, `ClerkSignIn` sets a theme-aware logo and left-aligned header. + +### CSS Layer Integration + +To ensure Tailwind utilities can override Clerk's styles without `!important`: + +1. **Declare layer order** at the top of `globals.css`: + + ```css + @layer theme, base, clerk, components, utilities; + ``` + +2. **Import Clerk's styles** after the layer declaration: + + ```css + @import "@clerk/themes/shadcn.css"; + ``` + +3. **Set `cssLayerName`** in ClerkProvider to place Clerk styles in the `clerk` layer. + +This ordering ensures utilities (highest priority) can override Clerk styles cleanly. + +### Theme-Aware Assets + +CSS variables in `globals.css` provide theme-aware URLs: + +```css +:root { + --logo-full-themed: url("/images/logo-light.svg"); + --auth-bg: url("/images/auth-bg-light.webp"); +} +.dark { + --logo-full-themed: url("/images/logo-dark.svg"); + --auth-bg: url("/images/auth-bg-dark.webp"); +} +``` + +These variables are used directly in Tailwind classes via arbitrary value syntax: `bg-(image:--auth-bg)`. + +For Clerk components specifically, JavaScript theme detection (`useTheme()`) is required because Clerk's API accepts only static URL strings. + +--- + +## Key Files + +| File | Purpose | +|------|---------| +| `proxy.ts` | Route protection via `clerkMiddleware()` | +| `app/layout.tsx` | ClerkProvider wrapping the app | +| `components/providers/clerk-provider.tsx` | Global Clerk theming and localisation | +| `app/(auth)/layout.tsx` | Auth page layout with background | +| `app/(auth)/sign-in/[[...sign-in]]/page.tsx` | Sign-in route | +| `app/(auth)/sign-up/[[...sign-up]]/page.tsx` | Sign-up route | +| `components/auth/clerk-signin.tsx` | Custom sign-in wrapper (theme-aware logo) | +| `components/auth/clerk-signup.tsx` | Custom sign-up wrapper (static logo) | +| `app/globals.css` | CSS layer order and theme-aware asset variables | + +--- + +## Notes + +- The `await connection()` call in auth pages forces dynamic rendering at request time. This may be unnecessary since Clerk components are client-side, but it ensures no caching issues with authentication state. +- Clerk's localisation API allows customising any text string. The `{{provider|titleize}}` template formats OAuth provider names (e.g., "GitHub" instead of "Continue with GitHub"). diff --git a/x_docs/OLD/navigation.md b/x_docs/OLD/navigation.md new file mode 100644 index 0000000..60741bb --- /dev/null +++ b/x_docs/OLD/navigation.md @@ -0,0 +1,265 @@ +# Navigation Architecture: Mobile & Sidebar + +Last updated: 2026-02-02 + +This document explains how the navigation system works across breakpoints, component structure, and the distinction between navigation and content discovery. + +--- + +## Overview + +The app has **two navigation contexts** that share the same nav items but render differently: + +| Context | Breakpoint | Container | Implementation | +|---------|------------|-----------|----------------| +| Mobile Nav | `` | shadcn/ui Sidebar with `collapsible="icon"` | + +The Left Sidebar can collapse to icon-only mode, persisted via cookie. + +--- + +## Visual Breakdown + +```text +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ MOBILE (<640px) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ MobileTopBar: [Logo] [Theme] [Hamburger] β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ Hamburger β†’ Sheet slides in from left (max 320px) β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ [Logo] β”‚ β”‚ +β”‚ β”‚ Home β”‚ β”‚ +β”‚ β”‚ Community β”‚ β”‚ +β”‚ β”‚ Collections β”‚ β”‚ +β”‚ β”‚ Find Jobs β”‚ β”‚ +β”‚ β”‚ Tags β”‚ β”‚ +β”‚ β”‚ Ask a question β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ [Auth buttons] β”‚ ← SignedOut: Sign in + Sign up β”‚ +β”‚ β”‚ [UserButton] β”‚ ← SignedIn: avatar β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ DESKTOP (β‰₯640px) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ DesktopTopBar: [Search placeholder] [Theme] [Auth] β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚Sidebar β”‚ β”‚ +β”‚ 13rem β”‚ Main Content β”‚ +β”‚ β”‚ β”‚ +β”‚ Home β”‚ ← Expanded: icon + label β”‚ +β”‚ Comm. β”‚ ← Collapsed: icon only (3rem width) β”‚ +β”‚ Coll. β”‚ β”‚ +β”‚ Jobs β”‚ β”‚ +β”‚ Tags β”‚ β”‚ +β”‚ Ask β”‚ β”‚ +β”‚ β”‚ β”‚ +β”‚[User] β”‚ ← UserButton (SignedIn only) β”‚ +β”‚[Toggle]β”‚ ← Collapse/expand toggle β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ XL DESKTOP (β‰₯1280px) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ DesktopTopBar β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚Sidebar β”‚ Main Content β”‚ RightSidebar β”‚ +β”‚ β”‚ β”‚ (22rem) β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ Top Questions β”‚ +β”‚ β”‚ β”‚ Popular Tags β”‚ +β”‚ β”‚ β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## Authentication UI + +Auth controls appear in different locations based on screen size and auth state: + +| Context | Unauthenticated | Authenticated | +|---------|-----------------|---------------| +| **DesktopTopBar** | Sign in + Sign up buttons | Nothing | +| **LeftSidebar** | Nothing | UserButton at bottom | +| **MobileNav** | Sign in + Sign up buttons | UserButton | + +--- + +## Navigation vs Content Discovery + +The application has two types of sidebars with different purposes: + +| Sidebar | Purpose | Content | Visibility | +|---------|---------|---------|------------| +| **LeftSidebar** | Navigation | Route links (Home, Community, etc.) | `β‰₯sm` (640px+) | +| **RightSidebar** | Content discovery | Top Questions, Popular Tags | `β‰₯xl` (1280px+) | + +The LeftSidebar and MobileNav are **navigation components** β€” they help users move between routes. + +The RightSidebar is a **content discovery component** β€” it surfaces related content to encourage exploration but doesn't provide primary navigation. + +--- + +## Component Architecture + +### Key Insight + +Navigation links are implemented differently for mobile and desktop, but share the same data source and styling utilities: + +- **MobileNav**: Uses `MobileNavLink` component in a Sheet overlay +- **LeftSidebar**: Uses shadcn/ui `SidebarMenuButton` with collapsible behaviour + +Both consume the `NAV_LINKS` constant and use shared utilities for active state detection. + +```text +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ SAME data source, DIFFERENT rendering: β”‚ +β”‚ β”‚ +β”‚ MobileNav (Sheet) LeftSidebar (shadcn/ui) β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ "icon"> β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ Button /> β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ ↓ ↓ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ ↓ β”‚ +β”‚ NAV_LINKS constant β”‚ +β”‚ Shared styling utilities β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Shared Utilities (`lib/utils.ts`) + +```typescript +// Check if route is active (exact or nested) +isRouteActive(pathname: string, route: string): boolean + +// Active state classes +NAV_LINK_ACTIVE_CLASSES = "bg-(image:--gradient-primary) font-bold text-primary-foreground" +NAV_LINK_INACTIVE_CLASSES = "font-medium" + +// Icon inversion for theme compatibility +getNavIconInvertClasses(isActive: boolean): string +``` + +--- + +## File Structure + +```text +components/navigation/ +β”œβ”€β”€ nav-links.constants.ts ← NAV_LINKS array (shared data) +β”œβ”€β”€ desktop-topbar.tsx ← Desktop top bar (β‰₯sm) +β”œβ”€β”€ mobile-topbar.tsx ← Mobile top bar ( - {children} - -``` - ---- - -## Q1: What Are Flexboxes? - -Flexbox (Flexible Box Layout) is a CSS layout system designed to arrange items in a **single direction** β€” either as a row (horizontal) or a column (vertical). Think of it as laying items out along a line, with powerful controls for spacing, alignment, and distribution. - -### The Mental Model - -Imagine a bookshelf. You can arrange books: - -- Left to right (row) -- Stacked top to bottom (column) -- Spread evenly across the shelf -- Pushed to one end -- Centred in the middle - -Flexbox gives you all these controls. - -### ASCII Diagram: Flex Row vs Flex Column - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ FLEX ROW (default: flex-direction: row) β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Item β”‚ β”‚ Item β”‚ β”‚ Item β”‚ ───────► β”‚ -β”‚ β”‚ 1 β”‚ β”‚ 2 β”‚ β”‚ 3 β”‚ Main Axis β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β–Ό Cross Axis β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ FLEX COLUMN (flex-direction: column) β”‚ -β”‚ β”‚ -β”‚ β”‚ β”‚ -β”‚ β–Ό Main Axis β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Item 1 β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Item 2 β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Item 3 β”‚ ───────► Cross Axis β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Why Flexbox for the Auth Layout? - -We used flexbox because we needed to **centre one thing** (the login form) both horizontally and vertically within a container. This is flexbox's sweet spot: - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Login β”‚ β”‚ -β”‚ β”‚ Form β”‚ ◄── children β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Screen (min-h-screen) -``` - -The combination `flex items-center justify-center` achieves this perfectly. - ---- - -## Q2: When to Use Flexbox vs Grid? - -Both are CSS layout systems, but they solve different problems. - -### πŸ“Š Comparison Table - -| Aspect | πŸ”€ Flexbox | πŸ”² Grid | -|--------|-----------|---------| -| **Dimension** | One-dimensional (row OR column) | Two-dimensional (rows AND columns) | -| **Best for** | Aligning items along a line | Creating structured layouts | -| **Content-driven** | βœ… Yes β€” items determine their size | ❌ No β€” grid defines the structure | -| **Layout-driven** | ❌ No | βœ… Yes β€” you define rows/columns first | -| **Simple centering** | βœ… Perfect | ⚠️ Works but overkill | -| **Complex layouts** | ⚠️ Hacky | βœ… Designed for this | -| **Navigation bars** | βœ… Ideal | ⚠️ Unnecessary | -| **Photo galleries** | ⚠️ Difficult | βœ… Ideal | -| **Card grids** | ⚠️ Requires wrapping | βœ… Natural fit | - -### When to Choose Each - -| Use Case | Choose | Why | -|----------|--------|-----| -| 🎯 Centre a single element | Flexbox | Two lines of code | -| πŸ“± Navigation bar | Flexbox | Items in a row with spacing | -| πŸ“ Form fields in a column | Flexbox | Items stacked vertically | -| πŸ–ΌοΈ Image gallery | Grid | Rows and columns together | -| πŸ“° Magazine-style layout | Grid | Complex 2D positioning | -| πŸ“Š Dashboard with widgets | Grid | Named areas, spanning cells | -| ↔️ Space items evenly | Flexbox | `justify-between` or `space-evenly` | - -### ASCII Diagram: The Difference - -``` -FLEXBOX: Thinks in ONE direction at a time -────────────────────────────────────────── - β”Œβ”€β”€β”€β” β”Œβ”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β” - β”‚ A β”‚ β”‚ B β”‚ β”‚ C β”‚ β”‚ D β”‚ ◄── Items flow, sizes vary - β””β”€β”€β”€β”˜ β””β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”˜ - - -GRID: Thinks in ROWS and COLUMNS together -────────────────────────────────────────── - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ A β”‚ B β”‚ C β”‚ ◄── Row 1 - β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ - β”‚ D β”‚ E β”‚ F β”‚ ◄── Row 2 - β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ - β”‚ G β”‚ H β”‚ I β”‚ ◄── Row 3 - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β–² β–² β–² - Col 1 Col 2 Col 3 -``` - -**For our auth layout:** We chose flexbox because we only needed to position one child element. Grid would work but adds unnecessary complexity for such a simple requirement. - ---- - -## Q3: Why Are "Layout" and "Flexbox & Grid" Separate in Tailwind Docs? - -The Tailwind documentation organises utilities by the CSS concepts they control. Here's why they're separate: - -### πŸ—‚οΈ Category Breakdown - -| Category | What It Controls | Examples | -|----------|------------------|----------| -| πŸ“ **Layout** | How elements participate in document flow | `display`, `position`, `float`, `z-index`, `overflow` | -| πŸ”€ **Flexbox & Grid** | How children are arranged within a flex/grid container | `flex-direction`, `justify-content`, `align-items`, `grid-template-columns` | - -### The Key Distinction - -**Layout** answers: *"How does this element exist in the page?"* - -- Is it `block` or `inline`? -- Is it `fixed` to the viewport? -- Is it `absolute` and pulled out of normal flow? -- What's its `z-index` (stacking order)? - -**Flexbox & Grid** answers: *"How are this element's children arranged?"* - -- Should children be in a row or column? -- How should space be distributed? -- How should children align? - -### Visual Example - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚
position: fixed ◄── LAYOUT β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚
display: flex ◄── LAYOUT β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ A β”‚ β”‚ B β”‚ β”‚ C β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β”‚ β–² β”‚ β”‚ -β”‚ β”‚ └── justify-center ◄── FLEXBOX β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -In our auth layout: - -- `flex` is technically a **Layout** utility (it sets `display: flex`) -- `items-center` and `justify-center` are **Flexbox** utilities (they control child alignment) - -They work together but control different aspects. - ---- - -## Q4: Is Flexbox a CSS Concept or Tailwind-Specific? - -**Flexbox is a native CSS standard.** Tailwind simply provides utility classes that map to the underlying CSS properties. - -### πŸ”„ The Relationship - -| What You Write (Tailwind) | What CSS Gets Applied | CSS Property | -|---------------------------|----------------------|--------------| -| `flex` | `display: flex;` | Native CSS | -| `items-center` | `align-items: center;` | Native CSS | -| `justify-center` | `justify-content: center;` | Native CSS | -| `flex-col` | `flex-direction: column;` | Native CSS | -| `gap-4` | `gap: 1rem;` | Native CSS | - -### The Same Thing, Two Ways - -```css -/* Pure CSS */ -.container { - display: flex; - align-items: center; - justify-content: center; - min-height: 100vh; -} - -/* Tailwind utility classes */ -
-``` - -Both produce identical results. Tailwind is a **convenience layer** that: - -1. Provides short, memorable class names -2. Ensures consistent spacing/sizing scales -3. Enables responsive design with prefixes (`md:flex-row`) -4. Enables state variants (`hover:items-start`) - -**The underlying concepts (flexbox, grid, etc.) are all standard CSS** that works in every modern browser, with or without Tailwind. - ---- - -## Q5: Utility Class Breakdown - -Here's every utility class used in the auth layout, explained: - -### πŸ“‹ Complete Class Reference - -| Tailwind Class | CSS Property | Purpose | Impact | -|----------------|--------------|---------|--------| -| πŸ”€ `flex` | `display: flex;` | Enables flexbox on the container | Children can now be positioned using flex properties | -| πŸ“ `min-h-screen` | `min-height: 100vh;` | Container is at least full viewport height | Ensures the background covers the entire screen | -| ↕️ `items-center` | `align-items: center;` | Centres children on the cross-axis (vertically for row) | Login form is vertically centred | -| ↔️ `justify-center` | `justify-content: center;` | Centres children on the main-axis (horizontally for row) | Login form is horizontally centred | -| πŸ–ΌοΈ `bg-cover` | `background-size: cover;` | Image scales to cover entire container | No empty space, image may crop | -| 🎯 `bg-center` | `background-position: center;` | Image is centred within container | Cropping happens equally from edges | -| 🚫 `bg-no-repeat` | `background-repeat: no-repeat;` | Image displays once, not tiled | Prevents image from repeating if container is larger | -| πŸŒ… bg-​[url('…')] | `background-image: url(…);` | Sets the background image | Displays the light-mode background | -| πŸŒ™ dark:​bg-​[url('…')] | `background-image: url(…);` (when `.dark` class present) | Sets dark-mode background | Switches image when theme is dark | - -### 🎨 Visual Impact Diagram - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ min-h-screen: Container fills viewport height β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ bg-cover + bg-center + bg-no-repeat: β”‚ β”‚ -β”‚ β”‚ Background image fills and centres β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ flex + items-center + justify-center: β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β–Ό β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Login β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ Form β”‚ ◄── children β”‚ β”‚ -β”‚ β”‚ β”‚ (centred) β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ bg-[url('/images/auth-bg-light.webp')] β”‚ β”‚ -β”‚ β”‚ dark:bg-[url('/images/auth-bg-dark.webp')] β”‚ β”‚ -β”‚ β”‚ β–² β”‚ β”‚ -β”‚ β”‚ └── Theme-aware background switching β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### How the Classes Work Together - -1. **`flex`** β€” Enables the flexbox layout model on `
` -2. **`items-center`** β€” Tells flex to centre children vertically -3. **`justify-center`** β€” Tells flex to centre children horizontally -4. **`min-h-screen`** β€” Ensures there's vertical space to centre within -5. **`bg-*` classes** β€” Handle the decorative background independently of the layout - -The layout (centering) and decoration (background) are separate concerns that combine to create the final result. - ---- - -## Background Image: Did We Use the Documentation? - -Yes! We used the bg-​[url(…)] syntax documented in the Tailwind background-image reference. - -### What the Docs Show - -From the documentation: - -```txt -
-``` - -This is the **arbitrary value syntax** β€” square brackets `[]` let you use any CSS value directly. - -### What We Implemented - -```html -
-``` - -### πŸ“š Features We Used from the Docs - -| Feature | From Docs | Our Usage | -|---------|-----------|-----------| -| βœ… Arbitrary URL syntax | bg-​[url(…)] | `bg-[url('/images/auth-bg-light.webp')]` | -| βœ… Dark mode variant | Via `dark:` prefix (covered in variants docs) | `dark:bg-[url('/images/auth-bg-dark.webp')]` | - -### Features We Did NOT Use - -The documentation also covers gradients, colour stops, and interpolation modes β€” none of which we needed for a simple image background: - -- `bg-linear-to-r` β€” Linear gradients -- `from-indigo-500 via-purple-500 to-pink-500` β€” Colour stops -- `bg-radial`, `bg-conic` β€” Other gradient types - -These are available if you want to add gradient overlays or effects in the future. - ---- - -## Summary - -| Concept | Key Takeaway | -|---------|--------------| -| πŸ”€ **Flexbox** | One-dimensional layout for arranging items in a row or column. Perfect for centering and distributing space. | -| πŸ”² **Grid** | Two-dimensional layout for complex row/column structures. Ideal for galleries and dashboards. | -| πŸ“ **Layout vs Flex/Grid** | Layout controls *how an element exists* in the page. Flexbox/Grid control *how its children are arranged*. | -| 🎨 **CSS vs Tailwind** | Flexbox is native CSS. Tailwind provides convenient utility classes that compile to standard CSS. | -| πŸ–ΌοΈ **Background Images** | Use bg-​[url(…)] for arbitrary images. Combine with `dark:` for theme-aware switching. | - ---- - -*Document created to explain the auth layout implementation in DevFlow.* diff --git a/x_docs/mine/globals-compare.md b/x_docs/mine/globals-compare.md deleted file mode 100644 index 352a2ad..0000000 --- a/x_docs/mine/globals-compare.md +++ /dev/null @@ -1,983 +0,0 @@ -# Tailwind Theming Comparison: `globals-old.css` vs My Modern Approach `globals.css` - -This document compares the light/dark mode approach from an old file (`globals-old.css`) with the modern Tailwind v4 approach (`globals.css`), and categorises all configuration patterns with explanations. - ---- - -## Light/Dark Mode Comparison - -| Aspect | Old File (globals-old.css) | Your File (globals.css) | -|--------|-------------------------------|-------------------------| -| **Approach** | Composite utility classes with `dark:` variant | CSS custom properties + `@theme inline` | -| **Colour Format** | Named scales (light-850, dark-100) | OKLCH (perceptually uniform) | -| **Theme Switching** | Class-based via Tailwind `dark:` | CSS variables that swap at runtime | -| **Naming** | Arbitrary (light-850, dark-400) | Semantic (primary, muted, accent) | -| **Tailwind Version** | v3 patterns | v4 native patterns | - -### Verdict: The modern globals.css approach is significantly better - -**Why the modern approach wins:** - -1. **Runtime theme switching** β€” CSS variables can be changed via JavaScript without recompiling CSS. This enables features like system preference detection, user preference persistence, and instant theme toggling. - -2. **OKLCH colour space** β€” A modern, perceptually uniform colour space. Unlike HSL or RGB, OKLCH ensures that colours with the same lightness value actually *appear* equally light to human eyes. This produces better gradients and more accessible colour combinations. - -3. **Semantic naming** β€” `bg-primary` communicates intent; `bg-light-850` is meaningless without context. Semantic names make code self-documenting and easier to maintain. - -4. **shadcn/ui compatible** β€” The CSS variable pattern is the standard for shadcn/ui components, Radix UI, and most modern React component libraries. Your setup works out of the box. - -5. **DRY (Don't Repeat Yourself)** β€” Change one variable in `:root` or `.dark`, and all usages update automatically. The old file has 50+ hardcoded light/dark combinations that must be updated individually. - -6. **No `!important` spam** β€” The old file uses `!important` 20+ times, which is a code smell indicating specificity problems. The modern approach avoids this entirely through proper CSS layering. - ---- - -## Old File Categories Explained - -The old file contains various utility patterns. Below, each category is explained with context on what it does, why it exists, and what you would need in a modern setup. - ---- - -### 1. Base Settings - -```css -body { font-family: "Inter", sans-serif; } -:root { --radius: 8px; } -``` - -**What it does:** -Sets the global font family and defines a CSS variable for border radius that can be used throughout the application. - -**Why it exists:** -Centralising design tokens like border radius allows for consistent UI and easy global changes. - -**What you'd need:** -Already handled in your file. Your setup is more sophisticated: - -- `--radius` is defined in `:root` and mapped via `@theme inline` to generate `rounded-sm`, `rounded-md`, `rounded-lg`, `rounded-xl` utilities -- Fonts are defined as CSS variables (`--font-display`, `--font-serif`, `--font-mono`) that integrate with Next.js font optimisation - ---- - -### 2. Background Theme Utilities (17 classes) - -```css -.background-light850_dark100 { @apply bg-light-850 dark:bg-dark-100; } -.background-light900_dark200 { @apply bg-light-900 dark:bg-dark-200; } -.background-light900_dark300 { @apply bg-light-900 dark:bg-dark-300; } -/* ... 14 more variations */ -``` - -**What it does:** -Pre-composed utility classes that apply different background colours depending on whether light or dark mode is active. The naming convention `light850_dark100` indicates "use light-850 in light mode, dark-100 in dark mode". - -**Why it exists:** -In Tailwind v3, this was a common pattern to avoid writing `bg-light-850 dark:bg-dark-100` repeatedly in JSX. It keeps component markup cleaner. - -**Problems with this approach:** - -- Creates dozens of single-purpose classes -- Arbitrary numbers (850, 100) have no semantic meaning -- Must create a new class for every light/dark combination needed -- Tightly couples colour values to class names - -**What you'd need:** -Nothing. Use semantic classes instead: - -```html - -
- - -
- -``` - -The modern approach uses semantic names that describe *purpose* (card, muted, secondary) rather than *appearance* (light-900, dark-200). - ---- - -### 3. Text Theme Utilities (16 classes) - -```css -.text-dark100_light900 { @apply text-dark-100 dark:text-light-900 !important; } -.text-dark200_light800 { @apply text-dark-200 dark:text-light-800 !important; } -.text-dark300_light700 { @apply text-dark-300 dark:text-light-700; } -/* ... 13 more variations */ -``` - -**What it does:** -Pre-composed text colour classes for light/dark mode. Note that many use `!important` to force specificity. - -**Why it exists:** -Same rationale as background utilities β€” reduces repetition in markup. - -**Problems with this approach:** - -- Heavy use of `!important` indicates specificity battles -- Arbitrary colour values make it hard to understand visual hierarchy -- No indication of what each colour combination is *for* - -**What you'd need:** -Nothing. Use semantic text colours: - -```html - -

Secondary text

- - -

Secondary text

-``` - -Common semantic text colours in your setup: - -- `text-foreground` β€” Primary text -- `text-muted-foreground` β€” Secondary/subdued text -- `text-primary` β€” Brand/accent text -- `text-destructive` β€” Error/warning text - ---- - -### 4. Border Utilities - -```css -.light-border { @apply border-light-800 dark:border-dark-300; } -.light-border-2 { @apply border-light-700 dark:border-dark-400 !important; } -``` - -**What it does:** -Consistent border colours that adapt to light/dark mode. - -**Why it exists:** -Borders often need different opacity/colour in dark mode to remain visible without being too harsh. - -**What you'd need:** -Already handled. Your `@layer base` includes: - -```css -* { - @apply border-border outline-ring/50; -} -``` - -This sets a default border colour on all elements using the `--border` CSS variable, which automatically changes between light and dark mode. Simply use the `border` class: - -```html -
-``` - ---- - -### 5. Typography Scale (16 classes) - -```css -.h1-bold { @apply text-[30px] font-bold leading-[42px] tracking-tighter; } -.h2-bold { @apply text-[24px] font-bold leading-[31.2px]; } -.h2-semibold { @apply text-[24px] font-semibold leading-[31.2px]; } -.h3-bold { @apply text-[20px] font-bold leading-[26px]; } -.h3-semibold { @apply text-[20px] font-semibold leading-[24.8px]; } -.base-medium { @apply text-[18px] font-medium leading-[25.2px]; } -.base-semibold { @apply text-[18px] font-semibold leading-[25.2px]; } -.base-bold { @apply text-[18px] font-bold leading-[140%]; } -.paragraph-regular { @apply text-[16px] font-normal leading-[22.4px]; } -.paragraph-medium { @apply text-[16px] font-medium leading-[22.4px]; } -.paragraph-semibold { @apply text-[16px] font-semibold leading-[20.8px]; } -.body-regular { @apply text-[14px] font-normal leading-[19.6px]; } -.body-medium { @apply text-[14px] font-medium leading-[18.2px]; } -.body-semibold { @apply text-[14px] font-semibold leading-[18.2px]; } -.body-bold { @apply text-[14px] font-bold leading-[18.2px]; } -.small-regular { @apply text-[12px] font-normal leading-[15.6px]; } -.small-medium { @apply text-[12px] font-medium leading-[15.6px]; } -.small-semibold { @apply text-[12px] font-semibold leading-[15.6px]; } -.subtle-medium { @apply text-[10px] font-medium leading-[13px] !important; } -.subtle-regular { @apply text-[10px] font-normal leading-[13px]; } -``` - -**What it does:** -A comprehensive type scale combining font size, weight, and line height into single utility classes. The naming convention is `{size}-{weight}`. - -**Why it exists:** -Typography often requires coordinated changes to size, weight, and line-height. These utilities ensure consistent combinations across the app. - -**Analysis:** -This is actually a reasonable pattern, though the arbitrary pixel values (`text-[30px]`, `leading-[42px]`) could be replaced with Tailwind's built-in scale for better maintainability. - -**What you'd need:** -Your file already has base styles for `h1`–`h6` in `@layer base`. For additional utility combinations, you could add: - -```css -@layer utilities { - /* Using Tailwind's built-in scale instead of arbitrary values */ - .h1-bold { @apply text-5xl font-bold tracking-tight; } - .h2-bold { @apply text-4xl font-bold; } - .h2-semibold { @apply text-4xl font-semibold; } - .h3-bold { @apply text-3xl font-bold; } - - .body-medium { @apply text-sm font-medium; } - .body-semibold { @apply text-sm font-semibold; } - - .small-medium { @apply text-xs font-medium; } - .caption { @apply text-xs text-muted-foreground; } -} -``` - -Alternatively, just compose Tailwind utilities directly in your JSX β€” `text-sm font-medium` is clear and doesn't require custom classes. - ---- - -### 6. Placeholder Styles - -```css -.placeholder { @apply placeholder:text-light-400 dark:placeholder:text-light-500; } -``` - -**What it does:** -Sets consistent placeholder text colour in form inputs across light/dark modes. - -**Why it exists:** -Placeholder text should be visually distinct from actual input text, but still readable. The colour often needs adjustment in dark mode. - -**What you'd need:** -Add to your base layer for global application: - -```css -@layer base { - input::placeholder, - textarea::placeholder { - @apply text-muted-foreground; - } -} -``` - -Or apply per-component using Tailwind's placeholder modifier: `placeholder:text-muted-foreground`. - ---- - -### 7. Visual Effects - -```css -.invert-colors { @apply invert dark:invert-0; } -.shadow-light100_dark100 { @apply shadow-light-100 dark:shadow-dark-100; } -.shadow-light100_darknone { @apply shadow-light-100 dark:shadow-none; } -``` - -**What it does:** - -- `invert-colors`: Inverts an element's colours in light mode, restores in dark mode. Useful for black icons that need to be white in dark mode. -- Shadow utilities: Apply different shadow styles per theme. Shadows often look too harsh in dark mode and need to be softer or removed. - -**Why it exists:** -Icons and shadows frequently need theme-specific treatment that simple colour changes don't address. - -**What you'd need:** -If using icons that need inversion (e.g., black SVGs): - -```css -@layer utilities { - .invert-on-light { @apply invert dark:invert-0; } - .invert-on-dark { @apply dark:invert; } -} -``` - -For shadows, consider defining shadow values in your theme that work across modes, or use: - -```css -@layer utilities { - .shadow-theme { - @apply shadow-md dark:shadow-none dark:ring-1 dark:ring-border; - } -} -``` - ---- - -### 8. Gradients - -```css -.primary-gradient { - background: linear-gradient(129deg, #ff7000 0%, #e2995f 100%); -} - -.dark-gradient { - background: linear-gradient( - 232deg, - rgba(23, 28, 35, 0.41) 0%, - rgba(19, 22, 28, 0.7) 100% - ); -} - -.light-gradient { - background: linear-gradient( - 132deg, - rgba(247, 249, 255, 0.5) 0%, - rgba(229, 237, 255, 0.25) 100% - ); -} - -.primary-text-gradient { - background: linear-gradient(129deg, #ff7000 0%, #e2995f 100%); - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; -} -``` - -**What it does:** - -- `primary-gradient`: Brand gradient for buttons, CTAs, highlights (orange tones) -- `dark-gradient`: Subtle overlay gradient for dark mode cards/surfaces -- `light-gradient`: Subtle overlay gradient for light mode -- `primary-text-gradient`: Applies gradient as text colour (the background shows through transparent text) - -**Why it exists:** -Gradients add visual interest and depth. Brand gradients reinforce identity. The text gradient technique creates eye-catching headings. - -**What you'd need:** -First, define brand colours as CSS variables, then create gradient utilities: - -```css -:root { - --brand-orange: #ff7000; - --brand-gold: #e2995f; -} - -@layer utilities { - .bg-gradient-primary { - background: linear-gradient(135deg, var(--brand-orange) 0%, var(--brand-gold) 100%); - } - - .bg-gradient-surface { - @apply bg-gradient-to-br from-background to-muted/50; - } - - .text-gradient-primary { - background: linear-gradient(135deg, var(--brand-orange) 0%, var(--brand-gold) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - } -} -``` - ---- - -### 9. Layout Utilities - -```css -.flex-center { @apply flex justify-center items-center; } -.flex-between { @apply flex justify-between items-center; } -.flex-start { @apply flex justify-start items-center; } -``` - -**What it does:** -Shorthand utilities for common flexbox patterns: - -- `flex-center`: Centre children both horizontally and vertically -- `flex-between`: Space children to opposite ends, vertically centred -- `flex-start`: Align children to start, vertically centred - -**Why it exists:** -These three-class combinations (`flex justify-center items-center`) are extremely common. Single utilities reduce markup verbosity. - -**What you'd need:** -These are genuinely useful shortcuts. Add if you find yourself writing these combinations frequently: - -```css -@layer utilities { - .flex-center { @apply flex items-center justify-center; } - .flex-between { @apply flex items-center justify-between; } - .flex-start { @apply flex items-center justify-start; } - .flex-end { @apply flex items-center justify-end; } - - /* Inline variant (horizontal only) */ - .inline-center { @apply inline-flex items-center justify-center; } -} -``` - ---- - -### 10. Component Utilities - -```css -.card-wrapper { - @apply bg-light-900 dark:dark-gradient shadow-light-100 dark:shadow-dark-100; -} - -.btn { @apply bg-light-800 dark:bg-dark-300 !important; } -.btn-secondary { @apply bg-light-800 dark:bg-dark-400 !important; } -.btn-tertiary { @apply bg-light-700 dark:bg-dark-300 !important; } - -.tab { - @apply min-h-full dark:bg-dark-400 bg-light-800 text-light-500 - dark:data-[state=active]:bg-dark-300 data-[state=active]:bg-primary-100 - data-[state=active]:text-primary-500 !important; -} -``` - -**What it does:** -Pre-styled component utilities for cards, buttons, and tabs. - -**Why it exists:** -When not using a component library, these utilities provide consistent component styling without writing full CSS classes for each component. - -**Problems with this approach:** - -- Heavy use of `!important` to override other styles -- Tightly coupled to specific colour values -- Doesn't scale well β€” you end up with `.btn`, `.btn-secondary`, `.btn-tertiary`, `.btn-ghost`, `.btn-outline`... -- State management (`:hover`, `:active`, `:disabled`) becomes complex - -**What you'd need:** -With shadcn/ui or similar component libraries, you get actual React components (`