forked from cardosofelipe/fast-next-template
Revert Zustand persist middleware approach and restore AuthInitializer
- Remove persist middleware from authStore (causing hooks timing issues) - Restore original AuthInitializer component pattern - Keep good Phase 3 optimizations: - Theme FOUC fix (inline script) - React Query refetchOnWindowFocus disabled - Code splitting for dev/auth components - Shared form components (FormField, useFormError) - Store location in lib/stores
This commit is contained in:
@@ -5,7 +5,15 @@
|
||||
*/
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
import { ComponentShowcase } from '@/components/dev/ComponentShowcase';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
// Code-split heavy dev component (787 lines)
|
||||
const ComponentShowcase = dynamic(
|
||||
() => import('@/components/dev/ComponentShowcase').then((mod) => mod.ComponentShowcase),
|
||||
{
|
||||
loading: () => <div className="p-8 text-center text-muted-foreground">Loading components...</div>,
|
||||
}
|
||||
);
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Component Showcase | Dev',
|
||||
|
||||
66
frontend/src/app/dev/docs/design-system/[...slug]/page.tsx
Normal file
66
frontend/src/app/dev/docs/design-system/[...slug]/page.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Dynamic Documentation Route
|
||||
* Renders markdown files from docs/ directory
|
||||
* Access: /dev/docs/design-system/01-foundations, etc.
|
||||
*/
|
||||
|
||||
import { notFound } from 'next/navigation';
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import matter from 'gray-matter';
|
||||
import { MarkdownContent } from '@/components/docs/MarkdownContent';
|
||||
|
||||
interface DocPageProps {
|
||||
params: Promise<{ slug: string[] }>;
|
||||
}
|
||||
|
||||
// Generate static params for all documentation files
|
||||
export async function generateStaticParams() {
|
||||
const docsDir = path.join(process.cwd(), 'docs', 'design-system');
|
||||
|
||||
try {
|
||||
const files = await fs.readdir(docsDir);
|
||||
const mdFiles = files.filter(file => file.endsWith('.md'));
|
||||
|
||||
return mdFiles.map(file => ({
|
||||
slug: [file.replace(/\.md$/, '')],
|
||||
}));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Get markdown file content
|
||||
async function getDocContent(slug: string[]) {
|
||||
const filePath = path.join(process.cwd(), 'docs', 'design-system', ...slug) + '.md';
|
||||
|
||||
try {
|
||||
const fileContent = await fs.readFile(filePath, 'utf-8');
|
||||
const { data, content } = matter(fileContent);
|
||||
|
||||
return {
|
||||
frontmatter: data,
|
||||
content,
|
||||
filePath: slug.join('/'),
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default async function DocPage({ params }: DocPageProps) {
|
||||
const { slug } = await params;
|
||||
const doc = await getDocContent(slug);
|
||||
|
||||
if (!doc) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<MarkdownContent content={doc.content} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Documentation Hub
|
||||
* Central hub for all design system documentation
|
||||
* Access: /docs
|
||||
* Access: /dev/docs
|
||||
*/
|
||||
|
||||
import Link from 'next/link';
|
||||
@@ -22,14 +22,14 @@ const gettingStartedDocs: DocItem[] = [
|
||||
{
|
||||
title: 'Quick Start',
|
||||
description: '5-minute crash course to get up and running with the design system',
|
||||
href: '/docs/design-system/00-quick-start',
|
||||
href: '/dev/docs/design-system/00-quick-start',
|
||||
icon: <Sparkles className="h-5 w-5" />,
|
||||
badge: 'Start Here',
|
||||
},
|
||||
{
|
||||
title: 'README',
|
||||
description: 'Complete overview and learning paths for the design system',
|
||||
href: '/docs/design-system/README',
|
||||
href: '/dev/docs/design-system/README',
|
||||
icon: <BookOpen className="h-5 w-5" />,
|
||||
},
|
||||
];
|
||||
@@ -38,43 +38,43 @@ const coreConceptsDocs: DocItem[] = [
|
||||
{
|
||||
title: 'Foundations',
|
||||
description: 'Colors (OKLCH), typography, spacing, and shadows',
|
||||
href: '/docs/design-system/01-foundations',
|
||||
href: '/dev/docs/design-system/01-foundations',
|
||||
icon: <Palette className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
title: 'Components',
|
||||
description: 'shadcn/ui component library guide and usage patterns',
|
||||
href: '/docs/design-system/02-components',
|
||||
href: '/dev/docs/design-system/02-components',
|
||||
icon: <Code2 className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
title: 'Layouts',
|
||||
description: 'Layout patterns with Grid vs Flex decision trees',
|
||||
href: '/docs/design-system/03-layouts',
|
||||
href: '/dev/docs/design-system/03-layouts',
|
||||
icon: <Layout className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
title: 'Spacing Philosophy',
|
||||
description: 'Parent-controlled spacing strategy and best practices',
|
||||
href: '/docs/design-system/04-spacing-philosophy',
|
||||
href: '/dev/docs/design-system/04-spacing-philosophy',
|
||||
icon: <FileCode className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
title: 'Component Creation',
|
||||
description: 'When to create vs compose components',
|
||||
href: '/docs/design-system/05-component-creation',
|
||||
href: '/dev/docs/design-system/05-component-creation',
|
||||
icon: <Code2 className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
title: 'Forms',
|
||||
description: 'Form patterns with react-hook-form and Zod validation',
|
||||
href: '/docs/design-system/06-forms',
|
||||
href: '/dev/docs/design-system/06-forms',
|
||||
icon: <FileCode className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
title: 'Accessibility',
|
||||
description: 'WCAG AA compliance, keyboard navigation, and screen readers',
|
||||
href: '/docs/design-system/07-accessibility',
|
||||
href: '/dev/docs/design-system/07-accessibility',
|
||||
icon: <Accessibility className="h-5 w-5" />,
|
||||
},
|
||||
];
|
||||
@@ -83,39 +83,21 @@ const referencesDocs: DocItem[] = [
|
||||
{
|
||||
title: 'AI Guidelines',
|
||||
description: 'Rules and best practices for AI code generation',
|
||||
href: '/docs/design-system/08-ai-guidelines',
|
||||
href: '/dev/docs/design-system/08-ai-guidelines',
|
||||
icon: <Lightbulb className="h-5 w-5" />,
|
||||
badge: 'AI',
|
||||
},
|
||||
{
|
||||
title: 'Quick Reference',
|
||||
description: 'Cheat sheet for quick lookups and common patterns',
|
||||
href: '/docs/design-system/99-reference',
|
||||
href: '/dev/docs/design-system/99-reference',
|
||||
icon: <Search className="h-5 w-5" />,
|
||||
},
|
||||
];
|
||||
|
||||
export default function DocsHub() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Header */}
|
||||
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<BookOpen className="h-6 w-6 text-primary" />
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold">FastNext Documentation</h1>
|
||||
<p className="text-xs text-muted-foreground">Design System & Component Library</p>
|
||||
</div>
|
||||
</div>
|
||||
<Link href="/dev">
|
||||
<Button variant="outline" size="sm">
|
||||
Interactive Demos
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="bg-background">
|
||||
{/* Hero Section */}
|
||||
<section className="border-b bg-gradient-to-b from-background to-muted/20 py-16">
|
||||
<div className="container mx-auto px-4">
|
||||
@@ -128,19 +110,19 @@ export default function DocsHub() {
|
||||
accessible, and maintainable user interfaces with the FastNext design system.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3 justify-center">
|
||||
<Link href="/docs/design-system/00-quick-start">
|
||||
<Link href="/dev/docs/design-system/00-quick-start">
|
||||
<Button size="lg" className="gap-2">
|
||||
<Sparkles className="h-4 w-4" />
|
||||
Get Started
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/docs/design-system/README">
|
||||
<Link href="/dev/docs/design-system/README">
|
||||
<Button variant="outline" size="lg" className="gap-2">
|
||||
<BookOpen className="h-4 w-4" />
|
||||
Full Documentation
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/dev">
|
||||
<Link href="/dev/components">
|
||||
<Button variant="outline" size="lg" className="gap-2">
|
||||
<Code2 className="h-4 w-4" />
|
||||
View Examples
|
||||
@@ -269,35 +251,6 @@ export default function DocsHub() {
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="mt-16 border-t py-8">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="flex flex-col gap-6 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-foreground mb-1">
|
||||
FastNext Design System
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Built with shadcn/ui, Tailwind CSS, and OKLCH colors
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<Link href="/dev">
|
||||
<Button variant="ghost" size="sm">
|
||||
Interactive Demos
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/docs/design-system/00-quick-start">
|
||||
<Button variant="ghost" size="sm">
|
||||
Quick Start
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -574,7 +574,7 @@ const { register, handleSubmit, formState: { errors } } = useForm({
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Learn more:{' '}
|
||||
<Link
|
||||
href="/docs/design-system/06-forms"
|
||||
href="/dev/docs/design-system/06-forms"
|
||||
className="font-medium hover:text-foreground"
|
||||
>
|
||||
Forms Documentation
|
||||
|
||||
10
frontend/src/app/dev/layout.tsx
Normal file
10
frontend/src/app/dev/layout.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Dev Layout
|
||||
* Shared layout for all development routes
|
||||
*/
|
||||
|
||||
import { DevLayout } from '@/components/dev/DevLayout';
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
return <DevLayout>{children}</DevLayout>;
|
||||
}
|
||||
@@ -509,7 +509,7 @@ export default function LayoutsPage() {
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Learn more:{' '}
|
||||
<Link
|
||||
href="/docs/design-system/03-layouts"
|
||||
href="/dev/docs/design-system/03-layouts"
|
||||
className="font-medium hover:text-foreground"
|
||||
>
|
||||
Layout Documentation
|
||||
|
||||
@@ -70,45 +70,45 @@ const documentationLinks = [
|
||||
{
|
||||
title: 'Quick Start',
|
||||
description: '5-minute crash course',
|
||||
href: '/docs/design-system/00-quick-start',
|
||||
href: '/dev/docs/design-system/00-quick-start',
|
||||
},
|
||||
{
|
||||
title: 'Complete Documentation',
|
||||
description: 'Full design system guide',
|
||||
href: '/docs/design-system/README',
|
||||
href: '/dev/docs',
|
||||
},
|
||||
{
|
||||
title: 'AI Guidelines',
|
||||
description: 'Rules for AI code generation',
|
||||
href: '/docs/design-system/08-ai-guidelines',
|
||||
href: '/dev/docs/design-system/08-ai-guidelines',
|
||||
},
|
||||
{
|
||||
title: 'Quick Reference',
|
||||
description: 'Cheat sheet for lookups',
|
||||
href: '/docs/design-system/99-reference',
|
||||
href: '/dev/docs/design-system/99-reference',
|
||||
},
|
||||
];
|
||||
|
||||
export default function DesignSystemHub() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Header */}
|
||||
<header className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="space-y-4">
|
||||
<div className="bg-background">
|
||||
{/* Hero Section */}
|
||||
<section className="border-b bg-gradient-to-b from-background to-muted/20 py-12">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="space-y-4 max-w-3xl">
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles className="h-8 w-8 text-primary" />
|
||||
<h1 className="text-4xl font-bold tracking-tight">
|
||||
Design System Hub
|
||||
</h1>
|
||||
</div>
|
||||
<p className="text-lg text-muted-foreground max-w-2xl">
|
||||
Interactive demonstrations, live examples, and copy-paste code for
|
||||
<p className="text-lg text-muted-foreground">
|
||||
Interactive demonstrations, live examples, and comprehensive documentation for
|
||||
the FastNext design system. Built with shadcn/ui + Tailwind CSS 4.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="container mx-auto px-4 py-12">
|
||||
@@ -276,32 +276,6 @@ export default function DesignSystemHub() {
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="mt-16 border-t py-8">
|
||||
<div className="container mx-auto px-4 text-center text-sm text-muted-foreground">
|
||||
<p>
|
||||
FastNext Design System • Built with{' '}
|
||||
<a
|
||||
href="https://ui.shadcn.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="font-medium hover:text-foreground"
|
||||
>
|
||||
shadcn/ui
|
||||
</a>
|
||||
{' + '}
|
||||
<a
|
||||
href="https://tailwindcss.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="font-medium hover:text-foreground"
|
||||
>
|
||||
Tailwind CSS 4
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
import dynamic from 'next/dynamic';
|
||||
import Link from 'next/link';
|
||||
import { ArrowLeft, Ruler } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -16,8 +17,22 @@ import {
|
||||
CardTitle,
|
||||
} from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Example, ExampleSection } from '@/components/dev/Example';
|
||||
import { BeforeAfter } from '@/components/dev/BeforeAfter';
|
||||
|
||||
// Code-split heavy dev components
|
||||
const Example = dynamic(
|
||||
() => import('@/components/dev/Example').then((mod) => ({ default: mod.Example })),
|
||||
{ loading: () => <div className="animate-pulse h-32 bg-muted rounded" /> }
|
||||
);
|
||||
|
||||
const ExampleSection = dynamic(
|
||||
() => import('@/components/dev/Example').then((mod) => ({ default: mod.ExampleSection })),
|
||||
{ loading: () => <div className="animate-pulse h-24 bg-muted rounded" /> }
|
||||
);
|
||||
|
||||
const BeforeAfter = dynamic(
|
||||
() => import('@/components/dev/BeforeAfter').then((mod) => ({ default: mod.BeforeAfter })),
|
||||
{ loading: () => <div className="animate-pulse h-48 bg-muted rounded" /> }
|
||||
);
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Spacing Patterns | Dev',
|
||||
@@ -507,7 +522,7 @@ export default function SpacingPage() {
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Learn more:{' '}
|
||||
<Link
|
||||
href="/docs/design-system/04-spacing-philosophy"
|
||||
href="/dev/docs/design-system/04-spacing-philosophy"
|
||||
className="font-medium hover:text-foreground"
|
||||
>
|
||||
Spacing Philosophy Documentation
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/**
|
||||
* Dynamic Documentation Route
|
||||
* Renders markdown files from docs/ directory
|
||||
* Access: /docs/design-system/01-foundations, etc.
|
||||
*/
|
||||
|
||||
import { notFound } from 'next/navigation';
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import matter from 'gray-matter';
|
||||
import Link from 'next/link';
|
||||
import { ArrowLeft, FileText } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { MarkdownContent } from '@/components/docs/MarkdownContent';
|
||||
|
||||
interface DocPageProps {
|
||||
params: Promise<{ slug: string[] }>;
|
||||
}
|
||||
|
||||
// Generate static params for all documentation files
|
||||
export async function generateStaticParams() {
|
||||
const docsDir = path.join(process.cwd(), 'docs', 'design-system');
|
||||
|
||||
try {
|
||||
const files = await fs.readdir(docsDir);
|
||||
const mdFiles = files.filter(file => file.endsWith('.md'));
|
||||
|
||||
return mdFiles.map(file => ({
|
||||
slug: ['design-system', file.replace(/\.md$/, '')],
|
||||
}));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Get markdown file content
|
||||
async function getDocContent(slug: string[]) {
|
||||
const filePath = path.join(process.cwd(), 'docs', ...slug) + '.md';
|
||||
|
||||
try {
|
||||
const fileContent = await fs.readFile(filePath, 'utf-8');
|
||||
const { data, content } = matter(fileContent);
|
||||
|
||||
return {
|
||||
frontmatter: data,
|
||||
content,
|
||||
filePath: slug.join('/'),
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default async function DocPage({ params }: DocPageProps) {
|
||||
const { slug } = await params;
|
||||
const doc = await getDocContent(slug);
|
||||
|
||||
if (!doc) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
// Extract title from first heading or use filename
|
||||
const title = doc.content.match(/^#\s+(.+)$/m)?.[1] || slug[slug.length - 1];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Header */}
|
||||
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
||||
<div className="container mx-auto flex h-16 items-center gap-4 px-4">
|
||||
<Link href="/dev">
|
||||
<Button variant="ghost" size="icon" aria-label="Back to design system">
|
||||
<ArrowLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2">
|
||||
<FileText className="h-5 w-5 text-muted-foreground" />
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold">{title}</h1>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{doc.filePath}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Content */}
|
||||
<main className="container mx-auto px-4 py-8">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<MarkdownContent content={doc.content} />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="mt-16 border-t py-6">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<Separator className="mb-6" />
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
FastNext Design System Documentation
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<Link href="/dev">
|
||||
<Button variant="outline" size="sm">
|
||||
View Interactive Demos
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/docs/design-system/README">
|
||||
<Button variant="outline" size="sm">
|
||||
Documentation Home
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
||||
import { useState } from 'react';
|
||||
import { ThemeProvider } from '@/components/theme';
|
||||
import { AuthInitializer } from '@/components/auth';
|
||||
|
||||
export function Providers({ children }: { children: React.ReactNode }) {
|
||||
const [queryClient] = useState(
|
||||
@@ -26,7 +27,7 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{/* AuthInitializer removed - Zustand persist middleware handles auto-hydration */}
|
||||
<AuthInitializer />
|
||||
{children}
|
||||
<ReactQueryDevtools initialIsOpen={false} />
|
||||
</QueryClientProvider>
|
||||
|
||||
Reference in New Issue
Block a user