30 KiB
OW Animation Arts Vault - UI Design System & Layout Guide
This document outlines the complete UI/style and layout architecture used in this codebase. Use this guide to create additional applications for the same client with consistent design and user experience.
Table of Contents
- Technology Stack
- Project Architecture
- Color System & Theming
- Layout System
- Navigation & Sidebar
- Page Layouts
- Component Library
- Typography & Spacing
- Form Patterns
- Responsive Design
- Dark Mode Implementation
- Reusable Patterns
- Asset Guidelines
1. Technology Stack
Core Framework
- Next.js 16.0.3 - React framework with App Router
- React 18+ - UI library
- TypeScript - Type safety
- Tailwind CSS 3.4+ - Utility-first CSS framework
UI Component Library
- shadcn/ui - Pre-built, composable React components
- @radix-ui/ - Unstyled, accessible component primitives
- Lucide React - Beautiful, consistent icon library
- Tabler Icons - Alternative icon set
State Management & Data
- NextAuth.js - Authentication
- Next-Themes - Theme management (dark/light mode)
- Prisma ORM - Database abstraction
- TanStack React Table - Advanced table data management
- Sonner - Toast notifications
Additional Libraries
- @dnd-kit - Drag and drop functionality
- Embla Carousel - Carousel/slider component
- Recharts - Data visualization charts
- HLS.js - Video streaming (HLS protocol)
- date-fns - Date utilities
- class-variance-authority (CVA) - Component variant management
- clsx - Conditional className merging
2. Project Architecture
Directory Structure
app/
├── layout.tsx # Root layout (server component)
├── page.tsx # Landing/home page
├── providers.tsx # Client-side providers (SessionProvider, ThemeProvider)
├── globals.css # Global styles & CSS variables
├── login/
│ ├── page.tsx # Login page
│ └── unauthorized/
├── dashboard/
│ ├── page.tsx # Protected dashboard
│ ├── dashboard-client.tsx # Client component with content
│ ├── liked-videos/
│ └── watch-history/
├── admin/
│ ├── page.tsx # Admin gate (server component)
│ ├── admin-client.tsx # Admin UI (client component)
│ ├── users/
│ ├── courses/
│ ├── playlists/
│ ├── videos/
│ ├── enrollments/
│ └── stats/
├── api/ # API routes for server operations
└── videoplayer/ # Video player page
components/
├── app-sidebar.tsx # Main navigation sidebar
├── site-header.tsx # Top header with breadcrumbs
├── nav-main.tsx # Primary navigation menu
├── nav-secondary.tsx # Secondary navigation items
├── nav-user.tsx # User profile dropdown
├── login-form.tsx # Google OAuth login form
├── data-table.tsx # Advanced data table component
├── hls.tsx # Video player (HLS streaming)
├── chart-area-interactive.tsx # Interactive chart component
├── comments-section.tsx # Comments/discussion area
├── admin-notifications.tsx # Admin notifications
├── ui/ # shadcn/ui components
│ ├── button.tsx
│ ├── card.tsx
│ ├── sidebar.tsx
│ ├── input.tsx
│ ├── label.tsx
│ ├── badge.tsx
│ ├── dropdown-menu.tsx
│ ├── dialog.tsx
│ ├── drawer.tsx
│ ├── table.tsx
│ ├── tabs.tsx
│ ├── carousel.tsx
│ ├── chart.tsx
│ ├── select.tsx
│ ├── checkbox.tsx
│ ├── field.tsx
│ ├── collapsible.tsx
│ └── ... (27+ components)
lib/
├── utils.ts # Utility functions (cn for className merging)
├── auth-options.ts # NextAuth configuration
├── auth-check.ts # Authentication helpers
├── prisma.ts # Prisma client
└── video-urls.ts # Video URL generation
hooks/
├── use-mobile.ts # Mobile breakpoint hook
├── useVideo.ts # Video data hooks
├── usePlaylists.ts # Playlist data hooks
└── usePlaylist.ts # Single playlist hook
public/
├── icon.svg # App icon
├── vault.png # Vault image (login page)
└── vault.exr # Vault image (high-res)
Component Structure Pattern
Server Component (pages):
// app/dashboard/page.tsx
import { requireUser } from '@/lib/auth-check';
import DashboardClient from './dashboard-client';
export default async function DashboardPage() {
const session = await requireUser('/login');
return <DashboardClient />;
}
Client Component (content):
// app/dashboard/dashboard-client.tsx
'use client';
import React from 'react';
import { AppSidebar } from '@/components/app-sidebar';
import { SiteHeader } from '@/components/site-header';
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';
export default function DashboardClient() {
return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
<SiteHeader />
<main className="flex flex-col gap-4 p-4">
{/* Page content */}
</main>
</SidebarInset>
</SidebarProvider>
);
}
3. Color System & Theming
CSS Variables (OKLch Color Space)
The design system uses OKLch color space for perceptually uniform colors across light and dark modes.
Light Mode (:root):
--background: oklch(1 0 0); /* White */
--foreground: oklch(0.141 0.005 285.823); /* Near Black */
--card: oklch(1 0 0); /* White */
--card-foreground: oklch(0.141 0.005 285.823); /* Near Black */
--primary: oklch(0.646 0.222 41.116); /* Warm Yellow/Orange */
--primary-foreground: oklch(0.98 0.016 73.684); /* Light cream */
--secondary: oklch(0.967 0.001 286.375); /* Light gray */
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375); /* Light gray (buttons, etc) */
--muted-foreground: oklch(0.552 0.016 285.938); /* Medium gray (text) */
--accent: oklch(0.967 0.001 286.375); /* Light gray */
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325); /* Red */
--border: oklch(0.92 0.004 286.32); /* Light gray */
--input: oklch(0.92 0.004 286.32); /* Light gray */
--ring: oklch(0.75 0.183 55.934); /* Orange/Gold for focus */
Dark Mode (.dark):
.dark {
--background: oklch(0.141 0.005 285.823); /* Near Black */
--foreground: oklch(0.985 0 0); /* White */
--card: oklch(0.21 0.006 285.885); /* Dark gray */
--card-foreground: oklch(0.985 0 0); /* White */
--primary: oklch(0.705 0.213 47.604); /* Lighter Orange */
--secondary: oklch(0.274 0.006 286.033); /* Dark gray */
--muted: oklch(0.274 0.006 286.033); /* Dark gray */
--muted-foreground: oklch(0.705 0.015 286.067);
--border: oklch(1 0 0 / 10%); /* White with 10% opacity */
--input: oklch(1 0 0 / 15%); /* White with 15% opacity */
--ring: oklch(0.408 0.123 38.172); /* Red-orange for focus */
}
Chart Colors
--chart-1: oklch(0.837 0.128 66.29); /* Warm yellow */
--chart-2: oklch(0.705 0.213 47.604); /* Orange */
--chart-3: oklch(0.646 0.222 41.116); /* Dark orange */
--chart-4: oklch(0.553 0.195 38.402); /* Red-orange */
--chart-5: oklch(0.47 0.157 37.304); /* Deep red-orange */
Sidebar Colors
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.646 0.222 41.116);
--sidebar-primary-foreground: oklch(0.98 0.016 73.684);
--sidebar-accent: oklch(0.967 0.001 286.375);
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
--sidebar-border: oklch(0.92 0.004 286.32);
--sidebar-ring: oklch(0.75 0.183 55.934);
Color Usage
| Color | Usage |
|---|---|
| Primary | Main CTA buttons, active links, selected items |
| Secondary | Secondary buttons, badges |
| Muted | Disabled states, placeholder text, subtle backgrounds |
| Accent | Hover states, subtle highlights |
| Destructive | Delete buttons, error states |
| Ring | Focus indicators, form input focus |
4. Layout System
Main Layout Structure
The application uses a sidebar + content layout pattern:
┌─────────────────────────────┐
│ SidebarProvider │
├──────────┬──────────────────┤
│ │ │
│AppSidebar│ SidebarInset │
│ ├──────────────────┤
│ │ SiteHeader │
│ Logo │ (breadcrumbs) │
│ Nav ├──────────────────┤
│ Items │ │
│ │ Main Content │
│ Footer │ │
│ (User) │ │
│ │ │
└──────────┴──────────────────┘
Layout Implementation
// Standard page layout
export default function DashboardClient() {
return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
<SiteHeader />
<main className="flex flex-col gap-4 p-4 md:gap-6 md:p-6">
{/* Page content */}
</main>
</SidebarInset>
</SidebarProvider>
);
}
Content Container Sizing
// Wide content area with centered max-width
<div className="flex flex-col gap-6 py-4 md:gap-6 md:py-6 px-4 lg:px-16">
{/* Content */}
</div>
// Grid layout patterns
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Columns adjust: 1 on mobile, 3 on desktop */}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* Responsive grid: 1 → 2 → 3 columns */}
</div>
5. Navigation & Sidebar
AppSidebar Component
Located in components/app-sidebar.tsx
Features:
- Collapsible sidebar (offcanvas mode on mobile)
- Uses
next-authfor user session and roles - Dynamic navigation based on user role (admin/superadmin/user)
- Logo and brand in header
- User profile footer with avatar
Navigation Items:
For Regular Users:
- Library →
/dashboard - Liked Videos →
/dashboard/liked-videos - History →
/dashboard/watch-history - Search →
#(secondary item)
For Admins/Superadmins (Additional):
- Admin (collapsible parent with submenu):
- Manage Users →
/admin/users - Manage Enrollments →
/admin/enrollments - Manage Courses →
/admin/courses - Manage Playlists →
/admin/playlists - Manage Videos →
/admin/videos
- Manage Users →
SiteHeader Component
Located in components/site-header.tsx
Features:
- Responsive breadcrumb navigation
- Sidebar toggle trigger button
- Dynamic breadcrumbs based on current route
- Breadcrumb mapping for all main routes
Breadcrumb Pattern:
Dashboard
Dashboard > Liked Videos
Dashboard > Watch History
Admin Panel
Admin Panel > Users > User Details
Admin Panel > Videos > Edit Video
NavMain Component
Located in components/nav-main.tsx
Features:
- Collapsible menu items with expandable submenus
- Icon support (Tabler icons)
- Smooth transitions with chevron rotation
- Accessible keyboard navigation
// Usage
<NavMain
items={[
{
title: 'Dashboard',
url: '/dashboard',
icon: IconDashboard
},
{
title: 'Admin',
url: '/admin',
icon: IconShieldCheck,
items: [
{ title: 'Manage Users', url: '/admin/users' }
]
}
]}
/>
NavSecondary Component
Located in components/nav-secondary.tsx
For secondary navigation items (Search, Help, etc.)
NavUser Component
Located in components/nav-user.tsx
Features:
- User avatar display
- User name and email
- Dropdown menu with user actions
- Sign out button
- Accessible user menu
6. Page Layouts
Login Page
Location: app/login/page.tsx
Layout Structure:
Centered Container (min-h-screen, flex-col)
├── Brand Logo + Text (top)
├── Vault Image
└── Login Form (Card with Google OAuth button)
Styling:
<div className="bg-muted flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
<div className="flex w-full max-w-sm flex-col gap-6">
{/* Content */}
</div>
</div>
Key Features:
- Centered, max-width container (sm = 448px)
- Muted background color
- Responsive padding (6 on mobile, 10 on desktop)
- Logo + app name at top
- Vault imagery
- Google OAuth login form in card
Dashboard Page
Location: app/dashboard/page.tsx (server) → dashboard-client.tsx (client)
Layout Structure:
Sidebar + Content Layout
├── AppSidebar
└── SidebarInset
├── SiteHeader (breadcrumbs)
└── Main Content
├── Hero Section (Welcome)
├── Video Carousels (by course/playlist)
├── Segmented Progress Bars
└── Lock indicators for restricted content
Content Structure:
<div className="flex flex-col gap-6">
{/* Section: Welcome/Title */}
<div>
<h1 className="text-2xl font-bold">Welcome back, {userName}</h1>
<p className="text-muted-foreground">Continue your learning</p>
</div>
{/* Section: Courses/Playlists with Video Carousels */}
{playlists.map(playlist => (
<div key={playlist.id} className="flex flex-col gap-4">
<h2 className="text-xl font-semibold">{playlist.title}</h2>
<Carousel>
{/* Video cards with progress bars */}
</Carousel>
</div>
))}
</div>
Admin Page
Location: app/admin/page.tsx (server) → admin-client.tsx (client)
Layout Structure:
Sidebar + Content Layout
├── AppSidebar (with Admin menu)
└── SidebarInset
├── SiteHeader (breadcrumbs)
└── Main Content
├── Page Title & Description
├── Grid of Management Cards (2-3 columns)
│ ├── Video Statistics Card
│ ├── Manage Users Card
│ ├── Manage Courses Card
│ ├── Manage Playlists Card
│ ├── Manage Videos Card
│ └── Manage Enrollments Card
└── Admin Notifications (right sidebar)
Admin Grid Layout:
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-2">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* Admin cards */}
</div>
</div>
<div className="lg:col-span-1">
<AdminNotifications />
</div>
</div>
7. Component Library
shadcn/ui Components
The following pre-built components are used throughout the application:
| Component | Used For |
|---|---|
| Button | CTAs, form submissions, interactive elements |
| Card | Container for content sections |
| Input | Text input fields |
| Label | Form labels |
| Badge | Tags, status indicators, trending indicators |
| Sidebar | Main navigation (with collapsible support) |
| Dropdown Menu | User menus, action menus |
| Dialog | Modal dialogs |
| Drawer | Mobile-friendly off-canvas menus |
| Table | Data tables with sorting, filtering, pagination |
| Tabs | Tab navigation |
| Carousel | Image/video sliders |
| Chart | Data visualization (AreaChart, BarChart, etc.) |
| Select | Dropdown select fields |
| Checkbox | Multi-select checkboxes |
| Form/Field | Form field containers and validation |
| Collapsible | Expandable/collapsible sections |
| Progress | Progress bars |
| Avatar | User profile pictures |
| Separator | Visual dividers |
| Toast/Sonner | Toast notifications |
| Tooltip | Info tooltips |
Custom Components
HlsPlayer (components/hls.tsx)
- HLS video streaming with fallback to MP4
- Subtitle/caption support
- Controls with no-download protection
- Used in: Video player pages
DataTable (components/data-table.tsx)
- Advanced table with sorting, filtering, pagination
- Column visibility toggle
- Drag-and-drop row reordering (via dnd-kit)
- Export functionality
- Used in: Admin management pages (Users, Videos, Courses, etc.)
SegmentedProgressBar (components/segmented-progress-bar.tsx)
- Shows watched segments of video
- Visual indication of progress across duration
- Used in: Dashboard video carousels
VideoCarousel (components/VideoCarousel.tsx)
- Embla carousel-based video slider
- Responsive grid layout
- Lock indicators for restricted content
- Used in: Dashboard, video listings
CommentsSection (components/comments-section.tsx)
- Comments display and threading
- Used in: Video player pages
LoginForm (components/login-form.tsx)
- Google OAuth integration
- Card-based layout
- Terms and privacy links
- Used in: Login page
8. Typography & Spacing
Font Families
The project uses Geist font family (Next.js default):
--font-sans: var(--font-geist-sans)- Primary (body text, UI)--font-mono: var(--font-geist-mono)- Monospace (code, technical text)
Imported in layout.tsx:
import { Geist, Geist_Mono } from "next/font/google";
Typography Scale
| Element | Class | Size | Weight | Usage |
|---|---|---|---|---|
| H1 | .text-3xl |
30px | bold (700) | Page titles |
| H2 | .text-2xl |
24px | bold (700) | Section titles |
| H3 | .text-xl |
20px | semibold (600) | Subsection titles |
| H4 | .text-lg |
18px | semibold (600) | Card titles |
| Body | .text-base |
16px | normal (400) | Body text |
| Small | .text-sm |
14px | normal (400) | Labels, captions, secondary text |
| Extra Small | .text-xs |
12px | normal (400) | Tiny labels |
Spacing Scale
Tailwind default spacing (4px base):
| Class | Size |
|---|---|
gap-1 |
4px |
gap-2 |
8px |
gap-3 |
12px |
gap-4 |
16px |
gap-6 |
24px |
gap-8 |
32px |
p-4 |
16px padding |
p-6 |
24px padding |
py-4 |
16px vertical padding |
px-4 |
16px horizontal padding |
Text Opacity/Color Hierarchy
// Primary text
<p className="text-foreground">Main content</p>
// Secondary text
<p className="text-muted-foreground">Secondary info</p>
// Subtle text
<span className="text-xs text-muted-foreground">Caption</span>
9. Form Patterns
Login Form Pattern
Located in components/login-form.tsx
<div className="flex flex-col gap-6">
<Card>
<CardHeader className="text-center">
<CardTitle className="text-xl">Welcome</CardTitle>
<CardDescription>Please login with your account</CardDescription>
</CardHeader>
<CardContent>
<form>
<FieldGroup>
<Field>
<Button
variant="outline"
className="w-full flex items-center justify-center gap-2"
onClick={() => signIn('google')}
>
<GoogleIcon className="w-4 h-4" />
Login with Google
</Button>
</Field>
</FieldGroup>
</form>
</CardContent>
</Card>
<FieldDescription className="text-center">
By continuing, you agree to our <a href="#">Terms of Service</a> and
<a href="#">Privacy Policy</a>
</FieldDescription>
</div>
Admin Form Patterns
Located in app/admin/*/ directories
Data Table Integration:
<DataTable
columns={columns}
data={data}
onSave={handleSave}
onDelete={handleDelete}
/>
Modal Form Pattern:
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Create New Item</DialogTitle>
</DialogHeader>
<form>
{/* Form fields */}
</form>
</DialogContent>
</Dialog>
10. Responsive Design
Tailwind Breakpoints
sm: 640px
md: 768px
lg: 1024px
xl: 1280px
2xl: 1536px
Mobile-First Approach
All responsive classes use mobile-first convention:
// Mobile: 1 column, Tablet: 2 columns, Desktop: 3 columns
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* Content */}
</div>
// Mobile: padding-4, Desktop: padding-6
<main className="p-4 md:p-6">
{/* Content */}
</main>
// Mobile: hidden, Desktop: visible
<aside className="hidden md:block">
{/* Content only on desktop */}
</aside>
Mobile-Specific Components
- Drawer - Off-canvas menus on mobile (instead of Dialog)
- Sidebar Collapsible - Sidebar collapses to mobile menu on small screens
- useMobile Hook -
hooks/use-mobile.tsfor React-based breakpoint logic
const isMobile = useIsMobile();
return isMobile ? <MobileLayout /> : <DesktopLayout />;
Container Queries
Used for responsive component sizing:
<div className="@container">
<h1 className="@[250px]:text-3xl text-2xl">
Responsive heading
</h1>
</div>
11. Dark Mode Implementation
Theme Provider Setup
Located in app/providers.tsx:
<ThemeProvider
attribute="class" // Toggles 'class' on <html>
defaultTheme="dark" // Dark by default
enableSystem={false} // Don't auto-detect system preference
>
{children}
</ThemeProvider>
Dark Mode Styling
CSS variables automatically switch in .dark class:
// Light mode (automatic)
:root {
--background: oklch(1 0 0); /* White */
--foreground: oklch(0.141 0.005 285.823); /* Dark gray */
}
// Dark mode (when .dark is on <html>)
.dark {
--background: oklch(0.141 0.005 285.823); /* Dark gray */
--foreground: oklch(0.985 0 0); /* White */
}
Toggle Theme Button Pattern
// In component
const { theme, setTheme } = useTheme();
<Button
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
>
{theme === 'dark' ? <SunIcon /> : <MoonIcon />}
</Button>
12. Reusable Patterns
Protected Page Pattern
Server Component (checks auth):
// app/dashboard/page.tsx
import { requireUser } from '@/lib/auth-check';
import DashboardClient from './dashboard-client';
export default async function DashboardPage() {
const session = await requireUser('/login');
return <DashboardClient />;
}
Client Component (renders content):
// app/dashboard/dashboard-client.tsx
'use client';
import React from 'react';
import { AppSidebar } from '@/components/app-sidebar';
import { SiteHeader } from '@/components/site-header';
export default function DashboardClient() {
return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
<SiteHeader />
<main /* content */>
</SidebarInset>
</SidebarProvider>
);
}
Role-Based Navigation
Located in components/app-sidebar.tsx:
const { data: session } = useSession();
const role = session?.user?.role ?? 'user';
const navMain = React.useMemo(() => {
const base = [...navMainBase];
if (role === 'admin' || role === 'superadmin') {
base.unshift({
title: 'Admin',
url: '/admin',
icon: IconShieldCheck,
items: [/*submenu items*/]
});
}
return base;
}, [role]);
Session Initialization
Located in app/layout.tsx:
export default async function RootLayout({ children }) {
// Get server session once, pass to client providers
const session = await getServerSession(authOptions);
return (
<html>
<body>
<Providers session={session}>
{children}
</Providers>
<Toaster />
</body>
</html>
);
}
Data Fetching Pattern
Using useFetch/SWR for client-side data:
// hooks/usePlaylists.ts
export function usePlaylists() {
const [subjects, setSubjects] = React.useState([]);
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
fetchPlaylists().then(data => {
setSubjects(data);
setIsLoading(false);
});
}, []);
return { subjects, isLoading };
}
// Usage in component
export default function DashboardClient() {
const { subjects, isLoading } = usePlaylists();
if (isLoading) return <LoadingState />;
return <>{/* Content */}</>;
}
Carousel Pattern
// Embla-based carousel
<Carousel className="w-full">
<CarouselContent className="gap-4">
{videos.map(video => (
<CarouselItem key={video.id} className="basis-1/2 md:basis-1/3 lg:basis-1/4">
<VideoCard video={video} />
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
Badge & Status Pattern
// Icon + Badge combination
<div className="flex items-center gap-2">
<Badge variant="outline">
<IconTrendingUp className="size-4" />
+12.5%
</Badge>
</div>
// Status badge
<Badge variant={status === 'active' ? 'default' : 'secondary'}>
{status}
</Badge>
13. Asset Guidelines
Logo & Branding
- Icon:
/public/icon.svg- Small 5x5 size in sidebar header - Vault Image:
/public/vault.png- 1:1 aspect ratio for login page - High-Res Alternative:
/public/vault.exr- For promotional use
Image Optimization
// Use Next.js Image for optimization
import Image from 'next/image';
<Image
src="/path/to/image.png"
alt="Description"
width={400}
height={300}
quality={60}
/>
// Regular images
<img src="/icon.svg" alt="Icon" className="size-5" />
Approved Icon Sets
-
Tabler Icons (
@tabler/icons-react) - Primary- Large collection (4000+)
- Consistent stroke weight
- Import:
import { IconHome, IconUsers } from '@tabler/icons-react';
-
Lucide React (
lucide-react) - Secondary- Modern, clean icons
- Import:
import { Home, Users } from 'lucide-react';
-
SVG Files - Custom branding
- Small icons in public/
- Optimized for performance
Sizing Conventions
// Icon sizes
<Icon className="size-3" /> /* 12px */
<Icon className="size-4" /> /* 16px */
<Icon className="size-5" /> /* 20px */
<Icon className="w-6 h-6" /> /* 24px */
<Icon className="w-8 h-8" /> /* 32px */
// Image sizes
<Image className="w-full" /> /* Full width */
<Image className="max-w-sm" /> /* Max 448px */
<Image className="max-w-md" /> /* Max 512px */
Quick Reference - Common Patterns
Button Variants
<Button>Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Delete</Button>
<Button disabled>Disabled</Button>
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
Card Layout
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Subtitle</CardDescription>
</CardHeader>
<CardContent>
{/* Content */}
</CardContent>
<CardFooter>
{/* Footer */}
</CardFooter>
</Card>
Container Classes
// Full width
className="w-full"
// Max width containers
className="w-full max-w-sm" /* 448px */
className="w-full max-w-md" /* 512px */
className="w-full max-w-lg" /* 576px */
className="w-full max-w-2xl" /* 672px */
// Flex containers
className="flex flex-col gap-4"
className="flex items-center justify-between"
// Grid containers
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
Responsive Padding
className="p-4 md:p-6 lg:p-8" /* All sides */
className="px-4 py-6" /* Horizontal & vertical */
className="p-4 md:py-6 md:px-8" /* Different per breakpoint */
Text & Styling
className="text-foreground" /* Main text */
className="text-muted-foreground" /* Secondary text */
className="text-sm text-muted-foreground" /* Label text */
className="font-semibold" /* Bold text */
className="line-clamp-1" /* Truncate to 1 line */
className="text-center" /* Centered text */
Migration Checklist for New Projects
When creating a new app with this design system:
- Copy
globals.css(CSS variables) - Copy
tailwind.config.cjs - Copy
components/ui/directory (all base components) - Copy
components/app-sidebar.tsx,site-header.tsx,nav-*.tsx - Copy
app/providers.tsx(SessionProvider, ThemeProvider) - Copy
lib/utils.ts(utility functions) - Copy
lib/auth-options.tsand auth-related files - Install dependencies from
package.json - Update branding assets (/public icons, logos)
- Customize navigation items in
app-sidebar.tsx - Update theme colors in
globals.cssif needed - Test responsive design on mobile/tablet/desktop
Key Takeaways
- Framework: Next.js 16 with shadcn/ui component library
- Styling: Tailwind CSS with OKLch color variables
- Layout: Sidebar + content pattern with collapsible nav
- Dark Mode: CSS class-based switching with automatic variable updates
- Components: Pre-built shadcn/ui components + custom components (HLS, DataTable, etc.)
- Responsiveness: Mobile-first, Tailwind breakpoints (sm/md/lg/xl)
- Navigation: Role-based dynamic nav, breadcrumb system
- Auth: NextAuth.js with Google OAuth integration
- Icons: Tabler Icons (primary), Lucide (secondary)
- Consistency: Use className patterns, spacing scale, and color variables throughout
Last Updated: February 2026 Version: 1.0
For questions or updates to this design system guide, refer to the component files and config files referenced throughout.