Udate the projects layout. And style guide.

This commit is contained in:
sean-eskerium
2025-10-08 17:37:29 -04:00
parent 6e86fd0d9b
commit 0727245c9d
31 changed files with 5081 additions and 4191 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
{
"$schema": "https://json-schema.org/draft-07/schema#",
"version": "1.0.0",
"description": "Archon UI Component Reference for AI Agents and Developers",
"categories": {
"navigation": {
"description": "Navigation components for app and page-level navigation",
"components": [
{
"name": "MainNavigation",
"path": "archon-ui-main/src/components/layout/Navigation.tsx",
"usage": "Fixed left sidebar navigation with glassmorphism, tooltips, and active state indicators",
"props": ["className?"],
"example": "Fixed position, icon-based, tooltip on hover, neon glow on active"
},
{
"name": "PageTabs",
"path": "archon-ui-main/src/features/ui/primitives/tabs.tsx (Radix Tabs)",
"usage": "Top-level page navigation tabs (e.g., Docs/Tasks in Projects)",
"props": ["defaultValue", "value", "onValueChange"],
"example": "See Projects page (Docs/Tasks tabs) - archon-ui-main/src/features/projects/views/ProjectsView.tsx:188-210"
},
{
"name": "ViewToggleButtons",
"path": "archon-ui-main/src/features/knowledge/components/KnowledgeHeader.tsx:88-118",
"usage": "Toggle between grid and table views",
"props": ["viewMode", "onViewModeChange"],
"example": "Grid/List icon buttons with active state styling"
}
]
},
"layouts": {
"description": "Page layout patterns",
"components": [
{
"name": "CardGridLayout",
"path": "archon-ui-main/src/features/projects/components/ProjectList.tsx:100-117",
"usage": "Horizontal scrolling card grid for project cards or similar items",
"pattern": "flex gap-4 overflow-x-auto with min-w-max",
"example": "Projects page - horizontal scrollable cards",
"variant": "horizontal (default)"
},
{
"name": "SidebarListLayout",
"path": "archon-ui-main/src/features/style-guide/layouts/ProjectsLayoutExample.tsx",
"usage": "Sidebar navigation list with compact cards and search",
"pattern": "Fixed left column (w-72) with vertical list, Input for search, main content on right (flex-1)",
"example": "Projects page sidebar variant - vertical list with smaller cards",
"variant": "sidebar (alternative to horizontal cards)"
},
{
"name": "BentoGridLayout",
"path": "archon-ui-main/src/pages/SettingsPage.tsx:125-223",
"usage": "Two-column responsive grid for collapsible settings cards",
"pattern": "grid grid-cols-1 lg:grid-cols-2 gap-6",
"example": "Settings page - left/right column layout"
},
{
"name": "ResponsiveGridLayout",
"path": "archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx:158-183",
"usage": "Responsive grid for card items (1/2/3/4 columns)",
"pattern": "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",
"example": "Knowledge page grid view"
},
{
"name": "TableLayout",
"path": "archon-ui-main/src/features/knowledge/components/KnowledgeTable.tsx:68-209",
"usage": "Table with glassmorphism styling, hover states, and action buttons",
"pattern": "overflow-x-auto wrapper with full-width table",
"example": "Knowledge page table view"
}
]
},
"cards": {
"description": "Card components for various use cases",
"components": [
{
"name": "ProjectCard",
"path": "archon-ui-main/src/features/projects/components/ProjectCard.tsx",
"usage": "Card with real-time data (task counts), selection states, pinned indicator",
"features": ["glassmorphism", "hover effects", "neon glow borders", "task count pills", "pin badge"],
"example": "w-72 min-h-[180px] with gradient backgrounds"
},
{
"name": "CollapsibleSettingsCard",
"path": "archon-ui-main/src/components/ui/CollapsibleSettingsCard.tsx",
"usage": "Collapsible card with PowerButton toggle and flicker animation",
"features": ["expand/collapse", "localStorage persistence", "accent colors"],
"example": "Settings page cards"
},
{
"name": "GlassCard (Primitive)",
"path": "archon-ui-main/src/features/ui/primitives/card.tsx",
"usage": "Base glassmorphism card with configurable blur, transparency, tints, edges",
"props": ["blur?", "transparency?", "glassTint?", "edgePosition?", "edgeColor?", "size?"],
"example": "See GlassCardConfigurator for all options"
}
]
},
"information_display": {
"description": "Patterns for displaying structured information",
"components": [
{
"name": "DocumentBrowser",
"path": "archon-ui-main/src/features/knowledge/components/DocumentBrowser.tsx",
"usage": "Modal for displaying documents, code, logs, or structured information with tabs and search",
"features": ["Dialog modal", "Tabs navigation", "Search filtering", "Expandable content", "Code syntax highlighting"],
"radix_used": ["Dialog", "Tabs", "Input"],
"pattern": "Dialog + Tabs + Search input + Collapsible items with expand/collapse",
"example": "Knowledge inspector, document viewer, code browser, log viewer"
}
]
},
"buttons": {
"description": "Button components and variants",
"components": [
{
"name": "Button (Primitive)",
"path": "archon-ui-main/src/features/ui/primitives/button.tsx",
"usage": "Base button with glassmorphism variants",
"variants": ["default", "destructive", "outline", "ghost", "cyan", "purple", "green"],
"sizes": ["sm", "md", "lg", "icon"],
"example": "See ButtonConfigurator for all variants"
}
]
},
"radix_primitives": {
"description": "Radix UI primitives with Archon glassmorphism styling",
"components": [
{
"name": "Tabs",
"path": "archon-ui-main/src/features/ui/primitives/tabs.tsx",
"usage": "Tab navigation with color variants and neon glow effects",
"radix_package": "@radix-ui/react-tabs",
"parts": ["Tabs", "TabsList", "TabsTrigger", "TabsContent"],
"props": ["defaultValue", "value", "onValueChange", "color (cyan|blue|purple|orange|green|pink)"],
"example": "Projects page Docs/Tasks tabs"
},
{
"name": "Select",
"path": "archon-ui-main/src/features/ui/primitives/select.tsx",
"usage": "Dropdown select with glassmorphism and color variants",
"radix_package": "@radix-ui/react-select",
"parts": ["Select", "SelectTrigger", "SelectValue", "SelectContent", "SelectItem"],
"props": ["value", "onValueChange", "color (purple|blue|green|pink|orange|cyan)"],
"example": "Configurators use Select for all dropdowns"
},
{
"name": "Dialog",
"path": "archon-ui-main/src/features/ui/primitives/dialog.tsx",
"usage": "Modal dialogs with glassmorphism backdrop",
"radix_package": "@radix-ui/react-dialog",
"parts": ["Dialog", "DialogTrigger", "DialogContent", "DialogHeader", "DialogTitle", "DialogDescription"],
"props": ["open", "onOpenChange"],
"example": "NewProjectModal, EditTaskModal"
},
{
"name": "Checkbox",
"path": "archon-ui-main/src/features/ui/primitives/checkbox.tsx",
"usage": "Styled checkbox with color variants",
"radix_package": "@radix-ui/react-checkbox",
"parts": ["Checkbox"],
"props": ["checked", "onCheckedChange", "color (cyan|purple|blue|green|etc)"],
"example": "Settings toggles, NavigationConfigurator"
},
{
"name": "Switch",
"path": "archon-ui-main/src/features/ui/primitives/switch.tsx",
"usage": "Toggle switch with smooth animations",
"radix_package": "@radix-ui/react-switch",
"parts": ["Switch"],
"props": ["checked", "onCheckedChange"],
"example": "Feature toggles in Settings"
},
{
"name": "Tooltip",
"path": "archon-ui-main/src/features/ui/primitives/tooltip.tsx",
"usage": "Hover tooltips with glassmorphism",
"radix_package": "@radix-ui/react-tooltip",
"parts": ["TooltipProvider", "Tooltip", "TooltipTrigger", "TooltipContent"],
"props": ["delayDuration", "side", "align"],
"example": "Navigation sidebar icons"
},
{
"name": "DropdownMenu",
"path": "archon-ui-main/src/features/ui/primitives/dropdown-menu.tsx",
"usage": "Context menus with glassmorphism",
"radix_package": "@radix-ui/react-dropdown-menu",
"parts": ["DropdownMenu", "DropdownMenuTrigger", "DropdownMenuContent", "DropdownMenuItem"],
"example": "ProjectCardActions, context menus"
},
{
"name": "ToggleGroup",
"path": "archon-ui-main/src/features/ui/primitives/toggle-group.tsx",
"usage": "Mutually exclusive button group",
"radix_package": "@radix-ui/react-toggle-group",
"parts": ["ToggleGroup", "ToggleGroupItem"],
"props": ["type (single|multiple)", "value", "onValueChange"],
"example": "KnowledgeHeader type filter"
}
]
}
}
}

View File

@@ -1,156 +1,58 @@
import { useState } from 'react';
import { Palette, Component, Layout, Code } from 'lucide-react';
import { PillNavigation } from '../shared/PillNavigation';
import { ThemeToggle } from '../../../components/ui/ThemeToggle';
import { GlassCardConfigurator } from '../configurators/GlassCardConfigurator';
import { ButtonConfigurator } from '../configurators/ButtonConfigurator';
import { ModalConfigurator } from '../configurators/ModalConfigurator';
import { FormConfigurator } from '../configurators/FormConfigurator';
import { TableConfigurator } from '../configurators/TableConfigurator';
import { ToggleConfigurator } from '../configurators/ToggleConfigurator';
import { SwitchConfigurator } from '../configurators/SwitchConfigurator';
import { CheckboxConfigurator } from '../configurators/CheckboxConfigurator';
import { ColorsFoundation } from '../foundations/ColorsFoundation';
import { TypographyFoundation } from '../foundations/TypographyFoundation';
import { SpacingFoundation } from '../foundations/SpacingFoundation';
import { EffectsFoundation } from '../foundations/EffectsFoundation';
import { LayoutsPattern } from '../patterns/LayoutsPattern';
import { FeedbackPattern } from '../patterns/FeedbackPattern';
import { NavigationPattern } from '../patterns/NavigationPattern';
import { DataDisplayPattern } from '../patterns/DataDisplayPattern';
import { CompositionsExample } from '../examples/CompositionsExample';
import { PagesExample } from '../examples/PagesExample';
import { WorkflowsExample } from '../examples/WorkflowsExample';
import { RAGSettingsExample } from '../examples/RAGSettingsExample';
const FOUNDATION_TABS = [
{ id: 'Colors', label: 'Colors', component: ColorsFoundation },
{ id: 'Typography', label: 'Typography', component: TypographyFoundation },
{ id: 'Spacing', label: 'Spacing', component: SpacingFoundation },
{ id: 'Effects', label: 'Effects', component: EffectsFoundation },
];
const COMPONENT_TABS = [
{ id: 'Cards', label: 'Cards', component: GlassCardConfigurator },
{ id: 'Buttons', label: 'Buttons', component: ButtonConfigurator },
{ id: 'Forms', label: 'Forms', component: FormConfigurator },
{ id: 'Tables', label: 'Tables', component: TableConfigurator },
{ id: 'Modals', label: 'Modals', component: ModalConfigurator },
{ id: 'Toggles', label: 'Toggles', component: ToggleConfigurator },
{ id: 'Switches', label: 'Switches', component: SwitchConfigurator },
{ id: 'Checkboxes', label: 'Checkboxes', component: CheckboxConfigurator },
];
const PATTERN_TABS = [
{ id: 'Layouts', label: 'Layouts', component: LayoutsPattern },
{ id: 'Feedback', label: 'Feedback', component: FeedbackPattern },
{ id: 'Navigation', label: 'Navigation', component: NavigationPattern },
{ id: 'Data Display', label: 'Data Display', component: DataDisplayPattern },
];
const EXAMPLE_TABS = [
{ id: 'Compositions', label: 'Compositions', component: CompositionsExample },
{ id: 'Pages', label: 'Pages', component: PagesExample },
{ id: 'Workflows', label: 'Workflows', component: WorkflowsExample },
{ id: 'RAG Settings', label: 'RAG Settings', component: RAGSettingsExample },
];
import { useState } from "react";
import { Palette, Layout, Settings } from "lucide-react";
import { PillNavigation, type PillNavigationItem } from "../shared/PillNavigation";
import { StyleGuideTab } from "../tabs/StyleGuideTab";
import { LayoutsTab } from "../tabs/LayoutsTab";
import { ConfiguratorsTab } from "../tabs/ConfiguratorsTab";
import { ThemeToggle } from "../../../components/ui/ThemeToggle";
export const StyleGuideView = () => {
const [selectedSection, setSelectedSection] = useState('foundations');
const [selectedComponent, setSelectedComponent] = useState<string | null>('Colors');
const [activeTab, setActiveTab] = useState<"style-guide" | "layouts" | "configurators">(
"style-guide",
);
const handleSectionChange = (section: string) => {
setSelectedSection(section);
// Reset to first item of new section
if (section === 'foundations') setSelectedComponent('Colors');
else if (section === 'components') setSelectedComponent('Cards');
else if (section === 'patterns') setSelectedComponent('Layouts');
else if (section === 'examples') setSelectedComponent('Compositions');
else setSelectedComponent(null);
};
const renderContent = () => {
if (selectedSection === 'foundations' && selectedComponent) {
const tab = FOUNDATION_TABS.find(t => t.id === selectedComponent);
if (tab) {
const FoundationComponent = tab.component;
return <FoundationComponent />;
}
}
if (selectedSection === 'components' && selectedComponent) {
const tab = COMPONENT_TABS.find(t => t.id === selectedComponent);
if (tab) {
const ComponentConfigurator = tab.component;
return <ComponentConfigurator />;
}
}
if (selectedSection === 'patterns' && selectedComponent) {
const tab = PATTERN_TABS.find(t => t.id === selectedComponent);
if (tab) {
const PatternComponent = tab.component;
return <PatternComponent />;
}
}
if (selectedSection === 'examples' && selectedComponent) {
const tab = EXAMPLE_TABS.find(t => t.id === selectedComponent);
if (tab) {
const ExampleComponent = tab.component;
return <ExampleComponent />;
}
}
// Default content for other sections or no selection
const sectionContent = {
foundations: { icon: <Palette className="w-16 h-16 mx-auto mb-4 opacity-50" />, text: "Select a foundation element from the dropdown above" },
components: { icon: <Component className="w-16 h-16 mx-auto mb-4 opacity-50" />, text: "Select a component from the dropdown above" },
patterns: { icon: <Layout className="w-16 h-16 mx-auto mb-4 opacity-50" />, text: "Select a pattern from the dropdown above" },
examples: { icon: <Code className="w-16 h-16 mx-auto mb-4 opacity-50" />, text: "Select an example from the dropdown above" }
};
const content = sectionContent[selectedSection as keyof typeof sectionContent];
return (
<div className="text-center py-16 text-gray-500 dark:text-gray-400">
{content.icon}
<p>{content.text}</p>
</div>
);
};
const navigationItems: PillNavigationItem[] = [
{ id: "style-guide", label: "Style Guide", icon: <Palette className="w-4 h-4" /> },
{ id: "layouts", label: "Layouts", icon: <Layout className="w-4 h-4" /> },
{ id: "configurators", label: "Configurators", icon: <Settings className="w-4 h-4" /> },
];
return (
<div className="space-y-12">
{/* Header */}
<div className="relative">
{/* Theme Toggle in top right */}
<div className="absolute top-0 right-0">
<ThemeToggle accentColor="blue" />
</div>
<div className="text-center space-y-4">
<h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-4">Interactive Style Guide</h1>
<h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-4">
Archon UI Style Guide
</h1>
<p className="text-gray-600 dark:text-gray-400 text-lg max-w-2xl mx-auto">
Configure and preview Archon's glassmorphism components with live code generation.
Design system foundations, layout patterns, and interactive component configurators.
</p>
</div>
</div>
{/* Pill Navigation */}
{/* Tab Navigation - Blue Pill Navigation */}
<div className="flex justify-center">
<PillNavigation
selectedSection={selectedSection}
selectedItem={selectedComponent}
onSectionChange={handleSectionChange}
onItemChange={setSelectedComponent}
items={navigationItems}
activeSection={activeTab}
onSectionClick={(id) => setActiveTab(id as typeof activeTab)}
colorVariant="blue"
showIcons={true}
showText={true}
hasSubmenus={false}
/>
</div>
{/* Content */}
{/* Tab Content */}
<div>
{renderContent()}
{activeTab === "style-guide" && <StyleGuideTab />}
{activeTab === "layouts" && <LayoutsTab />}
{activeTab === "configurators" && <ConfiguratorsTab />}
</div>
</div>
);
};
};

View File

@@ -1,638 +0,0 @@
import React, { useState } from 'react';
import { Card } from '@/features/ui/primitives/card';
import type { GlowColor } from '../types';
import { Button } from '@/features/ui/primitives/button';
import { CodeDisplay } from '../shared/CodeDisplay';
import { LivePreview } from '../shared/LivePreview';
import { cn, glassmorphism } from '@/features/ui/primitives/styles';
import {
Home,
Settings,
User,
FileText,
BarChart,
Plus,
Search,
Bell,
MoreVertical,
Calendar,
} from 'lucide-react';
interface ExampleComposition {
id: string;
name: string;
description: string;
usage: string;
component: React.ComponentType;
}
// Complete Dashboard Composition
const DashboardComposition = () => {
return (
<div className="h-96 bg-gray-50 dark:bg-gray-900 overflow-hidden rounded-lg">
{/* Top Navigation */}
<Card className="p-4 rounded-none border-b">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-gradient-to-br from-cyan-500 to-purple-500 rounded-lg" />
<span className="font-bold text-lg">Archon</span>
</div>
<nav className="hidden md:flex items-center gap-1">
{['Dashboard', 'Projects', 'Team', 'Analytics'].map((item, index) => (
<button
key={item}
className={cn(
"px-3 py-1 rounded-lg text-sm font-medium transition-all duration-200",
index === 0
? cn(glassmorphism.background.cyan, "text-cyan-700 dark:text-cyan-300")
: "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"
)}
>
{item}
</button>
))}
</nav>
<div className="flex items-center gap-2">
<Button variant="ghost" size="sm"><Search className="w-4 h-4" /></Button>
<Button variant="ghost" size="sm"><Bell className="w-4 h-4" /></Button>
<Button variant="ghost" size="sm"><User className="w-4 h-4" /></Button>
</div>
</div>
</Card>
<div className="flex h-full">
{/* Sidebar */}
<Card className="w-48 h-full rounded-none border-r">
<div className="p-3">
<nav className="space-y-1">
{[
{ icon: <Home className="w-4 h-4" />, label: 'Dashboard', active: true },
{ icon: <FileText className="w-4 h-4" />, label: 'Projects' },
{ icon: <BarChart className="w-4 h-4" />, label: 'Analytics' },
{ icon: <Settings className="w-4 h-4" />, label: 'Settings' }
].map((item) => (
<button
key={item.label}
className={cn(
"w-full flex items-center gap-2 px-2 py-1.5 rounded text-sm transition-all",
item.active
? cn(glassmorphism.background.cyan, "text-cyan-700 dark:text-cyan-300")
: "hover:bg-gray-100 dark:hover:bg-gray-800"
)}
>
{item.icon}
{item.label}
</button>
))}
</nav>
</div>
</Card>
{/* Main Content */}
<div className="flex-1 p-4 space-y-4">
{/* Stats Grid */}
<div className="grid grid-cols-3 gap-3">
{[
{ label: 'Projects', value: '24', color: 'purple' },
{ label: 'Tasks', value: '156', color: 'blue' },
{ label: 'Team', value: '8', color: 'green' }
].map((stat) => (
<Card key={stat.label} glowColor={stat.color as GlowColor} className="p-3 text-center">
<p className="text-lg font-bold">{stat.value}</p>
<p className="text-xs text-gray-600 dark:text-gray-400">{stat.label}</p>
</Card>
))}
</div>
{/* Content Grid */}
<div className="grid grid-cols-3 gap-3 flex-1">
<Card className="col-span-2 p-3">
<h3 className="font-medium text-sm mb-2">Recent Activity</h3>
<div className="space-y-1">
{['Project updated', 'Task completed', 'New member'].map((activity, i) => (
<div key={i} className="text-xs py-1 border-b border-gray-200 dark:border-gray-700 last:border-b-0">
{activity}
</div>
))}
</div>
</Card>
<Card className="p-3">
<h3 className="font-medium text-sm mb-2">Quick Actions</h3>
<div className="space-y-1">
<Button variant="outline" size="sm" className="w-full text-xs">Create</Button>
<Button variant="outline" size="sm" className="w-full text-xs">Invite</Button>
</div>
</Card>
</div>
</div>
</div>
</div>
);
};
// Project Card Collection
const ProjectCardsComposition = () => {
const projects = [
{ title: 'Alpha', status: 'Active', progress: 75, color: 'purple' },
{ title: 'Beta', status: 'Review', progress: 90, color: 'blue' },
{ title: 'Gamma', status: 'Planning', progress: 25, color: 'orange' }
];
return (
<div className="p-6 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div className="flex items-center justify-between mb-6">
<h2 className="text-xl font-bold">Projects</h2>
<Button size="sm">
<Plus className="w-4 h-4 mr-2" />
New Project
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{projects.map((project) => (
<Card
key={project.title}
glowColor={project.color as GlowColor}
className="p-4 hover:shadow-lg transition-shadow"
>
<div className="flex items-start justify-between mb-3">
<h3 className="font-semibold">Project {project.title}</h3>
<Button variant="ghost" size="sm">
<MoreVertical className="w-4 h-4" />
</Button>
</div>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-3">
Development project with team collaboration features.
</p>
<div className="mb-3">
<div className="flex justify-between text-sm mb-1">
<span>Progress</span>
<span>{project.progress}%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-cyan-500 h-2 rounded-full"
style={{ width: `${project.progress}%` }}
/>
</div>
</div>
<div className="flex items-center justify-between text-xs text-gray-500 dark:text-gray-400">
<span className="flex items-center gap-1">
<Calendar className="w-3 h-3" />
Due: 2 weeks
</span>
<span className="flex items-center gap-1">
<User className="w-3 h-3" />
5 members
</span>
</div>
</Card>
))}
</div>
</div>
);
};
// Modal with Form
const ModalFormComposition = () => {
const [showModal, setShowModal] = useState(false);
return (
<div className="relative">
<div className="p-6 text-center">
<Button onClick={() => setShowModal(true)}>
Show Modal Example
</Button>
</div>
{showModal && (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50">
<Card size="lg" glowColor="purple" className="w-full max-w-md">
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-bold">Create New Task</h2>
<Button variant="ghost" size="sm" onClick={() => setShowModal(false)}>
×
</Button>
</div>
<form className="space-y-4">
<div>
<label className="block text-sm font-medium mb-1">Task Title</label>
<input
type="text"
className={cn(
"w-full px-3 py-2 rounded-md text-sm",
glassmorphism.background.subtle,
glassmorphism.border.default,
glassmorphism.border.focus
)}
placeholder="Enter task title"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Priority</label>
<select
className={cn(
"w-full px-3 py-2 rounded-md text-sm",
glassmorphism.background.subtle,
glassmorphism.border.default,
glassmorphism.border.focus
)}
>
<option>High</option>
<option>Medium</option>
<option>Low</option>
</select>
</div>
<div>
<label className="block text-sm font-medium mb-1">Description</label>
<textarea
className={cn(
"w-full px-3 py-2 rounded-md text-sm h-20 resize-none",
glassmorphism.background.subtle,
glassmorphism.border.default,
glassmorphism.border.focus
)}
placeholder="Describe the task"
/>
</div>
<div className="flex gap-3 pt-4">
<Button
variant="outline"
className="flex-1"
onClick={() => setShowModal(false)}
>
Cancel
</Button>
<Button
className="flex-1"
onClick={() => setShowModal(false)}
>
Create Task
</Button>
</div>
</form>
</Card>
</div>
)}
</div>
);
};
const EXAMPLE_COMPOSITIONS: ExampleComposition[] = [
{
id: 'dashboard',
name: 'Complete Dashboard',
description: 'Full dashboard layout with navigation, sidebar, stats, and content areas',
usage: 'Admin panels, application dashboards, overview pages',
component: DashboardComposition
},
{
id: 'cards',
name: 'Project Cards Grid',
description: 'Collection of project cards with consistent styling and interactions',
usage: 'Project portfolios, product grids, content galleries',
component: ProjectCardsComposition
},
{
id: 'modal',
name: 'Modal with Form',
description: 'Interactive modal dialog with form inputs and glassmorphism styling',
usage: 'Create/edit dialogs, settings panels, confirmation prompts',
component: ModalFormComposition
}
];
const generateCode = (compositionId: string) => {
const codeExamples = {
dashboard: `/**
* 🤖 AI CONTEXT: Complete Dashboard Composition
*
* PURPOSE: Full-featured dashboard with navigation and content
* WHEN TO USE: Admin interfaces, application dashboards, data overview
* WHEN NOT TO USE: Simple pages, mobile-first designs, content-focused sites
*
* COMPOSITION ELEMENTS:
* - Top navigation with branding and user actions
* - Collapsible sidebar with navigation items
* - Stats cards grid for key metrics
* - Content areas with recent activity and quick actions
*
* RESPONSIVE STRATEGY:
* - Desktop: Full layout with sidebar
* - Tablet: Collapsible sidebar
* - Mobile: Overlay navigation drawer
*/
import { Card } from '@/features/ui/primitives/card';
import { Button } from '@/features/ui/primitives/button';
import { glassmorphism } from '@/features/ui/primitives/styles';
export const DashboardLayout = () => {
return (
<div className="h-screen bg-gray-50 dark:bg-gray-900">
{/* Top Navigation */}
<Card className="p-4 rounded-none border-b">
<div className="flex items-center justify-between">
{/* Brand */}
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-gradient-to-br from-cyan-500 to-purple-500 rounded-lg" />
<span className="font-bold text-lg">Your App</span>
</div>
{/* Navigation */}
<nav className="hidden md:flex items-center gap-1">
{/* Navigation items */}
</nav>
{/* User Actions */}
<div className="flex items-center gap-2">
{/* User action buttons */}
</div>
</div>
</Card>
<div className="flex h-full">
{/* Sidebar */}
<Card className="w-64 h-full rounded-none border-r">
<nav className="p-4 space-y-1">
{/* Navigation items */}
</nav>
</Card>
{/* Main Content */}
<div className="flex-1 p-6 space-y-6">
{/* Stats Grid */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
{/* Stat cards */}
</div>
{/* Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Content sections */}
</div>
</div>
</div>
</div>
);
};`,
cards: `/**
* 🤖 AI CONTEXT: Project Cards Grid Composition
*
* PURPOSE: Consistent card layout for project/product display
* WHEN TO USE: Portfolios, galleries, collection views
* WHEN NOT TO USE: List data, text-heavy content, simple navigation
*
* CARD ELEMENTS:
* - Header with title and actions
* - Progress indicators for status
* - Metadata with icons and labels
* - Consistent hover states and interactions
*
* GRID BEHAVIOR:
* - Responsive: 1->2->3 columns
* - Equal heights maintained
* - Proper spacing and alignment
*/
import { Card } from '@/features/ui/primitives/card';
import { Button } from '@/features/ui/primitives/button';
export const ProjectCardsGrid = ({ projects }: { projects: any[] }) => {
return (
<div className="p-6">
{/* Header */}
<div className="flex items-center justify-between mb-6">
<h2 className="text-2xl font-bold">Projects</h2>
<Button>
<Plus className="w-4 h-4 mr-2" />
New Project
</Button>
</div>
{/* Cards Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{projects.map((project) => (
<Card
key={project.id}
glowColor={project.status}
className="p-6 hover:shadow-lg transition-all duration-300"
>
{/* Card header */}
<div className="flex items-start justify-between mb-4">
<h3 className="font-semibold text-lg">{project.title}</h3>
<Button variant="ghost" size="sm">
<MoreVertical className="w-4 h-4" />
</Button>
</div>
{/* Card content */}
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
{project.description}
</p>
{/* Progress */}
<div className="mb-4">
<div className="flex justify-between text-sm mb-2">
<span>Progress</span>
<span>{project.progress}%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-cyan-500 h-2 rounded-full transition-all"
style={{ width: \`\${project.progress}%\` }}
/>
</div>
</div>
{/* Metadata */}
<div className="flex items-center justify-between text-xs text-gray-500">
<span>Due: {project.dueDate}</span>
<span>{project.teamSize} members</span>
</div>
</Card>
))}
</div>
</div>
);
};`,
modal: `/**
* 🤖 AI CONTEXT: Modal with Form Composition
*
* PURPOSE: Interactive dialog for data input and actions
* WHEN TO USE: Create/edit workflows, settings, confirmations
* WHEN NOT TO USE: Large forms, multi-step processes, navigation
*
* MODAL STRUCTURE:
* - Backdrop with blur effect
* - Card container with glassmorphism
* - Form with consistent input styling
* - Action buttons with clear hierarchy
*
* ACCESSIBILITY:
* - Focus trap within modal
* - Escape key to close
* - Proper ARIA labels
* - Keyboard navigation
*/
import { useState } from 'react';
import { Card } from '@/features/ui/primitives/card';
import { Button } from '@/features/ui/primitives/button';
import { glassmorphism, cn } from '@/features/ui/primitives/styles';
export const ModalForm = ({ isOpen, onClose, onSubmit }: {
isOpen: boolean;
onClose: () => void;
onSubmit: (data: any) => void;
}) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50">
<Card size="lg" glowColor="purple" className="w-full max-w-md">
{/* Header */}
<div className="flex items-center justify-between mb-6">
<h2 className="text-xl font-bold">Create New Item</h2>
<Button variant="ghost" size="sm" onClick={onClose}>
×
</Button>
</div>
{/* Form */}
<form className="space-y-4" onSubmit={onSubmit}>
<div>
<label className="block text-sm font-medium mb-2">
Title
</label>
<input
type="text"
className={cn(
"w-full px-3 py-2 rounded-md text-sm",
glassmorphism.background.subtle,
glassmorphism.border.default,
glassmorphism.border.focus,
"transition-all duration-200"
)}
placeholder="Enter title"
required
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Description
</label>
<textarea
className={cn(
"w-full px-3 py-2 rounded-md text-sm h-20 resize-none",
glassmorphism.background.subtle,
glassmorphism.border.default,
glassmorphism.border.focus,
"transition-all duration-200"
)}
placeholder="Enter description"
/>
</div>
{/* Actions */}
<div className="flex gap-3 pt-4">
<Button
type="button"
variant="outline"
className="flex-1"
onClick={onClose}
>
Cancel
</Button>
<Button type="submit" className="flex-1">
Create
</Button>
</div>
</form>
</Card>
</div>
);
};`
};
return codeExamples[compositionId as keyof typeof codeExamples] || '';
};
export const CompositionsExample = () => {
const [selectedComposition, setSelectedComposition] = useState<string>('dashboard');
const currentComposition = EXAMPLE_COMPOSITIONS.find(c => c.id === selectedComposition);
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold mb-4">Complete Compositions</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Real-world examples combining multiple components into complete UI compositions.
</p>
</div>
{/* Composition Selector */}
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">Select Composition</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{EXAMPLE_COMPOSITIONS.map((composition) => (
<Card
key={composition.id}
className={cn(
"p-4 cursor-pointer transition-all duration-200",
selectedComposition === composition.id
? "border-cyan-500 shadow-[0_0_10px_rgba(34,211,238,0.3)]"
: "hover:shadow-lg"
)}
onClick={() => setSelectedComposition(composition.id)}
>
<h4 className="font-medium mb-2">{composition.name}</h4>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-2">
{composition.description}
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
<strong>Use for:</strong> {composition.usage}
</p>
</Card>
))}
</div>
</Card>
{/* Live Preview */}
{currentComposition && (
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">
{currentComposition.name} - Live Preview
</h3>
<LivePreview minHeight="400px">
<div className="w-full max-w-6xl">
<currentComposition.component />
</div>
</LivePreview>
</Card>
)}
{/* Generated Code */}
{currentComposition && (
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">Implementation Code</h3>
<CodeDisplay
code={generateCode(selectedComposition)}
showLineNumbers
/>
</Card>
)}
</div>
);
};

View File

@@ -1,395 +0,0 @@
import React, { useState } from 'react';
import { Card } from '@/features/ui/primitives/card';
import { Button } from '@/features/ui/primitives/button';
import { Switch } from '@/features/ui/primitives/switch';
import { Input } from '@/features/ui/primitives/input';
import { Label } from '@/features/ui/primitives/label';
import { CodeDisplay } from '../shared/CodeDisplay';
import {
ArrowRight, Zap, Shield, Sparkles,
BarChart, Users, DollarSign, TrendingUp,
User, Bell, Lock, Palette, Globe, Database
} from 'lucide-react';
// Landing Page Example
const LandingPageExample = () => {
return (
<div className="relative overflow-hidden rounded-lg">
<div className="bg-gradient-to-br from-gray-900 via-purple-900/20 to-gray-900 p-8">
{/* Hero Section */}
<section className="text-center py-12">
<h1 className="text-4xl font-bold mb-4 bg-gradient-to-r from-cyan-400 to-purple-400 bg-clip-text text-transparent">
Welcome to Archon
</h1>
<p className="text-gray-400 mb-8 max-w-2xl mx-auto">
Build beautiful applications with our glassmorphism design system
</p>
<div className="flex gap-4 justify-center">
<Button size="lg" className="shadow-[0_0_20px_rgba(168,85,247,0.5)]">
Get Started <ArrowRight className="ml-2 w-4 h-4" />
</Button>
<Button variant="outline" size="lg">
Learn More
</Button>
</div>
</section>
{/* Features Grid */}
<section className="mt-12 grid grid-cols-3 gap-6">
<Card accentColor="purple" className="p-6 text-center hover:scale-105 transition-transform">
<Zap className="w-12 h-12 mx-auto mb-4 text-purple-400" />
<h3 className="font-semibold mb-2">Lightning Fast</h3>
<p className="text-sm text-gray-400">Optimized performance for modern applications</p>
</Card>
<Card accentColor="cyan" className="p-6 text-center hover:scale-105 transition-transform">
<Shield className="w-12 h-12 mx-auto mb-4 text-cyan-400" />
<h3 className="font-semibold mb-2">Secure by Default</h3>
<p className="text-sm text-gray-400">Enterprise-grade security features built-in</p>
</Card>
<Card accentColor="pink" className="p-6 text-center hover:scale-105 transition-transform">
<Sparkles className="w-12 h-12 mx-auto mb-4 text-pink-400" />
<h3 className="font-semibold mb-2">Beautiful UI</h3>
<p className="text-sm text-gray-400">Glassmorphic design that stands out</p>
</Card>
</section>
</div>
</div>
);
};
// Dashboard Page Example
const DashboardPageExample = () => {
return (
<div className="p-6 space-y-6 bg-gray-900/50 rounded-lg">
{/* Header */}
<div className="flex justify-between items-center">
<div>
<h2 className="text-2xl font-bold">Dashboard</h2>
<p className="text-sm text-gray-400">Welcome back, Admin</p>
</div>
<Button>Download Report</Button>
</div>
{/* Stats Cards */}
<div className="grid grid-cols-4 gap-4">
<Card accentColor="green" className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-400">Total Revenue</p>
<p className="text-2xl font-bold">$45,231</p>
<p className="text-xs text-green-400">+12.5% from last month</p>
</div>
<DollarSign className="w-8 h-8 text-green-400" />
</div>
</Card>
<Card accentColor="blue" className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-400">Active Users</p>
<p className="text-2xl font-bold">2,543</p>
<p className="text-xs text-blue-400">+23 new today</p>
</div>
<Users className="w-8 h-8 text-blue-400" />
</div>
</Card>
<Card accentColor="purple" className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-400">Conversion Rate</p>
<p className="text-2xl font-bold">3.2%</p>
<p className="text-xs text-purple-400">+0.5% this week</p>
</div>
<TrendingUp className="w-8 h-8 text-purple-400" />
</div>
</Card>
<Card accentColor="orange" className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-400">Active Projects</p>
<p className="text-2xl font-bold">12</p>
<p className="text-xs text-orange-400">3 pending review</p>
</div>
<BarChart className="w-8 h-8 text-orange-400" />
</div>
</Card>
</div>
{/* Main Content Grid */}
<div className="grid grid-cols-3 gap-6">
<Card className="col-span-2 p-6">
<h3 className="font-semibold mb-4">Revenue Chart</h3>
<div className="h-48 bg-gradient-to-t from-cyan-500/10 to-transparent rounded-lg flex items-end justify-around">
{[40, 65, 45, 75, 55, 85, 70].map((height, i) => (
<div
key={i}
className="w-8 bg-cyan-500/50 rounded-t"
style={{ height: `${height}%` }}
/>
))}
</div>
</Card>
<Card className="p-6">
<h3 className="font-semibold mb-4">Recent Activity</h3>
<div className="space-y-3">
<div className="flex items-center gap-3 text-sm">
<div className="w-2 h-2 bg-green-400 rounded-full" />
<span className="text-gray-400">New user registered</span>
</div>
<div className="flex items-center gap-3 text-sm">
<div className="w-2 h-2 bg-blue-400 rounded-full" />
<span className="text-gray-400">Payment received</span>
</div>
<div className="flex items-center gap-3 text-sm">
<div className="w-2 h-2 bg-purple-400 rounded-full" />
<span className="text-gray-400">Project completed</span>
</div>
</div>
</Card>
</div>
</div>
);
};
// Settings Page Example
const SettingsPageExample = () => {
const [notifications, setNotifications] = useState(true);
const [darkMode, setDarkMode] = useState(true);
const [autoSave, setAutoSave] = useState(false);
return (
<div className="max-w-2xl mx-auto p-6 space-y-6">
<h2 className="text-2xl font-bold mb-6">Settings</h2>
{/* Profile Section */}
<Card accentColor="blue" className="p-6">
<div className="flex items-center gap-2 mb-4">
<User className="w-5 h-5 text-blue-400" />
<h3 className="text-lg font-semibold">Profile</h3>
</div>
<div className="space-y-4">
<div>
<Label htmlFor="name">Display Name</Label>
<Input id="name" defaultValue="John Doe" className="mt-1" />
</div>
<div>
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" defaultValue="john@example.com" className="mt-1" />
</div>
</div>
</Card>
{/* Preferences Section */}
<Card accentColor="purple" className="p-6">
<div className="flex items-center gap-2 mb-4">
<Palette className="w-5 h-5 text-purple-400" />
<h3 className="text-lg font-semibold">Preferences</h3>
</div>
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<Label htmlFor="dark-mode">Dark Mode</Label>
<p className="text-sm text-gray-400">Use dark theme across the application</p>
</div>
<Switch
id="dark-mode"
size="lg"
color="purple"
checked={darkMode}
onCheckedChange={setDarkMode}
/>
</div>
<div className="flex items-center justify-between">
<div>
<Label htmlFor="notifications">Notifications</Label>
<p className="text-sm text-gray-400">Receive push notifications</p>
</div>
<Switch
id="notifications"
size="lg"
color="purple"
checked={notifications}
onCheckedChange={setNotifications}
iconOn={<Bell className="w-5 h-5" />}
iconOff={<Bell className="w-5 h-5" />}
/>
</div>
<div className="flex items-center justify-between">
<div>
<Label htmlFor="auto-save">Auto Save</Label>
<p className="text-sm text-gray-400">Automatically save changes</p>
</div>
<Switch
id="auto-save"
size="lg"
color="purple"
checked={autoSave}
onCheckedChange={setAutoSave}
/>
</div>
</div>
</Card>
{/* Security Section */}
<Card accentColor="green" className="p-6">
<div className="flex items-center gap-2 mb-4">
<Lock className="w-5 h-5 text-green-400" />
<h3 className="text-lg font-semibold">Security</h3>
</div>
<div className="space-y-4">
<Button variant="outline" className="w-full justify-start">
Change Password
</Button>
<Button variant="outline" className="w-full justify-start">
Two-Factor Authentication
</Button>
<Button variant="outline" className="w-full justify-start text-red-500 hover:text-red-400">
Delete Account
</Button>
</div>
</Card>
</div>
);
};
export const PagesExample = () => {
const [activeExample, setActiveExample] = useState<'landing' | 'dashboard' | 'settings'>('landing');
const generateCode = () => {
if (activeExample === 'dashboard') {
return `// Dashboard Page with Stats Cards
import { Card } from '@/features/ui/primitives/card';
import { DollarSign, Users, TrendingUp, BarChart } from 'lucide-react';
export const Dashboard = () => {
return (
<div className="p-6 space-y-6">
{/* Stats Cards */}
<div className="grid grid-cols-4 gap-4">
<Card accentColor="green" className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-400">Revenue</p>
<p className="text-2xl font-bold">$45,231</p>
</div>
<DollarSign className="w-8 h-8 text-green-400" />
</div>
</Card>
{/* More stat cards... */}
</div>
</div>
);
};`;
} else if (activeExample === 'settings') {
return `// Settings Page with Form Sections
import { Card } from '@/features/ui/primitives/card';
import { Switch } from '@/features/ui/primitives/switch';
import { Input } from '@/features/ui/primitives/input';
export const Settings = () => {
const [darkMode, setDarkMode] = useState(true);
return (
<div className="max-w-2xl mx-auto p-6 space-y-6">
<Card accentColor="purple" className="p-6">
<h3 className="text-lg font-semibold mb-4">Preferences</h3>
<div className="flex items-center justify-between">
<Label htmlFor="dark-mode">Dark Mode</Label>
<Switch
id="dark-mode"
size="lg"
color="purple"
checked={darkMode}
onCheckedChange={setDarkMode}
/>
</div>
</Card>
</div>
);
};`;
}
return `// Landing Page with Hero Section
import { Card } from '@/features/ui/primitives/card';
import { Button } from '@/features/ui/primitives/button';
import { ArrowRight, Zap, Shield, Sparkles } from 'lucide-react';
export const LandingPage = () => {
return (
<div className="bg-gradient-to-br from-gray-900 to-purple-900/20">
{/* Hero Section */}
<section className="text-center py-12">
<h1 className="text-4xl font-bold mb-4 bg-gradient-to-r from-cyan-400 to-purple-400 bg-clip-text text-transparent">
Welcome to Archon
</h1>
<Button size="lg">
Get Started <ArrowRight className="ml-2 w-4 h-4" />
</Button>
</section>
{/* Features Grid */}
<section className="grid grid-cols-3 gap-6">
<Card accentColor="purple" className="p-6 text-center">
<Zap className="w-12 h-12 mx-auto mb-4 text-purple-400" />
<h3 className="font-semibold">Lightning Fast</h3>
</Card>
{/* More feature cards... */}
</section>
</div>
);
};`;
};
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold mb-4">Page Examples</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Complete page layouts demonstrating how to compose components into full user interfaces.
</p>
</div>
{/* Example Selector */}
<div className="flex gap-2 mb-6">
<Button
variant={activeExample === 'landing' ? 'primary' : 'outline'}
size="sm"
onClick={() => setActiveExample('landing')}
>
Landing Page
</Button>
<Button
variant={activeExample === 'dashboard' ? 'primary' : 'outline'}
size="sm"
onClick={() => setActiveExample('dashboard')}
>
Dashboard
</Button>
<Button
variant={activeExample === 'settings' ? 'primary' : 'outline'}
size="sm"
onClick={() => setActiveExample('settings')}
>
Settings
</Button>
</div>
{/* Live Example */}
<Card className="p-0 overflow-hidden">
<div className="max-h-96 overflow-auto">
{activeExample === 'landing' && <LandingPageExample />}
{activeExample === 'dashboard' && <DashboardPageExample />}
{activeExample === 'settings' && <SettingsPageExample />}
</div>
</Card>
{/* Code Example */}
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">Implementation Code</h3>
<CodeDisplay
code={generateCode()}
showLineNumbers
/>
</Card>
</div>
);
};

View File

@@ -1,369 +0,0 @@
import { useState } from "react";
import { Card } from "../../../features/ui/primitives/card";
import { Switch } from "../../../features/ui/primitives/switch";
import { Checkbox } from "../../../features/ui/primitives/checkbox";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from "../../../features/ui/primitives/select";
import { Label } from "../../../features/ui/primitives/label";
import { Input } from "../../../features/ui/primitives/input";
import { Brain, Cpu, Zap, Database, Search, FileText } from "lucide-react";
/**
* 🤖 AI CONTEXT: RAG Settings Example
*
* DESIGN PRINCIPLES:
* 1. GLASSMORPHISM - All components use true glass effect
* 2. NEON ACCENTS - Color-coded sections with glow
* 3. GROUPED LAYOUT - Related settings in glass cards
* 4. ACCESSIBILITY - Proper labels and keyboard navigation
*
* This replicates the actual RAG settings UI with:
* - Model selection dropdowns
* - Feature toggle switches
* - Checkbox options
* - Number inputs with glass styling
*/
export function RAGSettingsExample() {
const [llmProvider, setLlmProvider] = useState("openai");
const [modelChoice, setModelChoice] = useState("gpt-4");
const [embeddingModel, setEmbeddingModel] = useState("text-embedding-3-small");
const [enableRAG, setEnableRAG] = useState(true);
const [enableCache, setEnableCache] = useState(true);
const [enableStreaming, setEnableStreaming] = useState(false);
const [searchOptions, setSearchOptions] = useState({
semantic: true,
keyword: true,
hybrid: false,
});
const [maxTokens, setMaxTokens] = useState("2048");
const [temperature, setTemperature] = useState("0.7");
const [topK, setTopK] = useState("5");
return (
<div className="max-w-4xl mx-auto space-y-6 p-6">
{/* Header */}
<div className="text-center space-y-2">
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
RAG Settings Example
</h2>
<p className="text-sm text-gray-600 dark:text-gray-400">
Retrieval-Augmented Generation configuration with glassmorphic components
</p>
</div>
{/* LLM Configuration */}
<Card
glassTint="green"
glowColor="green"
transparency="medium"
className="p-6"
>
<div className="flex items-center gap-2 mb-4">
<Brain className="w-5 h-5 text-emerald-400 drop-shadow-[0_0_5px_rgba(16,185,129,0.7)]" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
LLM Configuration
</h3>
</div>
<div className="grid grid-cols-2 gap-4">
{/* Provider Selection */}
<div>
<Label htmlFor="provider" className="mb-2 block">
Provider
</Label>
<Select value={llmProvider} onValueChange={setLlmProvider}>
<SelectTrigger id="provider" color="green">
<SelectValue />
</SelectTrigger>
<SelectContent color="green">
<SelectItem value="openai" color="green">OpenAI</SelectItem>
<SelectItem value="anthropic" color="green">Anthropic</SelectItem>
<SelectItem value="google" color="green">Google</SelectItem>
<SelectItem value="ollama" color="green">Ollama (Local)</SelectItem>
</SelectContent>
</Select>
</div>
{/* Model Selection */}
<div>
<Label htmlFor="model" className="mb-2 block">
Model
</Label>
<Select value={modelChoice} onValueChange={setModelChoice}>
<SelectTrigger id="model" color="green">
<SelectValue />
</SelectTrigger>
<SelectContent color="green">
<SelectItem value="gpt-4" color="green">GPT-4</SelectItem>
<SelectItem value="gpt-4-turbo" color="green">GPT-4 Turbo</SelectItem>
<SelectItem value="gpt-3.5-turbo" color="green">GPT-3.5 Turbo</SelectItem>
<SelectItem value="claude-3" color="green">Claude 3</SelectItem>
</SelectContent>
</Select>
</div>
{/* Embedding Model */}
<div>
<Label htmlFor="embedding" className="mb-2 block">
Embedding Model
</Label>
<Select value={embeddingModel} onValueChange={setEmbeddingModel}>
<SelectTrigger id="embedding" color="green">
<SelectValue />
</SelectTrigger>
<SelectContent color="green">
<SelectItem value="text-embedding-3-small" color="green">text-embedding-3-small</SelectItem>
<SelectItem value="text-embedding-3-large" color="green">text-embedding-3-large</SelectItem>
<SelectItem value="text-embedding-ada-002" color="green">text-embedding-ada-002</SelectItem>
</SelectContent>
</Select>
</div>
{/* Max Tokens */}
<div>
<Label htmlFor="max-tokens" className="mb-2 block">
Max Tokens
</Label>
<Input
id="max-tokens"
type="number"
value={maxTokens}
onChange={(e) => setMaxTokens(e.target.value)}
className="backdrop-blur-xl bg-black/10 dark:bg-white/10 border-green-500/30 focus:border-green-500"
/>
</div>
</div>
</Card>
{/* Feature Toggles */}
<Card
glassTint="green"
glowColor="green"
transparency="medium"
className="p-6"
>
<div className="flex items-center gap-2 mb-4">
<Cpu className="w-5 h-5 text-emerald-400 drop-shadow-[0_0_5px_rgba(16,185,129,0.7)]" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
Features
</h3>
</div>
<div className="space-y-4">
<div className="flex items-center justify-between p-3 rounded-lg bg-black/5 dark:bg-white/5">
<div className="flex-1">
<Label htmlFor="rag-toggle" className="cursor-pointer">
Enable RAG
</Label>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
Use knowledge base for context enhancement
</p>
</div>
<Switch
id="rag-toggle"
size="lg"
color="green"
checked={enableRAG}
onCheckedChange={setEnableRAG}
icon={<Database className="w-5 h-5" />}
/>
</div>
<div className="flex items-center justify-between p-3 rounded-lg bg-black/5 dark:bg-white/5">
<div className="flex-1">
<Label htmlFor="cache-toggle" className="cursor-pointer">
Response Caching
</Label>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
Cache similar queries for faster responses
</p>
</div>
<Switch
id="cache-toggle"
size="lg"
color="green"
checked={enableCache}
onCheckedChange={setEnableCache}
icon={<Zap className="w-5 h-5" />}
/>
</div>
<div className="flex items-center justify-between p-3 rounded-lg bg-black/5 dark:bg-white/5">
<div className="flex-1">
<Label htmlFor="stream-toggle" className="cursor-pointer">
Stream Responses
</Label>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
Enable real-time streaming of LLM responses
</p>
</div>
<Switch
id="stream-toggle"
size="lg"
color="green"
checked={enableStreaming}
onCheckedChange={setEnableStreaming}
icon={<FileText className="w-5 h-5" />}
/>
</div>
</div>
</Card>
{/* Search Options */}
<Card
glassTint="green"
glowColor="green"
transparency="medium"
className="p-6"
>
<div className="flex items-center gap-2 mb-4">
<Search className="w-5 h-5 text-emerald-400 drop-shadow-[0_0_5px_rgba(16,185,129,0.7)]" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
Search Options
</h3>
</div>
<div className="space-y-3">
<div className="flex items-center space-x-2">
<Checkbox
id="semantic"
color="green"
checked={searchOptions.semantic}
onCheckedChange={(checked) =>
setSearchOptions(prev => ({ ...prev, semantic: checked as boolean }))
}
/>
<Label htmlFor="semantic" className="cursor-pointer">
Semantic Search
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
(Vector similarity)
</span>
</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="keyword"
color="green"
checked={searchOptions.keyword}
onCheckedChange={(checked) =>
setSearchOptions(prev => ({ ...prev, keyword: checked as boolean }))
}
/>
<Label htmlFor="keyword" className="cursor-pointer">
Keyword Search
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
(Full-text matching)
</span>
</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="hybrid"
color="green"
checked={searchOptions.hybrid}
onCheckedChange={(checked) =>
setSearchOptions(prev => ({ ...prev, hybrid: checked as boolean }))
}
/>
<Label htmlFor="hybrid" className="cursor-pointer">
Hybrid Search
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
(Combined approach)
</span>
</Label>
</div>
</div>
<div className="grid grid-cols-2 gap-4 mt-4">
<div>
<Label htmlFor="temperature" className="mb-2 block">
Temperature ({temperature})
</Label>
<input
id="temperature"
type="range"
min="0"
max="2"
step="0.1"
value={temperature}
onChange={(e) => setTemperature(e.target.value)}
className="w-full accent-emerald-500"
/>
</div>
<div>
<Label htmlFor="top-k" className="mb-2 block">
Top K Results
</Label>
<Input
id="top-k"
type="number"
value={topK}
onChange={(e) => setTopK(e.target.value)}
className="backdrop-blur-xl bg-black/10 dark:bg-white/10 border-emerald-500/30 focus:border-emerald-500"
/>
</div>
</div>
</Card>
{/* Status Summary */}
<Card
glassTint="green"
glowColor="green"
transparency="medium"
className="p-4"
>
<div className="grid grid-cols-3 gap-4 text-sm">
<div className="text-center">
<p className="text-gray-500 dark:text-gray-400">Provider</p>
<p className="font-semibold text-gray-900 dark:text-white">{llmProvider}</p>
</div>
<div className="text-center">
<p className="text-gray-500 dark:text-gray-400">Model</p>
<p className="font-semibold text-gray-900 dark:text-white">{modelChoice}</p>
</div>
<div className="text-center">
<p className="text-gray-500 dark:text-gray-400">RAG Status</p>
<p className={`font-semibold ${enableRAG ? 'text-emerald-400' : 'text-gray-500'}`}>
{enableRAG ? 'Enabled' : 'Disabled'}
</p>
</div>
</div>
</Card>
{/* Code Example */}
<div className="mt-8 p-4 rounded-lg bg-gray-900 text-gray-100 overflow-x-auto">
<pre className="text-xs">
{`// Example configuration object
const ragConfig = {
provider: "${llmProvider}",
model: "${modelChoice}",
embedding: "${embeddingModel}",
features: {
rag: ${enableRAG},
cache: ${enableCache},
streaming: ${enableStreaming}
},
search: {
semantic: ${searchOptions.semantic},
keyword: ${searchOptions.keyword},
hybrid: ${searchOptions.hybrid}
},
parameters: {
maxTokens: ${maxTokens},
temperature: ${temperature},
topK: ${topK}
}
};`}
</pre>
</div>
</div>
);
}

View File

@@ -1,137 +0,0 @@
import { Card } from '@/features/ui/primitives/card';
import { CodeDisplay } from '../shared/CodeDisplay';
export const WorkflowsExample = () => {
const generateCode = () => {
return `/**
* 🤖 AI CONTEXT: User Workflow Examples
*
* PURPOSE: Multi-step user flows using Archon components
* WHEN TO USE: Complex user journeys requiring multiple screens
* WHEN NOT TO USE: Simple single-page interactions
*
* WORKFLOW TYPES:
* - Onboarding flows with progressive disclosure
* - Multi-step forms with validation
* - Wizard-style configuration processes
* - Data import/export workflows
* - User authentication flows
*
* FLOW PRINCIPLES:
* - Clear progress indication
* - Consistent navigation patterns
* - Proper error handling and recovery
* - Accessible keyboard navigation
* - Mobile-responsive design
*/
import { useState } from 'react';
import { Card } from '@/features/ui/primitives/card';
import { Button } from '@/features/ui/primitives/button';
// Example: Multi-step Onboarding
export const OnboardingWorkflow = () => {
const [currentStep, setCurrentStep] = useState(0);
const [formData, setFormData] = useState({});
const steps = [
{ title: "Welcome", component: WelcomeStep },
{ title: "Profile", component: ProfileStep },
{ title: "Preferences", component: PreferencesStep },
{ title: "Complete", component: CompleteStep }
];
const nextStep = () => setCurrentStep(prev => Math.min(prev + 1, steps.length - 1));
const prevStep = () => setCurrentStep(prev => Math.max(prev - 1, 0));
return (
<div className="max-w-2xl mx-auto">
{/* Progress Indicator */}
<div className="mb-8">
<div className="flex items-center justify-between mb-2">
{steps.map((step, index) => (
<div
key={step.title}
className={cn(
"flex items-center justify-center w-8 h-8 rounded-full text-sm font-medium",
index <= currentStep
? "bg-cyan-500 text-white"
: "bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-400"
)}
>
{index + 1}
</div>
))}
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-cyan-500 h-2 rounded-full transition-all"
style={{ width: \`\${((currentStep + 1) / steps.length) * 100}%\` }}
/>
</div>
</div>
{/* Step Content */}
<Card glowColor="purple" className="p-8 mb-6">
<h2 className="text-2xl font-bold mb-6">{steps[currentStep].title}</h2>
<steps[currentStep].component
formData={formData}
setFormData={setFormData}
/>
</Card>
{/* Navigation */}
<div className="flex justify-between">
<Button
variant="outline"
onClick={prevStep}
disabled={currentStep === 0}
>
Previous
</Button>
<Button
onClick={nextStep}
disabled={currentStep === steps.length - 1}
>
{currentStep === steps.length - 1 ? 'Complete' : 'Next'}
</Button>
</div>
</div>
);
};`;
};
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold mb-4">Workflow Examples</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Multi-step user flows and complex interactions using Archon's design system.
</p>
</div>
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">Coming Soon</h3>
<p className="text-gray-600 dark:text-gray-400 mb-4">
This section will include interactive workflow examples such as:
</p>
<ul className="list-disc list-inside text-sm text-gray-600 dark:text-gray-400 space-y-1 mb-6">
<li>Onboarding flows with step-by-step guidance</li>
<li>Multi-step form wizards with validation</li>
<li>Data import/export workflows with progress tracking</li>
<li>User authentication flows with error handling</li>
<li>Configuration wizards with branching logic</li>
</ul>
</Card>
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">Example Workflow Pattern</h3>
<CodeDisplay
code={generateCode()}
showLineNumbers
/>
</Card>
</div>
);
};

View File

@@ -1 +1,6 @@
export { StyleGuideView } from './components/StyleGuideView';
export { StyleGuideView } from "./components/StyleGuideView";
export { PillNavigation } from "./shared/PillNavigation";
export { SideNavigation } from "./shared/SideNavigation";
export { StyleGuideTab } from "./tabs/StyleGuideTab";
export { LayoutsTab } from "./tabs/LayoutsTab";
export { ConfiguratorsTab } from "./tabs/ConfiguratorsTab";

View File

@@ -0,0 +1,297 @@
import { useState } from "react";
import { Search, ChevronDown, ChevronRight, Code, FileText } from "lucide-react";
import { Button } from "@/features/ui/primitives/button";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/features/ui/primitives/dialog";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/features/ui/primitives/tabs";
import { Input } from "@/features/ui/primitives/input";
const MOCK_DOCUMENTS = [
{
id: "1",
title: "Getting Started with React",
content:
"React is a JavaScript library for building user interfaces. It lets you compose complex UIs from small and isolated pieces of code called components. React components are JavaScript functions that return markup. Components can be as simple as a function that returns JSX, or they can have state and lifecycle methods...",
tags: ["guide", "intro", "react"],
},
{
id: "2",
title: "API Reference - useState Hook",
content:
"useState is a React Hook that lets you add a state variable to your component. Call useState at the top level of your component to declare a state variable. The convention is to name state variables like [something, setSomething] using array destructuring. useState returns an array with exactly two values: the current state and the set function that lets you update it...",
tags: ["api", "hooks", "reference"],
},
{
id: "3",
title: "Performance Optimization Guide",
content:
"Before you start optimizing, make sure you're actually measuring performance. React DevTools Profiler can help you identify components that are re-rendering unnecessarily. Common optimization techniques include: using React.memo for expensive components, using useMemo and useCallback hooks to memoize values and functions, code splitting with React.lazy and Suspense...",
tags: ["performance", "optimization", "guide"],
},
];
const MOCK_CODE = [
{
id: "1",
language: "typescript",
summary: "React functional component with useState",
code: `const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
};`,
file_path: "src/components/Counter.tsx",
},
{
id: "2",
language: "python",
summary: "FastAPI endpoint with dependency injection",
code: `@app.get("/api/items/{item_id}")
async def get_item(
item_id: str,
db: Session = Depends(get_db)
):
item = db.query(Item).filter(Item.id == item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return item`,
file_path: "src/api/routes/items.py",
},
{
id: "3",
language: "typescript",
summary: "Custom React hook for data fetching",
code: `const useData = <T>(url: string) => {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
};`,
file_path: "src/hooks/useData.ts",
},
];
export const DocumentBrowserExample = () => {
const [open, setOpen] = useState(false);
return (
<div className="space-y-4">
{/* Explanation Text */}
<p className="text-sm text-gray-600 dark:text-gray-400">
<strong>Use this pattern for:</strong> Displaying structured information in modals
(documents, logs, code, API responses). Tabs organize different data types, search filters
content, items expand/collapse for details.
</p>
{/* Button to Open Modal */}
<Button onClick={() => setOpen(true)}>Open Document Browser Example</Button>
{/* Document Browser Modal */}
<DocumentBrowserModal open={open} onOpenChange={setOpen} />
</div>
);
};
const DocumentBrowserModal = ({
open,
onOpenChange,
}: {
open: boolean;
onOpenChange: (open: boolean) => void;
}) => {
const [activeTab, setActiveTab] = useState<"documents" | "code">("documents");
const [searchQuery, setSearchQuery] = useState("");
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
const toggleExpanded = (id: string) => {
setExpandedItems((prev) => {
const next = new Set(prev);
if (next.has(id)) {
next.delete(id);
} else {
next.add(id);
}
return next;
});
};
// Filter based on search
const filteredDocuments = MOCK_DOCUMENTS.filter((doc) =>
doc.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
doc.content.toLowerCase().includes(searchQuery.toLowerCase())
);
const filteredCode = MOCK_CODE.filter((example) =>
example.summary.toLowerCase().includes(searchQuery.toLowerCase()) ||
example.code.toLowerCase().includes(searchQuery.toLowerCase())
);
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl h-[80vh] flex flex-col">
<DialogHeader>
<DialogTitle>Document Browser</DialogTitle>
<div className="flex items-center gap-2 mt-4">
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
<Input
type="text"
placeholder="Search documents and code..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10 bg-black/30 border-white/10 focus:border-cyan-500/50"
/>
</div>
</div>
</DialogHeader>
<Tabs
value={activeTab}
onValueChange={(v) => setActiveTab(v as "documents" | "code")}
className="flex-1 flex flex-col"
>
<TabsList>
<TabsTrigger value="documents" className="data-[state=active]:bg-cyan-500/20">
<FileText className="w-4 h-4 mr-2" />
Documents ({filteredDocuments.length})
</TabsTrigger>
<TabsTrigger value="code" className="data-[state=active]:bg-cyan-500/20">
<Code className="w-4 h-4 mr-2" />
Code Examples ({filteredCode.length})
</TabsTrigger>
</TabsList>
<TabsContent value="documents" className="flex-1 overflow-hidden">
<div className="h-full overflow-y-auto">
{filteredDocuments.length === 0 ? (
<div className="text-center py-8 text-gray-400">
{searchQuery ? "No documents match your search" : "No documents available"}
</div>
) : (
<div className="space-y-3 p-4">
{filteredDocuments.map((doc) => {
const isExpanded = expandedItems.has(doc.id);
const preview = doc.content.substring(0, 200);
const needsExpansion = doc.content.length > 200;
return (
<div
key={doc.id}
className="bg-black/30 rounded-lg border border-white/10 p-4 hover:border-cyan-500/30 transition-colors"
>
{doc.title && (
<h4 className="font-medium text-white/90 mb-2 flex items-center gap-2">
{needsExpansion && (
<button
type="button"
onClick={() => toggleExpanded(doc.id)}
className="text-gray-400 hover:text-white transition-colors"
>
{isExpanded ? (
<ChevronDown className="w-4 h-4" />
) : (
<ChevronRight className="w-4 h-4" />
)}
</button>
)}
{doc.title}
</h4>
)}
<div className="text-sm text-gray-300 whitespace-pre-wrap">
{isExpanded || !needsExpansion ? (
doc.content
) : (
<>
{preview}...
<button
type="button"
onClick={() => toggleExpanded(doc.id)}
className="ml-2 text-cyan-400 hover:text-cyan-300"
>
Show more
</button>
</>
)}
</div>
{doc.tags && doc.tags.length > 0 && (
<div className="flex items-center gap-2 mt-3 flex-wrap">
{doc.tags.map((tag) => (
<span key={tag} className="px-2 py-1 text-xs border border-white/20 rounded bg-black/20">
{tag}
</span>
))}
</div>
)}
</div>
);
})}
</div>
)}
</div>
</TabsContent>
<TabsContent value="code" className="flex-1 overflow-hidden">
<div className="h-full overflow-y-auto">
{filteredCode.length === 0 ? (
<div className="text-center py-8 text-gray-400">
{searchQuery ? "No code examples match your search" : "No code examples available"}
</div>
) : (
<div className="space-y-3 p-4">
{filteredCode.map((example) => (
<div
key={example.id}
className="bg-black/30 rounded-lg border border-white/10 overflow-hidden hover:border-cyan-500/30 transition-colors"
>
<div className="flex items-center justify-between p-3 border-b border-white/10 bg-black/20">
<div className="flex items-center gap-2">
<Code className="w-4 h-4 text-cyan-400" />
{example.language && (
<span className="px-2 py-1 text-xs bg-cyan-500/20 text-cyan-400 rounded">
{example.language}
</span>
)}
</div>
{example.file_path && <span className="text-xs text-gray-400">{example.file_path}</span>}
</div>
{example.summary && (
<div className="p-3 text-sm text-gray-300 border-b border-white/10">{example.summary}</div>
)}
<pre className="p-4 text-sm overflow-x-auto">
<code className="text-gray-300">{example.code}</code>
</pre>
</div>
))}
</div>
)}
</div>
</TabsContent>
</Tabs>
</DialogContent>
</Dialog>
);
};

View File

@@ -0,0 +1,305 @@
import { useState } from "react";
import { Grid, List, Asterisk, Terminal, FileCode, Globe, FileText, Calendar } from "lucide-react";
import { Button } from "@/features/ui/primitives/button";
import { Card } from "@/features/ui/primitives/card";
import { Input } from "@/features/ui/primitives/input";
import { ToggleGroup, ToggleGroupItem } from "@/features/ui/primitives/toggle-group";
import { cn } from "@/features/ui/primitives/styles";
const MOCK_KNOWLEDGE_ITEMS = [
{
id: "1",
title: "React Documentation",
type: "technical",
url: "https://react.dev",
date: "2024-01-15",
chunks: 145,
},
{
id: "2",
title: "Product Requirements",
type: "business",
url: null,
date: "2024-01-20",
chunks: 23,
},
{
id: "3",
title: "FastAPI Guide",
type: "technical",
url: "https://fastapi.tiangolo.com",
date: "2024-01-18",
chunks: 89,
},
{
id: "4",
title: "TailwindCSS Docs",
type: "technical",
url: "https://tailwindcss.com",
date: "2024-01-22",
chunks: 112,
},
{
id: "5",
title: "Marketing Strategy",
type: "business",
url: null,
date: "2024-01-10",
chunks: 15,
},
{
id: "6",
title: "TypeScript Handbook",
type: "technical",
url: "https://www.typescriptlang.org/docs",
date: "2024-01-25",
chunks: 203,
},
];
export const KnowledgeLayoutExample = () => {
const [viewMode, setViewMode] = useState<"grid" | "table">("grid");
const [typeFilter, setTypeFilter] = useState("all");
return (
<div className="space-y-4">
{/* Explanation Text */}
<p className="text-sm text-gray-600 dark:text-gray-400">
<strong>Use this layout for:</strong> Switchable views (grid/table/list), filterable data,
search interfaces. Users can toggle between dense (table) and spacious (grid) layouts.
</p>
{/* Header with Controls */}
<div className="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between">
<Input placeholder="Search knowledge base..." className="max-w-xs" />
<div className="flex gap-2 items-center">
{/* Type Filter */}
<ToggleGroup
type="single"
size="sm"
value={typeFilter}
onValueChange={(v) => v && setTypeFilter(v)}
aria-label="Filter type"
>
<ToggleGroupItem value="all" aria-label="All" title="All">
<Asterisk className="w-4 h-4" />
</ToggleGroupItem>
<ToggleGroupItem value="technical" aria-label="Technical" title="Technical">
<Terminal className="w-4 h-4" />
</ToggleGroupItem>
<ToggleGroupItem value="business" aria-label="Business" title="Business">
<FileCode className="w-4 h-4" />
</ToggleGroupItem>
</ToggleGroup>
{/* View Toggle */}
<div className="flex gap-1 p-1 bg-black/30 rounded-lg border border-white/10">
<Button
variant="ghost"
size="sm"
onClick={() => setViewMode("grid")}
className={cn("px-3", viewMode === "grid" && "bg-cyan-500/20 text-cyan-400")}
>
<Grid className="w-4 h-4" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => setViewMode("table")}
className={cn("px-3", viewMode === "table" && "bg-cyan-500/20 text-cyan-400")}
>
<List className="w-4 h-4" />
</Button>
</div>
</div>
</div>
{/* Conditional View Rendering */}
{viewMode === "grid" ? (
// Grid View - Responsive columns
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{MOCK_KNOWLEDGE_ITEMS.map((item) => (
<KnowledgeCard key={item.id} item={item} />
))}
</div>
) : (
// Table View - Overflow-x-auto wrapper
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="border-b border-white/10">
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Title
</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Type
</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Source
</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Chunks
</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Date
</th>
</tr>
</thead>
<tbody>
{MOCK_KNOWLEDGE_ITEMS.map((item) => (
<KnowledgeTableRow key={item.id} item={item} />
))}
</tbody>
</table>
</div>
)}
</div>
);
};
// Grid Card Component - matches real KnowledgeCard structure
const KnowledgeCard = ({ item }: { item: typeof MOCK_KNOWLEDGE_ITEMS[0] }) => {
const isUrl = !!item.url;
const isTechnical = item.type === "technical";
const getCardGradient = () => {
if (isTechnical) {
return isUrl
? "from-cyan-100/50 via-cyan-50/25 to-white/60 dark:from-cyan-900/20 dark:via-cyan-900/10 dark:to-black/30"
: "from-purple-100/50 via-purple-50/25 to-white/60 dark:from-purple-900/20 dark:via-purple-900/10 dark:to-black/30";
}
return isUrl
? "from-blue-100/50 via-blue-50/25 to-white/60 dark:from-blue-900/20 dark:via-blue-900/10 dark:to-black/30"
: "from-pink-100/50 via-pink-50/25 to-white/60 dark:from-pink-900/20 dark:via-pink-900/10 dark:to-black/30";
};
const getBorderColor = () => {
if (isTechnical) {
return isUrl
? "border-cyan-600/30 dark:border-cyan-500/30"
: "border-purple-600/30 dark:border-purple-500/30";
}
return isUrl
? "border-blue-600/30 dark:border-blue-500/30"
: "border-pink-600/30 dark:border-pink-500/30";
};
const getAccent = () => {
if (isTechnical) {
return isUrl
? { bar: "bg-cyan-500", smear: "from-cyan-500/25" }
: { bar: "bg-purple-500", smear: "from-purple-500/25" };
}
return isUrl
? { bar: "bg-blue-500", smear: "from-blue-500/25" }
: { bar: "bg-pink-500", smear: "from-pink-500/25" };
};
const accent = getAccent();
return (
<div
className={cn(
"relative overflow-hidden transition-all duration-300 rounded-xl cursor-pointer",
"bg-gradient-to-b backdrop-blur-md border",
getCardGradient(),
getBorderColor(),
"hover:shadow-[0_0_30px_rgba(6,182,212,0.2)]",
"min-h-[240px] flex flex-col",
)}
>
{/* Top accent glow */}
<div className="pointer-events-none absolute inset-x-0 top-0">
<div className={cn("mx-1 mt-0.5 h-[2px] rounded-full", accent.bar)} />
<div className={cn("-mt-1 h-8 w-full bg-gradient-to-b to-transparent blur-md", accent.smear)} />
</div>
{/* Content */}
<div className="relative p-4">
<div className="flex items-start justify-between gap-2 mb-3">
<div className="flex items-center gap-2">
<div
className={cn(
"flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium",
isUrl
? "bg-cyan-100 text-cyan-700 dark:bg-cyan-500/10 dark:text-cyan-400"
: "bg-purple-100 text-purple-700 dark:bg-purple-500/10 dark:text-purple-400",
)}
>
{isUrl ? <Globe className="w-3.5 h-3.5" /> : <FileText className="w-3.5 h-3.5" />}
<span>{isUrl ? "Web Page" : "Document"}</span>
</div>
<span
className={cn(
"px-2 py-1 text-xs rounded-md font-medium",
item.type === "technical"
? "bg-cyan-500/10 text-cyan-600 dark:text-cyan-400"
: "bg-purple-500/10 text-purple-600 dark:text-purple-400",
)}
>
{item.type}
</span>
</div>
</div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2 line-clamp-2">{item.title}</h4>
{item.url && (
<div className="text-xs text-gray-600 dark:text-gray-400 truncate">{item.url}</div>
)}
</div>
{/* Footer with stats */}
<div className="mt-auto px-4 py-3 bg-gray-100/50 dark:bg-black/30 border-t border-gray-200/50 dark:border-white/10">
<div className="flex items-center justify-between text-xs">
<div className="flex items-center gap-1 text-gray-600 dark:text-gray-400">
<Calendar className="w-3 h-3" />
<span>{item.date}</span>
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-1 px-2 py-1 rounded-md bg-orange-500/10 text-orange-600 dark:text-orange-400">
<FileText className="w-3.5 h-3.5" />
<span>{item.chunks}</span>
</div>
</div>
</div>
</div>
</div>
);
};
// Table Row Component
const KnowledgeTableRow = ({ item }: { item: typeof MOCK_KNOWLEDGE_ITEMS[0] }) => {
return (
<tr className="border-b border-white/5 hover:bg-white/5 dark:hover:bg-white/5 transition-colors cursor-pointer">
<td className="py-3 px-4">
<div className="flex items-center gap-2">
{item.url ? (
<Globe className="w-4 h-4 text-cyan-500 flex-shrink-0" />
) : (
<FileText className="w-4 h-4 text-purple-500 flex-shrink-0" />
)}
<span className="text-sm text-gray-900 dark:text-white">{item.title}</span>
</div>
</td>
<td className="py-3 px-4">
<span
className={cn(
"px-2 py-0.5 text-xs rounded border",
item.type === "technical"
? "bg-cyan-500/10 text-cyan-600 dark:text-cyan-400 border-cyan-500/30"
: "bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/30",
)}
>
{item.type}
</span>
</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400 max-w-xs truncate">
{item.url || "Uploaded Document"}
</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">{item.chunks}</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">{item.date}</td>
</tr>
);
};

View File

@@ -0,0 +1,150 @@
import { ChevronRight } from "lucide-react";
import { Card } from "@/features/ui/primitives/card";
export const NavigationExplanation = () => {
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Navigation Patterns
</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Archon uses a layered navigation approach with distinct patterns for different navigation levels.
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Main Navigation */}
<Card className="p-6">
<div className="flex items-start gap-3 mb-4">
<div className="w-10 h-10 rounded-lg bg-cyan-500/20 flex items-center justify-center">
<span className="text-cyan-400 font-bold">1</span>
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Main Navigation
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
Fixed left sidebar (72px wide) with icon-based navigation. Always visible across all pages.
</p>
</div>
</div>
<div className="bg-black/20 rounded-lg p-4 border border-white/10">
<code className="text-xs text-gray-300">
<div>position: fixed</div>
<div>left: 24px (left-6)</div>
<div>width: 72px</div>
<div>Icon-based with tooltips</div>
</code>
</div>
</Card>
{/* Content Area */}
<Card className="p-6">
<div className="flex items-start gap-3 mb-4">
<div className="w-10 h-10 rounded-lg bg-purple-500/20 flex items-center justify-center">
<span className="text-purple-400 font-bold">2</span>
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Content Area
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
All page content lives in the content area with left padding to accommodate main nav.
</p>
</div>
</div>
<div className="bg-black/20 rounded-lg p-4 border border-white/10">
<code className="text-xs text-gray-300">
<div>padding-left: 100px (pl-[100px])</div>
<div>Gives space for 72px nav + 28px gap</div>
<div>All layouts exist INSIDE this area</div>
</code>
</div>
</Card>
{/* Page Navigation */}
<Card className="p-6">
<div className="flex items-start gap-3 mb-4">
<div className="w-10 h-10 rounded-lg bg-blue-500/20 flex items-center justify-center">
<span className="text-blue-400 font-bold">3</span>
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Page Navigation
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
Top-level tabs or pills for page sections. Uses Radix Tabs primitive with glassmorphism.
</p>
</div>
</div>
<div className="bg-black/20 rounded-lg p-4 border border-white/10">
<code className="text-xs text-gray-300">
<div>{'<Tabs>'} with TabsList</div>
<div>Example: Docs/Tasks tabs</div>
<div>Color variants: cyan, blue, purple, orange</div>
</code>
</div>
</Card>
{/* View Controls */}
<Card className="p-6">
<div className="flex items-start gap-3 mb-4">
<div className="w-10 h-10 rounded-lg bg-green-500/20 flex items-center justify-center">
<span className="text-green-400 font-bold">4</span>
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
View Controls
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
Toggle buttons for switching between view modes (grid/table/list).
</p>
</div>
</div>
<div className="bg-black/20 rounded-lg p-4 border border-white/10">
<code className="text-xs text-gray-300">
<div>Icon buttons with active state</div>
<div>Grid, List, Table icons</div>
<div>Glassmorphism background</div>
</code>
</div>
</Card>
</div>
{/* Visual Hierarchy */}
<Card className="p-6">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
Navigation Hierarchy
</h3>
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
<span className="px-3 py-1 bg-cyan-500/20 text-cyan-400 rounded border border-cyan-400/30">
Main Nav
</span>
<ChevronRight className="w-4 h-4" />
<span className="px-3 py-1 bg-purple-500/20 text-purple-400 rounded border border-purple-400/30">
Content Area
</span>
<ChevronRight className="w-4 h-4" />
<span className="px-3 py-1 bg-blue-500/20 text-blue-400 rounded border border-blue-400/30">
Page Tabs
</span>
<ChevronRight className="w-4 h-4" />
<span className="px-3 py-1 bg-green-500/20 text-green-400 rounded border border-green-400/30">
View Controls
</span>
</div>
</Card>
{/* Key Point */}
<div className="bg-orange-500/10 border border-orange-400/30 rounded-lg p-4">
<p className="text-sm text-gray-700 dark:text-gray-300">
<strong className="text-orange-600 dark:text-orange-400">Important:</strong>{" "}
Main navigation is OUTSIDE the content area (fixed position). All page layouts
(including sidebar variants) exist INSIDE the content area and use relative positioning
to avoid overlapping with the main nav.
</p>
</div>
</div>
);
};

View File

@@ -0,0 +1,703 @@
import { useState } from "react";
import { LayoutGrid, List, ListTodo, Activity, CheckCircle2, FileText, Search, Table as TableIcon, Tag, User, Trash2, Pin, Copy } from "lucide-react";
import { motion } from "framer-motion";
import { Button } from "@/features/ui/primitives/button";
import { Card } from "@/features/ui/primitives/card";
import { Input } from "@/features/ui/primitives/input";
import { PillNavigation, type PillNavigationItem } from "../shared/PillNavigation";
import { cn } from "@/features/ui/primitives/styles";
const MOCK_PROJECTS = [
{
id: "1",
title: "Design System Refactor",
pinned: true,
taskCounts: { todo: 5, doing: 2, review: 1, done: 12 },
},
{
id: "2",
title: "API Integration Layer",
pinned: false,
taskCounts: { todo: 3, doing: 1, review: 0, done: 8 },
},
{
id: "3",
title: "Mobile App Development",
pinned: false,
taskCounts: { todo: 8, doing: 0, review: 0, done: 0 },
},
{
id: "4",
title: "Documentation Updates",
pinned: false,
taskCounts: { todo: 2, doing: 1, review: 2, done: 15 },
},
];
const MOCK_TASKS = [
{ id: "1", title: "Update color palette", status: "todo" as const, assignee: "User", feature: "Design", priority: "high" as const },
{ id: "2", title: "Refactor button component", status: "todo" as const, assignee: "AI", feature: "Components", priority: "medium" as const },
{ id: "3", title: "Implement glassmorphism effects", status: "doing" as const, assignee: "User", feature: "Styling", priority: "high" as const },
{ id: "4", title: "Add documentation", status: "review" as const, assignee: "User", feature: "Docs", priority: "low" as const },
{ id: "5", title: "Setup project structure", status: "done" as const, assignee: "AI", feature: "Setup", priority: "high" as const },
{ id: "6", title: "Create initial components", status: "done" as const, assignee: "User", feature: "Components", priority: "medium" as const },
];
const MOCK_DOCUMENTS = [
{ id: "1", title: "Project Overview", type: "spec" as const },
{ id: "2", title: "API Documentation", type: "api" as const },
{ id: "3", title: "Design Notes", type: "note" as const },
];
export const ProjectsLayoutExample = () => {
const [selectedId, setSelectedId] = useState("1");
const [activeTab, setActiveTab] = useState<"docs" | "tasks">("tasks");
const [viewMode, setViewMode] = useState<"board" | "table">("board");
const [selectedDoc, setSelectedDoc] = useState(MOCK_DOCUMENTS[0]);
const [layoutMode, setLayoutMode] = useState<"horizontal" | "sidebar">("horizontal");
const [sidebarExpanded, setSidebarExpanded] = useState(true);
const selectedProject = MOCK_PROJECTS.find((p) => p.id === selectedId);
const tabItems: PillNavigationItem[] = [
{ id: "docs", label: "Docs", icon: <FileText className="w-4 h-4" /> },
{ id: "tasks", label: "Tasks", icon: <ListTodo className="w-4 h-4" /> },
];
return (
<div className="space-y-6">
{/* Layout Mode Toggle */}
<div className="flex justify-end">
<div className="flex gap-1 p-1 bg-black/30 rounded-lg border border-white/10">
<Button
variant="ghost"
size="sm"
onClick={() => setLayoutMode("horizontal")}
className={cn("px-3", layoutMode === "horizontal" && "bg-purple-500/20 text-purple-400")}
>
<LayoutGrid className="w-4 h-4" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => setLayoutMode("sidebar")}
className={cn("px-3", layoutMode === "sidebar" && "bg-purple-500/20 text-purple-400")}
>
<List className="w-4 h-4" />
</Button>
</div>
</div>
{layoutMode === "horizontal" ? (
<>
{/* Horizontal Project Cards */}
<div className="overflow-x-auto overflow-y-visible py-8 px-8">
<div className="flex gap-4 min-w-max">
{MOCK_PROJECTS.map((project) => (
<ProjectCardExample
key={project.id}
project={project}
isSelected={selectedId === project.id}
onSelect={() => setSelectedId(project.id)}
/>
))}
</div>
</div>
{/* Orange Pill Navigation centered, View Toggle on right */}
<div className="flex items-center justify-between">
<div className="flex-1" />
<PillNavigation
items={tabItems}
activeSection={activeTab}
onSectionClick={(id) => setActiveTab(id as typeof activeTab)}
colorVariant="orange"
size="small"
showIcons={true}
showText={true}
hasSubmenus={false}
/>
<div className="flex-1 flex justify-end">
{/* View Toggle aligned right */}
{activeTab === "tasks" && (
<div className="flex gap-1 p-1 bg-black/30 rounded-lg border border-white/10">
<Button
variant="ghost"
size="sm"
onClick={() => setViewMode("board")}
className={cn("px-3", viewMode === "board" && "bg-cyan-500/20 text-cyan-400")}
>
<LayoutGrid className="w-4 h-4" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => setViewMode("table")}
className={cn("px-3", viewMode === "table" && "bg-cyan-500/20 text-cyan-400")}
>
<TableIcon className="w-4 h-4" />
</Button>
</div>
)}
</div>
</div>
{/* Tab Content - NO extra margin */}
<div>
{activeTab === "tasks" && (viewMode === "board" ? <KanbanBoardView /> : <TaskTableView />)}
{activeTab === "docs" && <EmbeddedDocumentBrowser doc={selectedDoc} onDocSelect={setSelectedDoc} />}
</div>
</>
) : (
/* Sidebar Mode */
<div className="flex gap-6">
{/* Left Sidebar - Collapsible Project List */}
{sidebarExpanded && (
<div className="w-64 flex-shrink-0 space-y-2">
<div className="flex items-center justify-between mb-2">
<h3 className="text-sm font-semibold text-gray-800 dark:text-white">Projects</h3>
<Button variant="ghost" size="sm" onClick={() => setSidebarExpanded(false)} className="px-2">
<List className="w-3 h-3" />
</Button>
</div>
<div className="space-y-2">
{MOCK_PROJECTS.map((project) => (
<SidebarProjectCard
key={project.id}
project={project}
isSelected={selectedId === project.id}
onSelect={() => setSelectedId(project.id)}
/>
))}
</div>
</div>
)}
{/* Main Content Area */}
<div className="flex-1">
{/* Header with project name, tabs, and view toggle inline */}
<div className="flex items-center gap-4 mb-4">
{!sidebarExpanded && (
<Button
variant="ghost"
size="sm"
onClick={() => setSidebarExpanded(true)}
className="px-2 flex-shrink-0"
>
<List className="w-3 h-3 mr-1" />
<span className="text-sm font-medium">{selectedProject?.title}</span>
</Button>
)}
{/* Orange Pill Navigation - ALWAYS CENTERED */}
<div className="flex-1 flex justify-center">
<PillNavigation
items={tabItems}
activeSection={activeTab}
onSectionClick={(id) => setActiveTab(id as typeof activeTab)}
colorVariant="orange"
size="small"
showIcons={true}
showText={true}
hasSubmenus={false}
/>
</div>
{/* View Toggle - INLINE to right of pill nav */}
{activeTab === "tasks" && (
<div className="flex gap-1 p-1 bg-black/30 rounded-lg border border-white/10 flex-shrink-0">
<Button
variant="ghost"
size="sm"
onClick={() => setViewMode("board")}
className={cn("px-3", viewMode === "board" && "bg-cyan-500/20 text-cyan-400")}
>
<LayoutGrid className="w-4 h-4" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => setViewMode("table")}
className={cn("px-3", viewMode === "table" && "bg-cyan-500/20 text-cyan-400")}
>
<TableIcon className="w-4 h-4" />
</Button>
</div>
)}
</div>
{/* Tab Content - Full Width, NO extra spacing */}
<div>
{activeTab === "tasks" && (viewMode === "board" ? <KanbanBoardView /> : <TaskTableView />)}
{activeTab === "docs" && <EmbeddedDocumentBrowser doc={selectedDoc} onDocSelect={setSelectedDoc} />}
</div>
</div>
</div>
)}
</div>
);
};
// Sidebar Project Card with task counts
const SidebarProjectCard = ({
project,
isSelected,
onSelect,
}: {
project: typeof MOCK_PROJECTS[0];
isSelected: boolean;
onSelect: () => void;
}) => {
return (
<button
type="button"
onClick={onSelect}
className={cn(
"w-full text-left px-3 py-2 rounded-lg transition-all duration-200",
isSelected
? "bg-purple-500/10 dark:bg-purple-400/10 text-purple-700 dark:text-purple-300 border-l-2 border-purple-500"
: "text-gray-600 dark:text-gray-400 hover:bg-white/5 dark:hover:bg-white/5 border-l-2 border-transparent",
)}
>
<div className="font-medium text-sm line-clamp-1 mb-1">{project.title}</div>
{project.pinned && <div className="text-xs text-purple-600 dark:text-purple-400 mb-1">Pinned</div>}
{/* Task counts */}
<div className="flex gap-2 text-xs">
<span className="text-pink-600 dark:text-pink-400">{project.taskCounts.todo} todo</span>
<span className="text-blue-600 dark:text-blue-400">
{project.taskCounts.doing + project.taskCounts.review} doing
</span>
<span className="text-green-600 dark:text-green-400">{project.taskCounts.done} done</span>
</div>
</button>
);
};
// Project Card matching REAL ProjectCard exactly
const ProjectCardExample = ({
project,
isSelected,
onSelect,
}: {
project: typeof MOCK_PROJECTS[0];
isSelected: boolean;
onSelect: () => void;
}) => {
return (
<motion.div
onClick={onSelect}
className={cn(
"relative rounded-xl backdrop-blur-md w-72 min-h-[180px] cursor-pointer overflow-visible group flex flex-col",
"transition-all duration-300",
project.pinned
? "bg-gradient-to-b from-purple-100/80 via-purple-50/30 to-purple-100/50 dark:from-purple-900/30 dark:via-purple-900/20 dark:to-purple-900/10"
: isSelected
? "bg-gradient-to-b from-white/70 via-purple-50/20 to-white/50 dark:from-white/5 dark:via-purple-900/5 dark:to-black/20"
: "bg-gradient-to-b from-white/80 to-white/60 dark:from-white/10 dark:to-black/30",
"border",
project.pinned
? "border-purple-500/80 dark:border-purple-500/80 shadow-[0_0_15px_rgba(168,85,247,0.3)]"
: isSelected
? "border-purple-400/60 dark:border-purple-500/60"
: "border-gray-200 dark:border-zinc-800/50",
isSelected
? "shadow-[0_0_15px_rgba(168,85,247,0.4),0_0_10px_rgba(147,51,234,0.3)] dark:shadow-[0_0_20px_rgba(168,85,247,0.5),0_0_15px_rgba(147,51,234,0.4)]"
: "shadow-[0_10px_30px_-15px_rgba(0,0,0,0.1)] dark:shadow-[0_10px_30px_-15px_rgba(0,0,0,0.7)]",
isSelected ? "scale-[1.02]" : "hover:scale-[1.01]",
)}
>
{/* Aurora glow effect for selected card */}
{isSelected && (
<div className="absolute inset-0 rounded-xl overflow-hidden opacity-30 dark:opacity-40 pointer-events-none">
<div className="absolute -inset-[100px] bg-[radial-gradient(circle,rgba(168,85,247,0.8)_0%,rgba(147,51,234,0.6)_40%,transparent_70%)] blur-3xl animate-[pulse_8s_ease-in-out_infinite]" />
</div>
)}
{/* Main content */}
<div className="flex-1 p-4 pb-2">
{/* Title */}
<div className="flex flex-col items-center justify-center mb-4 min-h-[48px]">
<h3
className={cn(
"font-medium text-center leading-tight line-clamp-2 transition-all duration-300",
isSelected
? "text-gray-900 dark:text-white drop-shadow-[0_0_8px_rgba(255,255,255,0.8)]"
: project.pinned
? "text-purple-700 dark:text-purple-300"
: "text-gray-500 dark:text-gray-400",
)}
>
{project.title}
</h3>
</div>
{/* Task count pills */}
<div className="flex items-stretch gap-2 w-full">
{/* Todo pill */}
<div className="relative flex-1">
<div className={cn("absolute inset-0 bg-pink-600 rounded-full blur-md", isSelected ? "opacity-30 dark:opacity-75" : "opacity-0")} />
<div
className={cn(
"relative flex items-center h-12 backdrop-blur-sm rounded-full border shadow-sm transition-all duration-300",
isSelected
? "bg-white/70 dark:bg-zinc-900/90 border-pink-300 dark:border-pink-500/50 dark:shadow-[0_0_10px_rgba(236,72,153,0.5)]"
: "bg-white/30 dark:bg-zinc-900/30 border-gray-300/50 dark:border-gray-700/50",
)}
>
<div className="flex flex-col items-center justify-center px-2 min-w-[40px]">
<ListTodo className={cn("w-4 h-4", isSelected ? "text-pink-600 dark:text-pink-400" : "text-gray-500 dark:text-gray-600")} />
<span className={cn("text-[8px] font-medium", isSelected ? "text-pink-600 dark:text-pink-400" : "text-gray-500 dark:text-gray-600")}>
ToDo
</span>
</div>
<div className="flex-1 flex items-center justify-center border-l border-pink-300 dark:border-pink-500/30">
<span className={cn("text-lg font-bold", isSelected ? "text-pink-600 dark:text-pink-400" : "text-gray-500 dark:text-gray-600")}>
{project.taskCounts.todo}
</span>
</div>
</div>
</div>
{/* Doing pill */}
<div className="relative flex-1">
<div className={cn("absolute inset-0 bg-blue-600 rounded-full blur-md", isSelected ? "opacity-30 dark:opacity-75" : "opacity-0")} />
<div
className={cn(
"relative flex items-center h-12 backdrop-blur-sm rounded-full border shadow-sm transition-all duration-300",
isSelected
? "bg-white/70 dark:bg-zinc-900/90 border-blue-300 dark:border-blue-500/50 dark:shadow-[0_0_10px_rgba(59,130,246,0.5)]"
: "bg-white/30 dark:bg-zinc-900/30 border-gray-300/50 dark:border-gray-700/50",
)}
>
<div className="flex flex-col items-center justify-center px-2 min-w-[40px]">
<Activity className={cn("w-4 h-4", isSelected ? "text-blue-600 dark:text-blue-400" : "text-gray-500 dark:text-gray-600")} />
<span className={cn("text-[8px] font-medium", isSelected ? "text-blue-600 dark:text-blue-400" : "text-gray-500 dark:text-gray-600")}>
Doing
</span>
</div>
<div className="flex-1 flex items-center justify-center border-l border-blue-300 dark:border-blue-500/30">
<span className={cn("text-lg font-bold", isSelected ? "text-blue-600 dark:text-blue-400" : "text-gray-500 dark:text-gray-600")}>
{project.taskCounts.doing + project.taskCounts.review}
</span>
</div>
</div>
</div>
{/* Done pill */}
<div className="relative flex-1">
<div className={cn("absolute inset-0 bg-green-600 rounded-full blur-md", isSelected ? "opacity-30 dark:opacity-75" : "opacity-0")} />
<div
className={cn(
"relative flex items-center h-12 backdrop-blur-sm rounded-full border shadow-sm transition-all duration-300",
isSelected
? "bg-white/70 dark:bg-zinc-900/90 border-green-300 dark:border-green-500/50 dark:shadow-[0_0_10px_rgba(34,197,94,0.5)]"
: "bg-white/30 dark:bg-zinc-900/30 border-gray-300/50 dark:border-gray-700/50",
)}
>
<div className="flex flex-col items-center justify-center px-2 min-w-[40px]">
<CheckCircle2 className={cn("w-4 h-4", isSelected ? "text-green-600 dark:text-green-400" : "text-gray-500 dark:text-gray-600")} />
<span className={cn("text-[8px] font-medium", isSelected ? "text-green-600 dark:text-green-400" : "text-gray-500 dark:text-gray-600")}>
Done
</span>
</div>
<div className="flex-1 flex items-center justify-center border-l border-green-300 dark:border-green-500/30">
<span className={cn("text-lg font-bold", isSelected ? "text-green-600 dark:text-green-400" : "text-gray-500 dark:text-gray-600")}>
{project.taskCounts.done}
</span>
</div>
</div>
</div>
</div>
</div>
{/* Bottom bar with pin badge and action icons */}
<div className="flex items-center justify-between px-3 py-2 mt-auto border-t border-gray-200/30 dark:border-gray-700/20">
{project.pinned ? (
<div className="px-2 py-0.5 bg-purple-500 text-white text-[10px] font-bold rounded-full shadow-lg shadow-purple-500/30">
DEFAULT
</div>
) : (
<div />
)}
{/* Action icons */}
<div className="flex items-center gap-2">
<button
type="button"
onClick={(e) => e.stopPropagation()}
className="p-1.5 rounded-md hover:bg-red-500/10 text-gray-500 hover:text-red-500 transition-colors"
>
<Trash2 className="w-3.5 h-3.5" />
</button>
<button
type="button"
onClick={(e) => e.stopPropagation()}
className={cn(
"p-1.5 rounded-md transition-colors",
project.pinned
? "bg-purple-500/10 text-purple-500"
: "hover:bg-purple-500/10 text-gray-500 hover:text-purple-500",
)}
>
<Pin className="w-3.5 h-3.5" />
</button>
<button
type="button"
onClick={(e) => e.stopPropagation()}
className="p-1.5 rounded-md hover:bg-cyan-500/10 text-gray-500 hover:text-cyan-500 transition-colors"
>
<Copy className="w-3.5 h-3.5" />
</button>
</div>
</div>
</motion.div>
);
};
// Kanban Board - NO BACKGROUNDS
const KanbanBoardView = () => {
const columns = [
{ status: "todo" as const, title: "Todo", color: "text-pink-500", glow: "bg-pink-500" },
{ status: "doing" as const, title: "Doing", color: "text-blue-500", glow: "bg-blue-500" },
{ status: "review" as const, title: "Review", color: "text-purple-500", glow: "bg-purple-500" },
{ status: "done" as const, title: "Done", color: "text-green-500", glow: "bg-green-500" },
];
const getTasksByStatus = (status: typeof columns[0]["status"]) => {
return MOCK_TASKS.filter((t) => t.status === status);
};
return (
<div className="grid grid-cols-4 gap-2 min-h-[500px]">
{columns.map(({ status, title, color, glow }) => (
<div key={status} className="flex flex-col">
{/* Column Header - transparent */}
<div className="text-center py-3 relative">
<h3 className={cn("font-mono text-sm font-medium", color)}>{title}</h3>
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">{getTasksByStatus(status).length}</div>
<div className={cn("absolute bottom-0 left-[15%] right-[15%] w-[70%] mx-auto h-[1px]", glow, "shadow-md")} />
</div>
{/* Tasks */}
<div className="flex-1 p-2 space-y-2">
{getTasksByStatus(status).map((task) => (
<TaskCardExample key={task.id} task={task} />
))}
</div>
</div>
))}
</div>
);
};
// Task Card matching REAL TaskCard exactly
const TaskCardExample = ({ task }: { task: typeof MOCK_TASKS[0] }) => {
const getPriorityColor = (priority: string) => {
if (priority === "high") return { color: "bg-red-500", glow: "shadow-[0_0_10px_rgba(239,68,68,0.3)]" };
if (priority === "medium") return { color: "bg-yellow-500", glow: "shadow-[0_0_10px_rgba(234,179,8,0.3)]" };
return { color: "bg-green-500", glow: "shadow-[0_0_10px_rgba(34,197,94,0.3)]" };
};
const priorityStyle = getPriorityColor(task.priority);
return (
<div className="w-full min-h-[140px] group cursor-move relative">
<div className="bg-gradient-to-b from-white/80 to-white/60 dark:from-white/10 dark:to-black/30 border border-gray-200 dark:border-gray-700 rounded-lg backdrop-blur-md transition-all duration-200 group-hover:border-cyan-400/70 dark:group-hover:border-cyan-500/50 group-hover:shadow-[0_0_15px_rgba(34,211,238,0.4)] dark:group-hover:shadow-[0_0_15px_rgba(34,211,238,0.6)] w-full min-h-[140px] h-full relative">
{/* Priority indicator glow on left */}
<div className={cn("absolute left-0 top-0 bottom-0 w-[3px] rounded-l-lg opacity-80 group-hover:w-[4px] group-hover:opacity-100 transition-all duration-300", priorityStyle.color, priorityStyle.glow)} />
{/* Content */}
<div className="flex flex-col h-full p-3">
{/* Header with feature tag */}
<div className="flex items-center gap-2 mb-2 pl-1.5">
{task.feature && (
<div className="px-2 py-1 rounded-md text-xs font-medium flex items-center gap-1 backdrop-blur-md bg-cyan-500/10 text-cyan-600 dark:text-cyan-400 shadow-sm">
<Tag className="w-3 h-3" />
{task.feature}
</div>
)}
</div>
{/* Title */}
<h4 className="text-xs font-medium text-gray-900 dark:text-white mb-2 pl-1.5 line-clamp-2">
{task.title}
</h4>
{/* Spacer */}
<div className="flex-1" />
{/* Footer with assignee and priority */}
<div className="flex items-center justify-between mt-auto pt-2 pl-1.5 pr-3">
{/* Assignee card-style */}
<div className="flex items-center gap-1.5 px-2 py-1 rounded-md bg-white/50 dark:bg-black/30 border border-gray-200 dark:border-gray-700 text-xs">
<User className="w-3 h-3 text-gray-500 dark:text-gray-400" />
<span className="text-gray-700 dark:text-gray-300">{task.assignee}</span>
</div>
{/* Priority dot */}
<div className={cn("w-2 h-2 rounded-full", priorityStyle.color)} />
</div>
</div>
</div>
</div>
);
};
// Task Table View - matching real TableView
const TaskTableView = () => {
return (
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="bg-gradient-to-r from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 border-b-2 border-gray-200 dark:border-gray-700">
<th className="w-1" />
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700 dark:text-gray-300">Title</th>
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700 dark:text-gray-300 w-32">Status</th>
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700 dark:text-gray-300 w-40">Feature</th>
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700 dark:text-gray-300 w-36">Assignee</th>
</tr>
</thead>
<tbody>
{MOCK_TASKS.map((task, index) => {
const getPriorityColor = (priority: string) => {
if (priority === "high") return { color: "bg-red-500", glow: "shadow-[0_0_10px_rgba(239,68,68,0.3)]" };
if (priority === "medium") return { color: "bg-yellow-500", glow: "shadow-[0_0_10px_rgba(234,179,8,0.3)]" };
return { color: "bg-green-500", glow: "shadow-[0_0_10px_rgba(34,197,94,0.3)]" };
};
const priorityStyle = getPriorityColor(task.priority);
return (
<tr
key={task.id}
className={cn(
"group transition-all duration-200",
index % 2 === 0 ? "bg-white/50 dark:bg-black/50" : "bg-gray-50/80 dark:bg-gray-900/30",
"hover:bg-gradient-to-r hover:from-cyan-50/70 hover:to-purple-50/70 dark:hover:from-cyan-900/20 dark:hover:to-purple-900/20",
"border-b border-gray-200 dark:border-gray-800",
)}
>
{/* Priority indicator */}
<td className="w-1 p-0">
<div className={cn("w-1 h-full", priorityStyle.color, priorityStyle.glow)} />
</td>
{/* Title */}
<td className="px-4 py-2">
<span className="font-medium text-sm text-gray-900 dark:text-white">{task.title}</span>
</td>
{/* Status */}
<td className="px-4 py-2 w-32">
<span
className={cn(
"px-2 py-1 text-xs rounded-md font-medium inline-block",
task.status === "todo" && "bg-pink-500/10 text-pink-600 dark:text-pink-400",
task.status === "doing" && "bg-blue-500/10 text-blue-600 dark:text-blue-400",
task.status === "review" && "bg-purple-500/10 text-purple-600 dark:text-purple-400",
task.status === "done" && "bg-green-500/10 text-green-600 dark:text-green-400",
)}
>
{task.status}
</span>
</td>
{/* Feature */}
<td className="px-4 py-2 w-40">
<div className="flex items-center gap-1">
{task.feature && (
<>
<Tag className="w-3 h-3 text-gray-500 dark:text-gray-400" />
<span className="text-sm text-gray-700 dark:text-gray-300">{task.feature}</span>
</>
)}
</div>
</td>
{/* Assignee - card style like real component */}
<td className="px-4 py-2 w-36">
<div className="inline-flex items-center gap-1.5 px-2 py-1 rounded-md bg-white/70 dark:bg-black/40 border border-gray-300 dark:border-gray-600 backdrop-blur-sm">
<User className="w-3 h-3 text-gray-500 dark:text-gray-400" />
<span className="text-xs text-gray-700 dark:text-gray-300">{task.assignee}</span>
</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
};
// Embedded Document Browser
const EmbeddedDocumentBrowser = ({
doc,
onDocSelect,
}: {
doc: typeof MOCK_DOCUMENTS[0];
onDocSelect: (doc: typeof MOCK_DOCUMENTS[0]) => void;
}) => {
const [searchQuery, setSearchQuery] = useState("");
const filteredDocs = MOCK_DOCUMENTS.filter((d) => d.title.toLowerCase().includes(searchQuery.toLowerCase()));
return (
<div className="flex h-[600px] gap-6">
{/* Left Sidebar */}
<div className="w-64 flex flex-col space-y-4">
<div className="flex items-center gap-2">
<FileText className="w-5 h-5 text-gray-700 dark:text-gray-300" />
<h3 className="text-lg font-semibold text-gray-800 dark:text-white">Documents</h3>
</div>
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
<Input
type="text"
placeholder="Search..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9"
/>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400">{MOCK_DOCUMENTS.length} documents</p>
<div className="flex-1 space-y-1">
{filteredDocs.map((d) => {
const isActive = d.id === doc.id;
return (
<button
key={d.id}
type="button"
onClick={() => onDocSelect(d)}
className={cn(
"w-full text-left px-3 py-2 rounded-lg transition-all duration-200",
isActive
? "bg-cyan-500/10 dark:bg-cyan-400/10 text-cyan-700 dark:text-cyan-300 border-l-2 border-cyan-500"
: "text-gray-600 dark:text-gray-400 hover:bg-white/5 dark:hover:bg-white/5 border-l-2 border-transparent",
)}
>
<div className="font-medium text-sm line-clamp-1">{d.title}</div>
<div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{d.type}</div>
</button>
);
})}
</div>
</div>
{/* Right Content */}
<div className="flex-1 overflow-y-auto">
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">{doc.title}</h2>
<div className="text-gray-600 dark:text-gray-400 space-y-4">
<p>
Document type:{" "}
<span className="px-2 py-1 text-xs bg-blue-500/10 text-blue-600 dark:text-blue-400 rounded">{doc.type}</span>
</p>
<p>This area shows the full document content with rich formatting and embedded media.</p>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,162 @@
import { Settings, Palette, Key, Database, Code, Globe } from "lucide-react";
import { CollapsibleSettingsCard } from "@/components/ui/CollapsibleSettingsCard";
import { Switch } from "@/features/ui/primitives/switch";
import { Input } from "@/features/ui/primitives/input";
import { Label } from "@/features/ui/primitives/label";
export const SettingsLayoutExample = () => {
return (
<div className="space-y-4">
{/* Explanation Text */}
<p className="text-sm text-gray-600 dark:text-gray-400">
<strong>Use this layout for:</strong> Settings pages, dashboard widgets, grouped
configuration sections. Two-column responsive grid with collapsible cards.
</p>
{/* Bento Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<CollapsibleSettingsCard
title="Feature Toggles"
icon={Palette}
accentColor="purple"
defaultExpanded={true}
>
<div className="space-y-4">
<div className="flex items-center justify-between">
<Label htmlFor="projects-toggle">Enable Projects</Label>
<Switch id="projects-toggle" defaultChecked />
</div>
<div className="flex items-center justify-between">
<Label htmlFor="style-toggle">Style Guide</Label>
<Switch id="style-toggle" defaultChecked />
</div>
<div className="flex items-center justify-between">
<Label htmlFor="dark-mode">Dark Mode</Label>
<Switch id="dark-mode" defaultChecked />
</div>
</div>
</CollapsibleSettingsCard>
<CollapsibleSettingsCard title="API Keys" icon={Key} accentColor="cyan" defaultExpanded={true}>
<div className="space-y-4">
<div>
<Label htmlFor="openai-key">OpenAI API Key</Label>
<Input
id="openai-key"
type="password"
placeholder="sk-..."
className="mt-1"
defaultValue="sk-example-key-hidden"
/>
</div>
<div>
<Label htmlFor="anthropic-key">Anthropic API Key</Label>
<Input
id="anthropic-key"
type="password"
placeholder="sk-ant-..."
className="mt-1"
defaultValue="sk-ant-example-key"
/>
</div>
</div>
</CollapsibleSettingsCard>
<CollapsibleSettingsCard
title="Database Settings"
icon={Database}
accentColor="blue"
defaultExpanded={false}
>
<div className="space-y-4">
<div>
<Label htmlFor="db-url">Database URL</Label>
<Input
id="db-url"
placeholder="postgresql://..."
className="mt-1"
defaultValue="postgresql://localhost:5432/archon"
/>
</div>
<div className="flex items-center justify-between">
<Label htmlFor="auto-backup">Auto Backup</Label>
<Switch id="auto-backup" />
</div>
</div>
</CollapsibleSettingsCard>
<CollapsibleSettingsCard
title="Code Extraction"
icon={Code}
accentColor="green"
defaultExpanded={false}
>
<div className="space-y-4">
<div className="flex items-center justify-between">
<Label htmlFor="extract-code">Extract Code Examples</Label>
<Switch id="extract-code" defaultChecked />
</div>
<div>
<Label htmlFor="max-examples">Max Examples per Source</Label>
<Input
id="max-examples"
type="number"
placeholder="50"
className="mt-1"
defaultValue="50"
/>
</div>
</div>
</CollapsibleSettingsCard>
<CollapsibleSettingsCard
title="RAG Configuration"
icon={Settings}
accentColor="orange"
defaultExpanded={true}
>
<div className="space-y-4">
<div>
<Label htmlFor="match-count">Match Count</Label>
<Input
id="match-count"
type="number"
placeholder="5"
className="mt-1"
defaultValue="5"
/>
</div>
<div className="flex items-center justify-between">
<Label htmlFor="rerank">Enable Reranking</Label>
<Switch id="rerank" defaultChecked />
</div>
</div>
</CollapsibleSettingsCard>
<CollapsibleSettingsCard
title="Crawling Settings"
icon={Globe}
accentColor="pink"
defaultExpanded={false}
>
<div className="space-y-4">
<div>
<Label htmlFor="max-depth">Max Crawl Depth</Label>
<Input
id="max-depth"
type="number"
placeholder="3"
className="mt-1"
defaultValue="3"
/>
</div>
<div className="flex items-center justify-between">
<Label htmlFor="follow-links">Follow External Links</Label>
<Switch id="follow-links" />
</div>
</div>
</CollapsibleSettingsCard>
</div>
</div>
);
};

View File

@@ -1,861 +0,0 @@
import { useState } from 'react';
import { Card } from '@/features/ui/primitives/card';
import { Button } from '@/features/ui/primitives/button';
import { CodeDisplay } from '../shared/CodeDisplay';
import { cn, glassmorphism } from '@/features/ui/primitives/styles';
import {
CheckCircle,
XCircle,
AlertTriangle,
Info,
X,
Loader2,
AlertCircle,
HelpCircle
} from 'lucide-react';
interface FeedbackPattern {
id: string;
name: string;
description: string;
usage: string;
component: React.ComponentType;
}
// Alert Component
const AlertsDemo = () => {
const alerts = [
{
type: 'success',
icon: <CheckCircle className="w-5 h-5" />,
title: 'Success',
message: 'Your project has been created successfully.',
bgColor: 'bg-green-50 dark:bg-green-900/20',
borderColor: 'border-green-200 dark:border-green-800',
textColor: 'text-green-800 dark:text-green-200',
iconColor: 'text-green-600 dark:text-green-400'
},
{
type: 'error',
icon: <XCircle className="w-5 h-5" />,
title: 'Error',
message: 'There was an error processing your request. Please try again.',
bgColor: 'bg-red-50 dark:bg-red-900/20',
borderColor: 'border-red-200 dark:border-red-800',
textColor: 'text-red-800 dark:text-red-200',
iconColor: 'text-red-600 dark:text-red-400'
},
{
type: 'warning',
icon: <AlertTriangle className="w-5 h-5" />,
title: 'Warning',
message: 'This action cannot be undone. Please proceed with caution.',
bgColor: 'bg-orange-50 dark:bg-orange-900/20',
borderColor: 'border-orange-200 dark:border-orange-800',
textColor: 'text-orange-800 dark:text-orange-200',
iconColor: 'text-orange-600 dark:text-orange-400'
},
{
type: 'info',
icon: <Info className="w-5 h-5" />,
title: 'Information',
message: 'New features have been added to your dashboard.',
bgColor: 'bg-blue-50 dark:bg-blue-900/20',
borderColor: 'border-blue-200 dark:border-blue-800',
textColor: 'text-blue-800 dark:text-blue-200',
iconColor: 'text-blue-600 dark:text-blue-400'
}
];
return (
<div className="space-y-4">
{alerts.map((alert) => (
<div
key={alert.type}
className={cn(
'p-4 rounded-lg border backdrop-blur-sm',
alert.bgColor,
alert.borderColor
)}
>
<div className="flex items-start gap-3">
<div className={alert.iconColor}>
{alert.icon}
</div>
<div className="flex-1 min-w-0">
<h4 className={cn('font-medium text-sm', alert.textColor)}>
{alert.title}
</h4>
<p className={cn('text-sm mt-1', alert.textColor)}>
{alert.message}
</p>
</div>
<Button variant="ghost" size="sm" className={cn('p-1', alert.textColor)}>
<X className="w-4 h-4" />
</Button>
</div>
</div>
))}
</div>
);
};
// Loading States Demo
const LoadingStatesDemo = () => {
const loadingStates = [
{
name: 'Spinner',
component: (
<div className="flex items-center justify-center p-8">
<Loader2 className="w-8 h-8 animate-spin text-cyan-500" />
</div>
)
},
{
name: 'Spinner with Text',
component: (
<div className="flex items-center justify-center gap-3 p-8">
<Loader2 className="w-5 h-5 animate-spin text-cyan-500" />
<span className="text-sm text-gray-600 dark:text-gray-400">Loading...</span>
</div>
)
},
{
name: 'Progress Bar',
component: (
<div className="p-8 space-y-3">
<div className="flex justify-between text-sm">
<span>Uploading files...</span>
<span>67%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div className="bg-cyan-500 h-2 rounded-full transition-all duration-300" style={{ width: '67%' }} />
</div>
</div>
)
},
{
name: 'Skeleton Loading',
component: (
<div className="p-8 space-y-4">
<div className="animate-pulse">
<div className="h-4 bg-gray-300 dark:bg-gray-700 rounded w-3/4 mb-3" />
<div className="h-4 bg-gray-300 dark:bg-gray-700 rounded w-1/2 mb-3" />
<div className="h-4 bg-gray-300 dark:bg-gray-700 rounded w-5/6" />
</div>
</div>
)
},
{
name: 'Pulsing Card',
component: (
<div className="p-8">
<Card className="animate-pulse opacity-60">
<div className="h-20 bg-gray-300 dark:bg-gray-700 rounded" />
</Card>
</div>
)
}
];
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{loadingStates.map((state) => (
<Card key={state.name} className="text-center">
<h4 className="font-medium text-sm mb-2 p-4 pb-0">{state.name}</h4>
{state.component}
</Card>
))}
</div>
);
};
// Toast Notifications Demo
const ToastDemo = () => {
const [toasts, setToasts] = useState<Array<{
id: number;
type: string;
title: string;
message: string;
}>>([]);
const addToast = (type: string) => {
const toastData = {
success: { title: 'Success!', message: 'Action completed successfully.' },
error: { title: 'Error!', message: 'Something went wrong.' },
warning: { title: 'Warning!', message: 'Please review your action.' },
info: { title: 'Info', message: 'Here\'s some useful information.' }
};
const newToast = {
id: Date.now(),
type,
...toastData[type as keyof typeof toastData]
};
setToasts(prev => [...prev, newToast]);
// Auto-remove after 3 seconds
setTimeout(() => {
setToasts(prev => prev.filter(t => t.id !== newToast.id));
}, 3000);
};
const removeToast = (id: number) => {
setToasts(prev => prev.filter(t => t.id !== id));
};
const getToastStyles = (type: string) => {
const styles = {
success: {
bg: glassmorphism.background.card,
border: 'border-green-500',
glow: glassmorphism.shadow.glow.green,
icon: <CheckCircle className="w-5 h-5 text-green-500" />
},
error: {
bg: glassmorphism.background.card,
border: 'border-red-500',
glow: glassmorphism.shadow.glow.red,
icon: <XCircle className="w-5 h-5 text-red-500" />
},
warning: {
bg: glassmorphism.background.card,
border: 'border-orange-500',
glow: glassmorphism.shadow.glow.orange,
icon: <AlertTriangle className="w-5 h-5 text-orange-500" />
},
info: {
bg: glassmorphism.background.card,
border: 'border-blue-500',
glow: glassmorphism.shadow.glow.blue,
icon: <Info className="w-5 h-5 text-blue-500" />
}
};
return styles[type as keyof typeof styles];
};
return (
<div>
{/* Controls */}
<div className="flex gap-2 mb-6">
<Button onClick={() => addToast('success')} size="sm" variant="outline">
Success Toast
</Button>
<Button onClick={() => addToast('error')} size="sm" variant="outline">
Error Toast
</Button>
<Button onClick={() => addToast('warning')} size="sm" variant="outline">
Warning Toast
</Button>
<Button onClick={() => addToast('info')} size="sm" variant="outline">
Info Toast
</Button>
</div>
{/* Toast Container */}
<div className="fixed top-4 right-4 z-50 space-y-2 max-w-sm">
{toasts.map((toast) => {
const styles = getToastStyles(toast.type);
return (
<div
key={toast.id}
className={cn(
'p-4 rounded-lg border backdrop-blur-md animate-in slide-in-from-right',
styles.bg,
styles.border,
styles.glow
)}
>
<div className="flex items-start gap-3">
{styles.icon}
<div className="flex-1 min-w-0">
<h4 className="font-medium text-sm">{toast.title}</h4>
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
{toast.message}
</p>
</div>
<Button
variant="ghost"
size="sm"
className="p-1"
onClick={() => removeToast(toast.id)}
>
<X className="w-4 h-4" />
</Button>
</div>
</div>
);
})}
</div>
{/* Static Example */}
<Card className="p-4">
<h4 className="font-medium mb-3">Static Toast Example</h4>
<div
className={cn(
'p-4 rounded-lg border backdrop-blur-md max-w-sm',
glassmorphism.background.card,
'border-green-500',
glassmorphism.shadow.glow.green
)}
>
<div className="flex items-start gap-3">
<CheckCircle className="w-5 h-5 text-green-500" />
<div className="flex-1 min-w-0">
<h4 className="font-medium text-sm">Project Created</h4>
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
Your new project has been created successfully.
</p>
</div>
<Button variant="ghost" size="sm" className="p-1">
<X className="w-4 h-4" />
</Button>
</div>
</div>
</Card>
</div>
);
};
// Empty States Demo
const EmptyStatesDemo = () => {
const emptyStates = [
{
name: 'No Data',
icon: <HelpCircle className="w-12 h-12 mx-auto mb-4 text-gray-400" />,
title: 'No projects found',
description: 'Get started by creating your first project.',
action: <Button size="sm">Create Project</Button>
},
{
name: 'No Search Results',
icon: <AlertCircle className="w-12 h-12 mx-auto mb-4 text-gray-400" />,
title: 'No results found',
description: 'Try adjusting your search criteria or filters.',
action: <Button size="sm" variant="outline">Clear Filters</Button>
},
{
name: 'Coming Soon',
icon: <Info className="w-12 h-12 mx-auto mb-4 text-cyan-500" />,
title: 'Feature coming soon',
description: 'This feature is currently under development.',
action: null
}
];
return (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{emptyStates.map((state) => (
<Card key={state.name} className="text-center p-8">
<h4 className="font-medium text-xs mb-4 text-gray-500 uppercase">
{state.name}
</h4>
{state.icon}
<h3 className="font-semibold text-lg mb-2">{state.title}</h3>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
{state.description}
</p>
{state.action}
</Card>
))}
</div>
);
};
const FEEDBACK_PATTERNS: FeedbackPattern[] = [
{
id: 'alerts',
name: 'Alerts & Messages',
description: 'Contextual feedback messages with different severity levels',
usage: 'Form validation, system notifications, user feedback',
component: AlertsDemo
},
{
id: 'loading',
name: 'Loading States',
description: 'Visual indicators for loading and processing states',
usage: 'Data fetching, file uploads, long-running operations',
component: LoadingStatesDemo
},
{
id: 'toasts',
name: 'Toast Notifications',
description: 'Temporary notifications that appear and disappear automatically',
usage: 'Action confirmations, real-time updates, background processes',
component: ToastDemo
},
{
id: 'empty',
name: 'Empty States',
description: 'Helpful messaging when no content is available',
usage: 'Empty lists, no search results, feature placeholders',
component: EmptyStatesDemo
}
];
const generateCode = (patternId: string) => {
const codeExamples = {
alerts: `import { Card } from '@/features/ui/primitives/card';
import { CheckCircle, XCircle, AlertTriangle, Info, X } from 'lucide-react';
/**
* 🤖 AI CONTEXT: Alert Pattern
*
* PURPOSE: Contextual feedback with appropriate visual treatment
* WHEN TO USE: Form validation, system notifications, important messages
* WHEN NOT TO USE: Temporary messages (use toasts), blocking dialogs (use modals)
*
* SEVERITY LEVELS:
* - Success: Green - Positive outcomes, completions
* - Error: Red - Critical errors, validation failures
* - Warning: Orange - Cautions, potential issues
* - Info: Blue - Neutral information, tips
*
* ACCESSIBILITY:
* - Use semantic colors consistently
* - Include icons for visual clarity
* - Provide clear, actionable text
* - Support dismissal with keyboard
*/
interface AlertProps {
type: 'success' | 'error' | 'warning' | 'info';
title: string;
message: string;
onDismiss?: () => void;
}
export const Alert = ({ type, title, message, onDismiss }: AlertProps) => {
const config = {
success: {
icon: <CheckCircle className="w-5 h-5" />,
bgColor: 'bg-green-50 dark:bg-green-900/20',
borderColor: 'border-green-200 dark:border-green-800',
textColor: 'text-green-800 dark:text-green-200',
iconColor: 'text-green-600 dark:text-green-400'
},
error: {
icon: <XCircle className="w-5 h-5" />,
bgColor: 'bg-red-50 dark:bg-red-900/20',
borderColor: 'border-red-200 dark:border-red-800',
textColor: 'text-red-800 dark:text-red-200',
iconColor: 'text-red-600 dark:text-red-400'
},
warning: {
icon: <AlertTriangle className="w-5 h-5" />,
bgColor: 'bg-orange-50 dark:bg-orange-900/20',
borderColor: 'border-orange-200 dark:border-orange-800',
textColor: 'text-orange-800 dark:text-orange-200',
iconColor: 'text-orange-600 dark:text-orange-400'
},
info: {
icon: <Info className="w-5 h-5" />,
bgColor: 'bg-blue-50 dark:bg-blue-900/20',
borderColor: 'border-blue-200 dark:border-blue-800',
textColor: 'text-blue-800 dark:text-blue-200',
iconColor: 'text-blue-600 dark:text-blue-400'
}
};
const styles = config[type];
return (
<div className={cn(
'p-4 rounded-lg border backdrop-blur-sm',
styles.bgColor,
styles.borderColor
)}>
<div className="flex items-start gap-3">
<div className={styles.iconColor}>
{styles.icon}
</div>
<div className="flex-1 min-w-0">
<h4 className={cn('font-medium text-sm', styles.textColor)}>
{title}
</h4>
<p className={cn('text-sm mt-1', styles.textColor)}>
{message}
</p>
</div>
{onDismiss && (
<button
onClick={onDismiss}
className={cn('p-1 hover:opacity-70', styles.textColor)}
>
<X className="w-4 h-4" />
</button>
)}
</div>
</div>
);
};`,
loading: `import { Loader2 } from 'lucide-react';
import { Card } from '@/features/ui/primitives/card';
/**
* 🤖 AI CONTEXT: Loading States Pattern
*
* PURPOSE: Visual feedback during async operations
* WHEN TO USE: Data fetching, file uploads, processing operations
* WHEN NOT TO USE: Instant operations, already completed actions
*
* LOADING TYPES:
* - Spinner: Quick operations (< 5 seconds)
* - Progress: Trackable operations with known duration
* - Skeleton: Content loading with known structure
* - Pulse: Unknown duration, maintaining layout
*
* UX GUIDELINES:
* - Show immediately for operations > 500ms
* - Provide progress feedback when possible
* - Maintain layout during loading states
* - Include descriptive text for clarity
*/
// Spinner Loading
export const SpinnerLoader = ({ text }: { text?: string }) => (
<div className="flex items-center justify-center gap-3 p-8">
<Loader2 className="w-5 h-5 animate-spin text-cyan-500" />
{text && (
<span className="text-sm text-gray-600 dark:text-gray-400">
{text}
</span>
)}
</div>
);
// Progress Loading
export const ProgressLoader = ({
progress,
text
}: {
progress: number;
text?: string;
}) => (
<div className="p-4 space-y-3">
{text && (
<div className="flex justify-between text-sm">
<span>{text}</span>
<span>{progress}%</span>
</div>
)}
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-cyan-500 h-2 rounded-full transition-all duration-300"
style={{ width: \`\${progress}%\` }}
/>
</div>
</div>
);
// Skeleton Loading
export const SkeletonLoader = () => (
<div className="animate-pulse space-y-4">
<div className="h-4 bg-gray-300 dark:bg-gray-700 rounded w-3/4" />
<div className="h-4 bg-gray-300 dark:bg-gray-700 rounded w-1/2" />
<div className="h-4 bg-gray-300 dark:bg-gray-700 rounded w-5/6" />
</div>
);
// Card Loading
export const CardLoader = () => (
<Card className="animate-pulse opacity-60">
<div className="h-20 bg-gray-300 dark:bg-gray-700 rounded" />
</Card>
);`,
toasts: `import { useState, useEffect } from 'react';
import { Card } from '@/features/ui/primitives/card';
import { glassmorphism } from '@/features/ui/primitives/styles';
import { CheckCircle, XCircle, AlertTriangle, Info, X } from 'lucide-react';
/**
* 🤖 AI CONTEXT: Toast Notifications Pattern
*
* PURPOSE: Temporary, non-blocking feedback messages
* WHEN TO USE: Action confirmations, background updates, quick feedback
* WHEN NOT TO USE: Critical errors (use alerts), complex messages (use modals)
*
* TOAST CHARACTERISTICS:
* - Auto-dismiss after 3-5 seconds
* - Non-blocking, can be dismissed manually
* - Stack vertically in corner of screen
* - Use glassmorphism for modern feel
*
* POSITIONING:
* - Top-right: Most common, non-intrusive
* - Top-center: Important announcements
* - Bottom-right: Mobile-friendly alternative
*/
interface Toast {
id: string;
type: 'success' | 'error' | 'warning' | 'info';
title: string;
message: string;
duration?: number;
}
export const useToast = () => {
const [toasts, setToasts] = useState<Toast[]>([]);
const addToast = (toast: Omit<Toast, 'id'>) => {
const id = Date.now().toString();
const newToast = { ...toast, id };
setToasts(prev => [...prev, newToast]);
// Auto-remove
setTimeout(() => {
removeToast(id);
}, toast.duration || 4000);
return id;
};
const removeToast = (id: string) => {
setToasts(prev => prev.filter(t => t.id !== id));
};
return { toasts, addToast, removeToast };
};
export const ToastContainer = ({
toasts,
onRemove
}: {
toasts: Toast[];
onRemove: (id: string) => void;
}) => {
const getToastStyles = (type: string) => {
const styles = {
success: {
border: 'border-green-500',
glow: glassmorphism.shadow.glow.green,
icon: <CheckCircle className="w-5 h-5 text-green-500" />
},
error: {
border: 'border-red-500',
glow: glassmorphism.shadow.glow.red,
icon: <XCircle className="w-5 h-5 text-red-500" />
},
warning: {
border: 'border-orange-500',
glow: glassmorphism.shadow.glow.orange,
icon: <AlertTriangle className="w-5 h-5 text-orange-500" />
},
info: {
border: 'border-blue-500',
glow: glassmorphism.shadow.glow.blue,
icon: <Info className="w-5 h-5 text-blue-500" />
}
};
return styles[type as keyof typeof styles];
};
return (
<div className="fixed top-4 right-4 z-50 space-y-2 max-w-sm">
{toasts.map((toast) => {
const styles = getToastStyles(toast.type);
return (
<div
key={toast.id}
className={cn(
'p-4 rounded-lg border backdrop-blur-md',
'animate-in slide-in-from-right duration-300',
glassmorphism.background.card,
styles.border,
styles.glow
)}
>
<div className="flex items-start gap-3">
{styles.icon}
<div className="flex-1 min-w-0">
<h4 className="font-medium text-sm">{toast.title}</h4>
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
{toast.message}
</p>
</div>
<button
onClick={() => onRemove(toast.id)}
className="p-1 hover:opacity-70"
>
<X className="w-4 h-4" />
</button>
</div>
</div>
);
})}
</div>
);
};`,
empty: `import { Card } from '@/features/ui/primitives/card';
import { Button } from '@/features/ui/primitives/button';
import { HelpCircle, AlertCircle, Info } from 'lucide-react';
/**
* 🤖 AI CONTEXT: Empty States Pattern
*
* PURPOSE: Helpful guidance when no content is available
* WHEN TO USE: Empty lists, no search results, disabled features
* WHEN NOT TO USE: Loading states, error conditions, temporary states
*
* EMPTY STATE TYPES:
* - No Data: First-time use, empty collections
* - No Results: Search/filter yielded nothing
* - Feature Disabled: Functionality not available
* - Coming Soon: Planned but not implemented
*
* CONTENT GUIDELINES:
* - Clear, descriptive title
* - Helpful explanation or next steps
* - Primary action when applicable
* - Appropriate icon for context
*/
interface EmptyStateProps {
icon: React.ReactNode;
title: string;
description: string;
action?: React.ReactNode;
className?: string;
}
export const EmptyState = ({
icon,
title,
description,
action,
className
}: EmptyStateProps) => (
<Card className={cn('text-center p-12', className)}>
<div className="mx-auto mb-4">
{icon}
</div>
<h3 className="font-semibold text-lg mb-2">{title}</h3>
<p className="text-gray-600 dark:text-gray-400 mb-6 max-w-md mx-auto">
{description}
</p>
{action}
</Card>
);
// Predefined empty states
export const NoDataState = ({
onAction
}: {
onAction?: () => void;
}) => (
<EmptyState
icon={<HelpCircle className="w-16 h-16 text-gray-400" />}
title="No projects found"
description="Get started by creating your first project. You can organize your work and collaborate with your team."
action={
onAction && (
<Button onClick={onAction}>
Create Your First Project
</Button>
)
}
/>
);
export const NoSearchResultsState = ({
onClearFilters
}: {
onClearFilters?: () => void;
}) => (
<EmptyState
icon={<AlertCircle className="w-16 h-16 text-gray-400" />}
title="No results found"
description="We couldn't find any projects matching your search criteria. Try adjusting your filters or search terms."
action={
onClearFilters && (
<Button variant="outline" onClick={onClearFilters}>
Clear All Filters
</Button>
)
}
/>
);
export const ComingSoonState = ({ feature }: { feature: string }) => (
<EmptyState
icon={<Info className="w-16 h-16 text-cyan-500" />}
title={\`\${feature} coming soon\`}
description="This feature is currently under development. We'll notify you when it becomes available."
/>
);`
};
return codeExamples[patternId as keyof typeof codeExamples] || '';
};
export const FeedbackPattern = () => {
const [selectedPattern, setSelectedPattern] = useState<string>('alerts');
const currentPattern = FEEDBACK_PATTERNS.find(p => p.id === selectedPattern);
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold mb-4">Feedback Patterns</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
User feedback patterns including alerts, loading states, notifications, and empty states.
</p>
</div>
{/* Pattern Selector */}
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">Select Feedback Pattern</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{FEEDBACK_PATTERNS.map((pattern) => (
<Card
key={pattern.id}
className={cn(
"p-4 cursor-pointer transition-all duration-200",
selectedPattern === pattern.id
? "border-cyan-500 shadow-[0_0_10px_rgba(34,211,238,0.3)]"
: "hover:shadow-lg"
)}
onClick={() => setSelectedPattern(pattern.id)}
>
<h4 className="font-medium mb-2">{pattern.name}</h4>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-2">
{pattern.description}
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
<strong>Use for:</strong> {pattern.usage}
</p>
</Card>
))}
</div>
</Card>
{/* Live Preview */}
{currentPattern && (
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">
{currentPattern.name} - Examples
</h3>
<currentPattern.component />
</Card>
)}
{/* Generated Code */}
{currentPattern && (
<Card className="p-6 max-w-none">
<h3 className="text-lg font-semibold mb-4">Generated Code</h3>
<CodeDisplay
code={generateCode(selectedPattern)}
showLineNumbers
/>
</Card>
)}
</div>
);
};

View File

@@ -1,358 +0,0 @@
import { useState } from 'react';
import { Card } from '@/features/ui/primitives/card';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/features/ui/primitives/select';
import { CodeDisplay } from '../shared/CodeDisplay';
import { cn } from '@/features/ui/primitives/styles';
import { BarChart, FileText, Users, Calendar, Grid, Table, Kanban } from 'lucide-react';
// Layout types that float over the grid
const LAYOUT_TYPES = [
{
name: 'Dashboard',
description: 'Cards arranged in responsive grid layout',
component: 'DashboardLayout'
},
{
name: 'Kanban Board',
description: 'Draggable columns with task cards',
component: 'KanbanLayout'
},
{
name: 'Data Table',
description: 'Structured data with sorting and actions',
component: 'TableLayout'
},
{
name: 'Card Grid',
description: 'Uniform cards in responsive grid',
component: 'CardGridLayout'
}
];
export const LayoutsPattern = () => {
const [selectedLayout, setSelectedLayout] = useState('Dashboard');
const generateCode = () => {
switch (selectedLayout) {
case 'Dashboard':
return `// Dashboard Layout - Cards over grid
<div className="p-6 space-y-6">
{/* Stats Row */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{statsCards.map((card) => (
<Card key={card.id} className="p-4">
<h3 className="text-sm text-gray-600">{card.title}</h3>
<p className="text-2xl font-bold">{card.value}</p>
</Card>
))}
</div>
{/* Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<Card className="lg:col-span-2 p-6">
{/* Main content */}
</Card>
<Card className="p-6">
{/* Sidebar content */}
</Card>
</div>
</div>`;
case 'Kanban Board':
return `// Kanban Layout - Columns over grid
<div className="p-6 overflow-x-auto">
<div className="flex gap-4 min-w-max">
{columns.map((column) => (
<Card key={column.id} className="w-72 p-4">
<h3 className="font-semibold mb-4">{column.title}</h3>
<div className="space-y-3">
{column.tasks.map((task) => (
<Card key={task.id} className="p-3 cursor-pointer hover:shadow-lg">
<h4 className="font-medium text-sm">{task.title}</h4>
<p className="text-xs text-gray-500 mt-1">{task.description}</p>
</Card>
))}
</div>
</Card>
))}
</div>
</div>`;
case 'Data Table':
return `// Table Layout - Structured data over grid
<div className="p-6 space-y-4">
<div className="flex justify-between items-center">
<h1 className="text-2xl font-bold">Data Table</h1>
<Button>Add Item</Button>
</div>
<Card className="overflow-hidden">
<table className="w-full">
<thead className="bg-gray-50 dark:bg-gray-800/50">
<tr>
{columns.map((column) => (
<th key={column.key} className="px-4 py-3 text-left text-xs font-medium">
{column.label}
</th>
))}
</tr>
</thead>
<tbody>
{data.map((row) => (
<tr key={row.id} className="hover:bg-gray-50 dark:hover:bg-gray-800/50">
{columns.map((column) => (
<td key={column.key} className="px-4 py-3 text-sm">
{row[column.key]}
</td>
))}
</tr>
))}
</tbody>
</table>
</Card>
</div>`;
case 'Card Grid':
return `// Card Grid Layout - Uniform cards over grid
<div className="p-6 space-y-6">
<div className="flex justify-between items-center">
<h1 className="text-2xl font-bold">Card Grid</h1>
<Button>Add Card</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{cards.map((card) => (
<Card key={card.id} className="p-4 hover:shadow-lg transition-shadow">
<h3 className="font-semibold mb-2">{card.title}</h3>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-3">
{card.description}
</p>
<div className="flex justify-between items-center">
<span className="text-xs text-gray-500">{card.meta}</span>
<Button size="sm" variant="outline">Action</Button>
</div>
</Card>
))}
</div>
</div>`;
default:
return '';
}
};
const renderLayoutDemo = () => {
switch (selectedLayout) {
case 'Dashboard':
return (
<div className="space-y-4">
{/* Stats Cards */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
{[
{ title: 'Projects', value: '12', icon: <FileText className="w-4 h-4" /> },
{ title: 'Tasks', value: '38', icon: <BarChart className="w-4 h-4" /> },
{ title: 'Team', value: '8', icon: <Users className="w-4 h-4" /> },
{ title: 'Events', value: '24', icon: <Calendar className="w-4 h-4" /> }
].map((stat, i) => (
<Card key={i} className="p-3 text-center">
<div className="flex items-center justify-center mb-2 text-cyan-500">
{stat.icon}
</div>
<p className="text-lg font-bold">{stat.value}</p>
<p className="text-xs text-gray-500">{stat.title}</p>
</Card>
))}
</div>
{/* Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
<Card className="lg:col-span-2 p-4">
<h3 className="font-semibold mb-3">Main Content</h3>
<div className="space-y-2">
{[1, 2, 3].map(i => (
<div key={i} className="h-8 bg-gray-100 dark:bg-gray-800 rounded"></div>
))}
</div>
</Card>
<Card className="p-4">
<h3 className="font-semibold mb-3">Sidebar</h3>
<div className="space-y-2">
{[1, 2].map(i => (
<div key={i} className="h-6 bg-gray-100 dark:bg-gray-800 rounded"></div>
))}
</div>
</Card>
</div>
</div>
);
case 'Kanban Board':
return (
<div className="flex gap-4 overflow-x-auto pb-4">
{['To Do', 'In Progress', 'Done'].map((column, i) => (
<Card key={column} className="w-48 p-4 flex-shrink-0">
<h3 className="font-semibold mb-3 text-sm">{column}</h3>
<div className="space-y-2">
{[1, 2].map(j => (
<Card key={j} className="p-2 cursor-pointer hover:shadow-md">
<p className="text-xs font-medium">Task {i + 1}.{j}</p>
<p className="text-xs text-gray-500 mt-1">Description</p>
</Card>
))}
</div>
</Card>
))}
</div>
);
case 'Data Table':
return (
<Card className="overflow-hidden">
<table className="w-full text-xs">
<thead className="bg-gray-50 dark:bg-gray-800/50">
<tr>
{['Name', 'Status', 'Priority', 'Progress'].map(header => (
<th key={header} className="px-3 py-2 text-left font-medium">
{header}
</th>
))}
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
{[
{ name: 'Project A', status: 'Active', priority: 'High', progress: '75%' },
{ name: 'Project B', status: 'Pending', priority: 'Medium', progress: '25%' },
{ name: 'Project C', status: 'Done', priority: 'Low', progress: '100%' }
].map((row, i) => (
<tr key={i} className="hover:bg-gray-50 dark:hover:bg-gray-800/50">
<td className="px-3 py-2 font-medium">{row.name}</td>
<td className="px-3 py-2">{row.status}</td>
<td className="px-3 py-2">{row.priority}</td>
<td className="px-3 py-2">{row.progress}</td>
</tr>
))}
</tbody>
</table>
</Card>
);
case 'Card Grid':
return (
<div className="grid grid-cols-2 lg:grid-cols-3 gap-3">
{[1, 2, 3, 4, 5, 6].map(i => (
<Card key={i} className="p-3 hover:shadow-lg transition-shadow">
<h3 className="font-semibold text-sm mb-2">Card {i}</h3>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-2">
Description text for card item {i}
</p>
<div className="flex justify-between items-center">
<span className="text-xs text-gray-500">Meta info</span>
<button className="text-xs text-cyan-500 hover:text-cyan-600">Action</button>
</div>
</Card>
))}
</div>
);
default:
return null;
}
};
return (
<div className="space-y-8">
{/* Header */}
<div className="text-center">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">Layout System</h2>
<p className="text-gray-600 dark:text-gray-400 text-lg">
Floating layout patterns over grid backgrounds
</p>
</div>
{/* Layout Explorer - Above the Fold */}
<Card className="p-8">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Left: Layout Selector */}
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">Layout Type</label>
<Select value={selectedLayout} onValueChange={setSelectedLayout}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{LAYOUT_TYPES.map((layout) => (
<SelectItem key={layout.name} value={layout.name}>
{layout.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* Current Layout Info */}
<div className="p-3 bg-gray-50 dark:bg-gray-800/50 rounded-lg">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">
{selectedLayout}
</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
{LAYOUT_TYPES.find(l => l.name === selectedLayout)?.description}
</p>
</div>
{/* Layout Options */}
<div className="space-y-2">
<h4 className="text-sm font-medium text-gray-900 dark:text-white">Available Layouts</h4>
{LAYOUT_TYPES.map((layout) => (
<div
key={layout.name}
className={cn(
"p-2 rounded cursor-pointer transition-colors flex items-center gap-2",
selectedLayout === layout.name
? "bg-cyan-500/20 border border-cyan-500"
: "hover:bg-gray-100 dark:hover:bg-gray-800"
)}
onClick={() => setSelectedLayout(layout.name)}
>
{layout.name === 'Dashboard' && <Grid className="w-4 h-4" />}
{layout.name === 'Kanban Board' && <Kanban className="w-4 h-4" />}
{layout.name === 'Data Table' && <Table className="w-4 h-4" />}
{layout.name === 'Card Grid' && <BarChart className="w-4 h-4" />}
<span className="text-sm">{layout.name}</span>
</div>
))}
</div>
</div>
{/* Center & Right: Grid Background with Floating Layout */}
<div className="lg:col-span-2">
{/* Grid Background with Floating Elements */}
<div
className="relative min-h-80 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden"
style={{
backgroundImage: `
linear-gradient(rgba(156, 163, 175, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(156, 163, 175, 0.1) 1px, transparent 1px)
`,
backgroundSize: '20px 20px'
}}
>
{/* Layout Content Floating Over Grid */}
<div className="absolute inset-4">
{renderLayoutDemo()}
</div>
</div>
</div>
</div>
{/* Generated Code */}
<div className="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700">
<h4 className="text-sm font-medium text-gray-900 dark:text-white mb-3">Generated Code</h4>
<CodeDisplay
code={generateCode()}
showLineNumbers={false}
/>
</div>
</Card>
</div>
);
};

View File

@@ -1,110 +1,105 @@
import React, { useState } from 'react';
import { cn, glassmorphism, glassCard } from '@/features/ui/primitives/styles';
import { Palette, Component, Layout, Code, ChevronRight } from 'lucide-react';
import { cn } from "@/features/ui/primitives/styles";
import { ChevronRight } from "lucide-react";
import type { ReactNode } from "react";
interface NavigationItem {
export interface PillNavigationItem {
id: string;
label: string;
icon: React.ReactNode;
icon?: ReactNode;
items?: string[];
}
interface PillNavigationProps {
selectedSection: string;
selectedItem: string | null;
onSectionChange: (section: string) => void;
onItemChange: (item: string | null) => void;
items: PillNavigationItem[];
activeSection: string;
activeItem?: string;
onSectionClick: (sectionId: string) => void;
onItemClick?: (item: string) => void;
colorVariant?: "blue" | "orange" | "cyan" | "purple" | "emerald";
size?: "small" | "default" | "large";
showIcons?: boolean;
showText?: boolean;
hasSubmenus?: boolean;
openDropdown?: string | null;
}
const NAVIGATION_ITEMS: NavigationItem[] = [
{
id: 'foundations',
label: 'Foundations',
icon: <Palette className="w-4 h-4" />,
items: ['Colors', 'Typography', 'Spacing', 'Effects']
},
{
id: 'components',
label: 'Components',
icon: <Component className="w-4 h-4" />,
items: ['Cards', 'Buttons', 'Forms', 'Tables', 'Modals', 'Toggles']
},
{
id: 'patterns',
label: 'Patterns',
icon: <Layout className="w-4 h-4" />,
items: ['Layouts', 'Feedback', 'Navigation', 'Data Display']
},
{
id: 'examples',
label: 'Examples',
icon: <Code className="w-4 h-4" />,
items: ['Compositions', 'Pages', 'Workflows']
}
];
export const PillNavigation: React.FC<PillNavigationProps> = ({
selectedSection,
selectedItem,
onSectionChange,
onItemChange
}) => {
const [openDropdown, setOpenDropdown] = useState<string | null>(null);
const handleSectionClick = (sectionId: string) => {
if (selectedSection === sectionId && openDropdown === sectionId) {
// Close dropdown if same section clicked
setOpenDropdown(null);
} else {
// Open new section
onSectionChange(sectionId);
setOpenDropdown(sectionId);
}
export const PillNavigation = ({
items,
activeSection,
activeItem,
onSectionClick,
onItemClick,
colorVariant = "cyan",
size = "default",
showIcons = true,
showText = true,
hasSubmenus = true,
openDropdown,
}: PillNavigationProps) => {
const getColorClasses = (variant: string, isSelected: boolean) => {
const colors = {
blue: isSelected
? "bg-blue-500/20 dark:bg-blue-400/20 text-blue-700 dark:text-blue-300 border border-blue-400/50 shadow-[0_0_10px_rgba(59,130,246,0.5)]"
: "text-gray-700 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5",
orange: isSelected
? "bg-orange-500/20 dark:bg-orange-400/20 text-orange-700 dark:text-orange-300 border border-orange-400/50 shadow-[0_0_10px_rgba(251,146,60,0.5)]"
: "text-gray-700 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5",
cyan: isSelected
? "bg-cyan-500/20 dark:bg-cyan-400/20 text-cyan-700 dark:text-cyan-300 border border-cyan-400/50 shadow-[0_0_10px_rgba(34,211,238,0.5)]"
: "text-gray-700 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5",
purple: isSelected
? "bg-purple-500/20 dark:bg-purple-400/20 text-purple-700 dark:text-purple-300 border border-purple-400/50 shadow-[0_0_10px_rgba(147,51,234,0.5)]"
: "text-gray-700 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5",
emerald: isSelected
? "bg-emerald-500/20 dark:bg-emerald-400/20 text-emerald-700 dark:text-emerald-300 border border-emerald-400/50 shadow-[0_0_10px_rgba(16,185,129,0.5)]"
: "text-gray-700 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5",
};
return colors[variant as keyof typeof colors] || colors.cyan;
};
const handleItemClick = (item: string) => {
onItemChange(item);
// Keep dropdown open after selection to show the selected state
const getSizeClasses = (sizeVariant: string) => {
const sizes = {
small: "px-4 py-2 text-xs",
default: "px-6 py-3 text-sm",
large: "px-8 py-4 text-base",
};
return sizes[sizeVariant as keyof typeof sizes] || sizes.default;
};
const selectedSectionData = NAVIGATION_ITEMS.find(item => item.id === selectedSection);
const isExpanded = openDropdown === selectedSection && selectedSectionData?.items;
return (
<div className="flex items-center justify-center">
<div className={cn(
"backdrop-blur-sm bg-white/40 dark:bg-white/5 border border-white/30 dark:border-white/15 rounded-full p-1 shadow-lg transition-all duration-300 ease-in-out"
)}>
<div className="flex gap-1 items-center">
{/* Main navigation items */}
{NAVIGATION_ITEMS.map((item) => {
const isSelected = selectedSection === item.id;
const hasDropdown = item.items && item.items.length > 0;
const isThisExpanded = openDropdown === item.id && hasDropdown;
<div className="backdrop-blur-sm bg-white/40 dark:bg-white/5 border border-white/30 dark:border-white/15 rounded-full p-1 shadow-lg transition-all duration-300 ease-in-out">
<div className="flex gap-1 items-center">
{items.map((item) => {
const isSelected = activeSection === item.id;
const hasDropdown = hasSubmenus && item.items && item.items.length > 0;
const isThisExpanded = openDropdown === item.id && hasDropdown;
return (
<div key={item.id} className="relative">
{/* Extended pill for selected item with dropdown */}
{isSelected && hasDropdown ? (
<div className={cn(
"flex items-center gap-2 px-6 py-3 rounded-full transition-all duration-200",
"text-sm font-medium whitespace-nowrap",
"bg-cyan-500/20 dark:bg-cyan-400/20 text-cyan-700 dark:text-cyan-300 border border-cyan-400/50 shadow-[0_0_10px_rgba(34,211,238,0.5)]"
)}>
{item.icon}
{item.label}
return (
<div key={item.id} className="relative">
{/* Extended pill for selected item with dropdown */}
{isSelected && hasDropdown ? (
<div
className={cn(
"flex items-center gap-2 rounded-full transition-all duration-200",
"font-medium whitespace-nowrap",
getSizeClasses(size),
getColorClasses(colorVariant, true),
)}
>
{showIcons && item.icon}
{showText && item.label}
{/* Dropdown selector inside the pill */}
<div className="flex items-center ml-4 pl-4 border-l border-cyan-400/30">
{/* Dropdown selector inside the pill */}
{onItemClick && (
<div className="flex items-center ml-4 pl-4 border-l border-current/30">
<select
value={selectedItem || ''}
onChange={(e) => handleItemClick(e.target.value)}
className={cn(
"bg-transparent text-cyan-700 dark:text-cyan-300 border-none outline-none",
"text-sm font-medium cursor-pointer"
)}
value={activeItem || ""}
onChange={(e) => onItemClick(e.target.value)}
className="bg-transparent border-none outline-none font-medium cursor-pointer text-inherit"
>
<option value="" disabled>Select...</option>
<option value="" disabled>
Select...
</option>
{item.items?.map((subItem) => (
<option key={subItem} value={subItem} className="bg-gray-800 text-white">
{subItem}
@@ -112,44 +107,44 @@ export const PillNavigation: React.FC<PillNavigationProps> = ({
))}
</select>
</div>
)}
<ChevronRight
className={cn(
"w-4 h-4 transition-transform duration-300 ml-2 cursor-pointer",
isThisExpanded ? "-rotate-90" : "rotate-0",
)}
onClick={() => onSectionClick(item.id)}
/>
</div>
) : (
/* Regular pill for non-selected items */
<button
type="button"
onClick={() => onSectionClick(item.id)}
className={cn(
"flex items-center gap-2 rounded-full transition-all duration-200",
"font-medium whitespace-nowrap",
getSizeClasses(size),
getColorClasses(colorVariant, isSelected),
)}
>
{showIcons && item.icon}
{showText && item.label}
{hasDropdown && (
<ChevronRight
className={cn(
"w-4 h-4 transition-transform duration-300 ml-2",
isThisExpanded ? "-rotate-90" : "rotate-0"
"w-4 h-4 transition-transform duration-300",
isThisExpanded ? "-rotate-90" : "rotate-0",
)}
onClick={() => handleSectionClick(item.id)}
/>
</div>
) : (
/* Regular pill for non-selected items */
<button
onClick={() => handleSectionClick(item.id)}
className={cn(
"flex items-center gap-2 px-6 py-3 rounded-full transition-all duration-200",
"text-sm font-medium whitespace-nowrap",
isSelected
? "bg-cyan-500/20 dark:bg-cyan-400/20 text-cyan-700 dark:text-cyan-300 border border-cyan-400/50 shadow-[0_0_10px_rgba(34,211,238,0.5)]"
: "text-gray-700 dark:text-gray-300 hover:bg-white/10 dark:hover:bg-white/5"
)}
>
{item.icon}
{item.label}
{hasDropdown && (
<ChevronRight
className={cn(
"w-4 h-4 transition-transform duration-300",
isThisExpanded ? "-rotate-90" : "rotate-0"
)}
/>
)}
</button>
)}
</div>
);
})}
</div>
)}
</button>
)}
</div>
);
})}
</div>
</div>
);
};
};

View File

@@ -0,0 +1,43 @@
import { cn } from "@/features/ui/primitives/styles";
import type { ReactNode } from "react";
export interface SideNavigationSection {
id: string;
label: string;
icon?: ReactNode;
}
interface SideNavigationProps {
sections: SideNavigationSection[];
activeSection: string;
onSectionClick: (sectionId: string) => void;
}
export const SideNavigation = ({ sections, activeSection, onSectionClick }: SideNavigationProps) => {
return (
<div className="w-32 flex-shrink-0">
<div className="sticky top-4 space-y-0.5">
{sections.map((section) => {
const isActive = activeSection === section.id;
return (
<button
key={section.id}
type="button"
onClick={() => onSectionClick(section.id)}
className={cn(
"w-full text-left px-2 py-1.5 rounded-md transition-all duration-200",
"flex items-center gap-1.5",
isActive
? "bg-blue-500/10 dark:bg-blue-400/10 text-blue-700 dark:text-blue-300 border-l-2 border-blue-500"
: "text-gray-600 dark:text-gray-400 hover:bg-white/5 dark:hover:bg-white/5 border-l-2 border-transparent",
)}
>
{section.icon && <span className="flex-shrink-0 w-3 h-3">{section.icon}</span>}
<span className="text-xs font-medium truncate">{section.label}</span>
</button>
);
})}
</div>
</div>
);
};

View File

@@ -0,0 +1,130 @@
import { Plus } from "lucide-react";
import { Button } from "@/features/ui/primitives/button";
import { Card } from "@/features/ui/primitives/card";
export const StaticButtons = () => {
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Buttons</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Button types used across the application
</p>
</div>
<div className="space-y-6">
{/* Glass Button (Outer Glow) */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">
Glass Button (Outer Glow)
</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-4">
Primary action button with gradient fill and external glow on hover
</p>
<div className="flex gap-3 items-center flex-wrap">
<Button variant="default" size="sm">
Small
</Button>
<Button variant="default">Default</Button>
<Button variant="default" size="lg">
Large
</Button>
<Button variant="default">
<Plus className="w-4 h-4 mr-2" />
With Icon
</Button>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
variant="default" Outer glow on hover
</p>
</Card>
{/* Outline Button (Inner Glow) */}
<Card className="p-6 shadow-[inset_0_0_15px_rgba(34,211,238,0.1)] dark:shadow-[inset_0_0_20px_rgba(34,211,238,0.15)]">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">
Outline Button (Inner Glow)
</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-4">
Transparent button with border and internal glow on hover
</p>
<div className="flex gap-3 items-center flex-wrap">
<Button variant="outline" size="sm">
Small
</Button>
<Button variant="outline">Default</Button>
<Button variant="outline" size="lg">
Large
</Button>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
variant="outline" Inner glow effect
</p>
</Card>
{/* Ghost Button */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Ghost Button</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-4">
Minimal button with hover background only
</p>
<div className="flex gap-3 items-center flex-wrap">
<Button variant="ghost" size="sm">
Small
</Button>
<Button variant="ghost">Default</Button>
<Button variant="ghost" size="lg">
Large
</Button>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
variant="ghost"
</p>
</Card>
{/* Icon Button */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Icon Only</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-4">
Square button for icon-only actions
</p>
<div className="flex gap-3 items-center flex-wrap">
<Button variant="outline" size="icon">
<Plus className="w-4 h-4" />
</Button>
<Button variant="default" size="icon">
<Plus className="w-4 h-4" />
</Button>
<Button variant="ghost" size="icon">
<Plus className="w-4 h-4" />
</Button>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
size="icon"
</p>
</Card>
{/* Destructive */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">
Destructive
</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-4">
For dangerous or destructive actions (delete, remove, etc.)
</p>
<div className="flex gap-3 items-center flex-wrap">
<Button variant="destructive" size="sm">
Delete
</Button>
<Button variant="destructive">Remove</Button>
<Button variant="destructive" size="lg">
Destroy
</Button>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
variant="destructive"
</p>
</Card>
</div>
</div>
);
};

View File

@@ -0,0 +1,80 @@
import { Card } from "@/features/ui/primitives/card";
import { cn } from "@/features/ui/primitives/styles";
export const StaticCards = () => {
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Cards</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Glass card variants used in the application
</p>
</div>
<div className="space-y-6">
{/* Base Glass Card */}
<div>
<h4 className="text-sm font-semibold mb-3 text-gray-800 dark:text-gray-200">Base Glass Card</h4>
<Card className="p-6 max-w-md">
<h5 className="font-medium text-gray-900 dark:text-white mb-2">Card Title</h5>
<p className="text-sm text-gray-600 dark:text-gray-400">
Default glass card with backdrop blur and semi-transparent background. Used for general containers, settings panels, and content wrappers.
</p>
</Card>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 font-mono">
{"<Card />"}
</p>
</div>
{/* Outer Glow Card */}
<div>
<h4 className="text-sm font-semibold mb-3 text-gray-800 dark:text-gray-200">Outer Glow Card</h4>
<div className="relative max-w-md">
<div className="absolute inset-0 bg-cyan-500/20 blur-xl rounded-xl" />
<Card className="p-6 relative border-cyan-500/30 hover:shadow-[0_0_30px_rgba(6,182,212,0.4)] transition-shadow">
<h5 className="font-medium text-gray-900 dark:text-white mb-2">Active Card</h5>
<p className="text-sm text-gray-600 dark:text-gray-400">
Card with external glow. Used for selected or active states. Hover to see enhanced glow.
</p>
</Card>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 font-mono">
shadow-[0_0_30px_rgba(6,182,212,0.3)] + hover effect
</p>
</div>
{/* Inner Glow Card */}
<div>
<h4 className="text-sm font-semibold mb-3 text-gray-800 dark:text-gray-200">Inner Glow Card</h4>
<Card className="p-6 max-w-md shadow-[inset_0_0_20px_rgba(59,130,246,0.2)] border-blue-500/30">
<h5 className="font-medium text-gray-900 dark:text-white mb-2">Featured Card</h5>
<p className="text-sm text-gray-600 dark:text-gray-400">
Card with internal glow effect. Used for special containers, featured sections, and highlighted content areas.
</p>
</Card>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 font-mono">
shadow-[inset_0_0_20px_rgba(59,130,246,0.2)]
</p>
</div>
{/* Top Edge Glow Card */}
<div>
<h4 className="text-sm font-semibold mb-3 text-gray-800 dark:text-gray-200">Top Edge Glow Card</h4>
<div className="relative overflow-hidden rounded-xl max-w-md">
<div className="absolute inset-x-0 top-0 h-[2px] bg-cyan-500 mx-1 mt-0.5 rounded-full pointer-events-none" />
<div className="absolute inset-x-0 top-0 h-8 bg-gradient-to-b from-cyan-500/25 to-transparent blur-md -mt-1 pointer-events-none" />
<Card className="p-6 relative border-cyan-500/30 bg-gradient-to-b from-cyan-100/50 via-cyan-50/25 to-white/60 dark:from-cyan-900/20 dark:via-cyan-900/10 dark:to-black/30">
<h5 className="font-medium text-gray-900 dark:text-white mb-2">Knowledge Item</h5>
<p className="text-sm text-gray-600 dark:text-gray-400">
Card with colored top edge glow. Used for knowledge cards - cyan for technical web pages, purple for uploaded docs, blue for business content.
</p>
</Card>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 font-mono">
Top hairline (2px) + blur smear (8px)
</p>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,94 @@
import { Card } from "@/features/ui/primitives/card";
import { cn } from "@/features/ui/primitives/styles";
export const StaticColors = () => {
const semanticColors = [
{ name: "Primary", hex: "#3b82f6", tailwind: "blue-500", usage: "Primary actions, links, focus states" },
{ name: "Secondary", hex: "#6b7280", tailwind: "gray-500", usage: "Secondary actions, neutral elements" },
{ name: "Success", hex: "#10b981", tailwind: "emerald-500", usage: "Success states, confirmations" },
{ name: "Warning", hex: "#f97316", tailwind: "orange-500", usage: "Warnings, cautions" },
{ name: "Error", hex: "#ef4444", tailwind: "red-500", usage: "Errors, destructive actions" },
];
const accentColors = [
{ name: "Cyan", hex: "#06b6d4", tailwind: "cyan-500", usage: "Active states, highlights" },
{ name: "Purple", hex: "#a855f7", tailwind: "purple-500", usage: "Creative elements, special features" },
{ name: "Pink", hex: "#ec4899", tailwind: "pink-500", usage: "Emphasis, special content" },
];
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Colors</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Color palette with semantic and accent colors
</p>
</div>
{/* Semantic Colors */}
<div>
<h3 className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-200">
Semantic Colors
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{semanticColors.map((color) => (
<Card key={color.name} className="p-4">
<div className="flex items-center gap-4">
<div
className={cn("w-16 h-16 rounded-lg border border-white/20", `bg-${color.tailwind}`)}
style={{ backgroundColor: color.hex }}
/>
<div className="flex-1">
<h4 className="font-semibold text-gray-900 dark:text-white">{color.name}</h4>
<p className="text-xs text-gray-500 dark:text-gray-400 font-mono mt-1">
{color.hex}
</p>
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">{color.usage}</p>
</div>
</div>
</Card>
))}
</div>
</div>
{/* Accent Colors */}
<div>
<h3 className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-200">
Accent Colors
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{accentColors.map((color) => (
<Card key={color.name} className="p-4">
<div className="flex flex-col gap-3">
<div
className={cn("w-full h-12 rounded-lg border border-white/20")}
style={{ backgroundColor: color.hex }}
/>
<div>
<h4 className="font-semibold text-gray-900 dark:text-white text-sm">{color.name}</h4>
<p className="text-xs text-gray-500 dark:text-gray-400 font-mono">{color.hex}</p>
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">{color.usage}</p>
</div>
</div>
</Card>
))}
</div>
</div>
{/* Grayscale */}
<div>
<h3 className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-200">
Grayscale
</h3>
<div className="flex gap-1">
{[50, 100, 200, 300, 400, 500, 600, 700, 800, 900].map((weight) => (
<div key={weight} className="flex-1">
<div className={cn("h-12 rounded", `bg-gray-${weight}`)} />
<p className="text-xs text-center mt-1 text-gray-500 dark:text-gray-400">{weight}</p>
</div>
))}
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,103 @@
import { motion } from "framer-motion";
import { Card } from "@/features/ui/primitives/card";
export const StaticEffects = () => {
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Effects & Animations</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Visual effects and animations used in the application
</p>
</div>
{/* Hover Effects */}
<div>
<h3 className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-200">Hover Effects</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<Card className="p-6 hover:shadow-[0_0_20px_rgba(34,211,238,0.6)] transition-all duration-300 cursor-pointer">
<h4 className="text-sm font-semibold mb-2 text-gray-900 dark:text-white">Glow Hover</h4>
<p className="text-xs text-gray-600 dark:text-gray-400">Hover to see cyan glow</p>
</Card>
<Card className="p-6 hover:scale-105 transition-transform duration-200 cursor-pointer">
<h4 className="text-sm font-semibold mb-2 text-gray-900 dark:text-white">Scale Hover</h4>
<p className="text-xs text-gray-600 dark:text-gray-400">Hover to scale up</p>
</Card>
<Card className="p-6 hover:border-purple-500 hover:shadow-[0_0_15px_rgba(168,85,247,0.5)] transition-all duration-300 cursor-pointer">
<h4 className="text-sm font-semibold mb-2 text-gray-900 dark:text-white">Border Glow</h4>
<p className="text-xs text-gray-600 dark:text-gray-400">Hover for purple border glow</p>
</Card>
</div>
</div>
{/* Loading States */}
<div>
<h3 className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-200">Loading States</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Spinner</h4>
<div className="flex justify-center py-4">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-cyan-500" />
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 font-mono text-center">
animate-spin
</p>
</Card>
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Pulse</h4>
<div className="flex justify-center py-4">
<div className="w-8 h-8 bg-blue-500 rounded-full animate-pulse" />
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 font-mono text-center">
animate-pulse
</p>
</Card>
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Progress Bar</h4>
<div className="py-4">
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2 overflow-hidden">
<motion.div
className="h-full bg-gradient-to-r from-cyan-500 to-blue-500"
initial={{ width: "0%" }}
animate={{ width: "70%" }}
transition={{ duration: 1.5, repeat: Number.POSITIVE_INFINITY, repeatDelay: 0.5 }}
/>
</div>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 font-mono text-center">
Framer Motion
</p>
</Card>
</div>
</div>
{/* Entrance Animations */}
<div>
<h3 className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-200">Stagger Entrance</h3>
<div className="space-y-2">
{[1, 2, 3, 4].map((i) => (
<motion.div
key={i}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.4, delay: i * 0.1 }}
>
<Card className="p-4">
<p className="text-sm text-gray-700 dark:text-gray-300">
Staggered item {i} - Fades in from left with delay
</p>
</Card>
</motion.div>
))}
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-4 font-mono">
Used for project cards, task lists, knowledge items
</p>
</div>
</div>
);
};

View File

@@ -0,0 +1,160 @@
import { Button } from "@/features/ui/primitives/button";
import { Card } from "@/features/ui/primitives/card";
import { Input } from "@/features/ui/primitives/input";
import { Label } from "@/features/ui/primitives/label";
import { Checkbox } from "@/features/ui/primitives/checkbox";
import { Switch } from "@/features/ui/primitives/switch";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/features/ui/primitives/select";
export const StaticForms = () => {
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Form Elements</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Form inputs and controls used in the application
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Text Input */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Text Input</h4>
<div className="space-y-3">
<div>
<Label htmlFor="example-input">Label</Label>
<Input id="example-input" placeholder="Enter text..." className="mt-1" />
</div>
<div>
<Label htmlFor="example-disabled">Disabled</Label>
<Input id="example-disabled" placeholder="Disabled..." disabled className="mt-1" />
</div>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
{"<Input />"}
</p>
</Card>
{/* Textarea */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Textarea</h4>
<div>
<Label htmlFor="example-textarea">Description</Label>
<textarea
id="example-textarea"
placeholder="Enter description..."
rows={4}
className="mt-1 w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white/50 dark:bg-black/30 px-3 py-2 text-sm backdrop-blur-sm focus:border-cyan-500 focus:outline-none"
/>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
{"<textarea />"}
</p>
</Card>
{/* Checkbox */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Checkbox</h4>
<div className="space-y-3">
<div className="flex items-center gap-2">
<Checkbox id="check-1" defaultChecked color="cyan" />
<Label htmlFor="check-1">Checked</Label>
</div>
<div className="flex items-center gap-2">
<Checkbox id="check-2" color="purple" />
<Label htmlFor="check-2">Unchecked</Label>
</div>
<div className="flex items-center gap-2">
<Checkbox id="check-3" disabled defaultChecked />
<Label htmlFor="check-3">Disabled</Label>
</div>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
{"<Checkbox />"}
</p>
</Card>
{/* Switch Toggle */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Switch Toggle</h4>
<div className="space-y-3">
<div className="flex items-center justify-between">
<Label htmlFor="switch-1">Enable Feature</Label>
<Switch id="switch-1" defaultChecked />
</div>
<div className="flex items-center justify-between">
<Label htmlFor="switch-2">Dark Mode</Label>
<Switch id="switch-2" />
</div>
<div className="flex items-center justify-between">
<Label htmlFor="switch-3">Disabled</Label>
<Switch id="switch-3" disabled />
</div>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
{"<Switch />"}
</p>
</Card>
{/* Select Dropdown */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Select Dropdown</h4>
<div className="space-y-3">
<div>
<Label htmlFor="select-cyan">Cyan Variant</Label>
<Select defaultValue="option2">
<SelectTrigger id="select-cyan" color="cyan" className="mt-1">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="select-purple">Purple Variant</Label>
<Select defaultValue="option1">
<SelectTrigger id="select-purple" color="purple" className="mt-1">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
{"<Select /> with color variants"}
</p>
</Card>
{/* Submit Button */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Form Submission</h4>
<div className="space-y-3">
<div>
<Label htmlFor="form-input">Email</Label>
<Input id="form-input" type="email" placeholder="email@example.com" className="mt-1" />
</div>
<Button variant="default" className="w-full">
Submit
</Button>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 font-mono">
Complete form example
</p>
</Card>
</div>
</div>
);
};

View File

@@ -0,0 +1,40 @@
import { Card } from "@/features/ui/primitives/card";
export const StaticSpacing = () => {
const spacingScale = [
{ value: 1, px: 4, rem: 0.25 },
{ value: 2, px: 8, rem: 0.5 },
{ value: 3, px: 12, rem: 0.75 },
{ value: 4, px: 16, rem: 1 },
{ value: 6, px: 24, rem: 1.5 },
{ value: 8, px: 32, rem: 2 },
{ value: 12, px: 48, rem: 3 },
{ value: 16, px: 64, rem: 4 },
];
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Spacing</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Consistent spacing scale based on 4px increments
</p>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{spacingScale.map((space) => (
<Card key={space.value} className="p-4">
<div className="mb-3">
<div className="bg-blue-500 rounded" style={{ height: `${space.px}px` }} />
</div>
<div className="text-xs space-y-1">
<div className="font-mono text-gray-900 dark:text-white">p-{space.value}</div>
<div className="text-gray-500 dark:text-gray-400">{space.px}px</div>
<div className="text-gray-500 dark:text-gray-400">{space.rem}rem</div>
</div>
</Card>
))}
</div>
</div>
);
};

View File

@@ -0,0 +1,72 @@
export const StaticTables = () => {
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Tables</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Table styles with glassmorphism and hover states
</p>
</div>
{/* Basic Table */}
<div>
<h3 className="text-sm font-semibold mb-3 text-gray-800 dark:text-gray-200">Standard Table</h3>
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="border-b border-white/10">
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Name
</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Status
</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Count
</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">
Date
</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-white/5 hover:bg-white/5 dark:hover:bg-white/5 transition-colors">
<td className="py-3 px-4 text-sm text-gray-900 dark:text-white">React Documentation</td>
<td className="py-3 px-4">
<span className="px-2 py-1 text-xs rounded-md bg-green-500/10 text-green-600 dark:text-green-400">
Active
</span>
</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">145</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">2024-01-15</td>
</tr>
<tr className="border-b border-white/5 hover:bg-white/5 dark:hover:bg-white/5 transition-colors">
<td className="py-3 px-4 text-sm text-gray-900 dark:text-white">API Integration</td>
<td className="py-3 px-4">
<span className="px-2 py-1 text-xs rounded-md bg-yellow-500/10 text-yellow-600 dark:text-yellow-400">
Processing
</span>
</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">89</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">2024-01-18</td>
</tr>
<tr className="border-b border-white/5 hover:bg-white/5 dark:hover:bg-white/5 transition-colors">
<td className="py-3 px-4 text-sm text-gray-900 dark:text-white">TypeScript Guide</td>
<td className="py-3 px-4">
<span className="px-2 py-1 text-xs rounded-md bg-cyan-500/10 text-cyan-600 dark:text-cyan-400">
Complete
</span>
</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">203</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">2024-01-20</td>
</tr>
</tbody>
</table>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3">
Features: Hover row highlight, status badges, responsive overflow
</p>
</div>
</div>
);
};

View File

@@ -0,0 +1,97 @@
import { useState } from "react";
import { Card } from "@/features/ui/primitives/card";
import { PowerButton } from "@/components/ui/PowerButton";
import { Switch } from "@/features/ui/primitives/switch";
import { Label } from "@/features/ui/primitives/label";
export const StaticToggles = () => {
const [powerStates, setPowerStates] = useState({
purple: true,
cyan: false,
green: true,
orange: false,
});
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Toggles</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Toggle controls used in the application
</p>
</div>
{/* Power Button */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-4 text-gray-900 dark:text-white">
Power Button
</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-4">
Animated toggle with glowing power icon. Used for collapsible settings cards.
</p>
<div className="flex gap-6 items-center justify-center py-4">
<div className="flex flex-col items-center gap-2">
<PowerButton
isOn={powerStates.purple}
onClick={() => setPowerStates((s) => ({ ...s, purple: !s.purple }))}
color="purple"
size={40}
/>
<span className="text-xs text-gray-500">Purple</span>
</div>
<div className="flex flex-col items-center gap-2">
<PowerButton
isOn={powerStates.cyan}
onClick={() => setPowerStates((s) => ({ ...s, cyan: !s.cyan }))}
color="cyan"
size={40}
/>
<span className="text-xs text-gray-500">Cyan</span>
</div>
<div className="flex flex-col items-center gap-2">
<PowerButton
isOn={powerStates.green}
onClick={() => setPowerStates((s) => ({ ...s, green: !s.green }))}
color="green"
size={40}
/>
<span className="text-xs text-gray-500">Green</span>
</div>
<div className="flex flex-col items-center gap-2">
<PowerButton
isOn={powerStates.orange}
onClick={() => setPowerStates((s) => ({ ...s, orange: !s.orange }))}
color="orange"
size={40}
/>
<span className="text-xs text-gray-500">Orange</span>
</div>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-4 font-mono">
{"<PowerButton />"}
</p>
</Card>
{/* Switch Toggle */}
<Card className="p-6">
<h4 className="text-sm font-semibold mb-4 text-gray-900 dark:text-white">Switch</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-4">
Standard toggle switch for settings and binary options
</p>
<div className="space-y-3">
<div className="flex items-center justify-between">
<Label htmlFor="toggle-1">Enable Feature</Label>
<Switch id="toggle-1" defaultChecked />
</div>
<div className="flex items-center justify-between">
<Label htmlFor="toggle-2">Auto Save</Label>
<Switch id="toggle-2" />
</div>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-4 font-mono">
{"<Switch />"}
</p>
</Card>
</div>
);
};

View File

@@ -0,0 +1,88 @@
import { Card } from "@/features/ui/primitives/card";
export const StaticTypography = () => {
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Typography</h2>
<p className="text-gray-600 dark:text-gray-400 mb-6">
Typography scale used across the application
</p>
</div>
<Card className="p-6 space-y-6">
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-2 font-mono">
H1 text-4xl font-bold
</div>
<h1 className="text-4xl font-bold text-gray-900 dark:text-white">
Heading 1
</h1>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-2 font-mono">
H2 text-3xl font-bold
</div>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">
Heading 2
</h2>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-2 font-mono">
H3 text-2xl font-semibold
</div>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white">
Heading 3
</h3>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-2 font-mono">
H4 text-xl font-semibold
</div>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white">
Heading 4
</h4>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-2 font-mono">
Body text-base
</div>
<p className="text-base text-gray-700 dark:text-gray-300">
Body text for paragraphs and general content. This is the default text style used throughout the application.
</p>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-2 font-mono">
Small text-sm
</div>
<p className="text-sm text-gray-600 dark:text-gray-400">
Small text for secondary information and descriptions
</p>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-2 font-mono">
Caption text-xs
</div>
<p className="text-xs text-gray-500 dark:text-gray-500">
Caption text for labels, timestamps, and metadata
</p>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-2 font-mono">
Code font-mono
</div>
<code className="font-mono text-sm bg-black/20 px-2 py-1 rounded text-cyan-400">
const example = "code text";
</code>
</div>
</Card>
</div>
);
};

View File

@@ -0,0 +1,172 @@
import { useState } from "react";
import {
Type,
Sparkles,
CreditCard,
MousePointer,
Navigation as NavIcon,
Square,
FormInput,
Table as TableIcon,
ToggleLeft,
Power,
CheckSquare,
} from "lucide-react";
import { SideNavigation, type SideNavigationSection } from "../shared/SideNavigation";
import { TypographyFoundation } from "../foundations/TypographyFoundation";
import { EffectsFoundation } from "../foundations/EffectsFoundation";
import { GlassCardConfigurator } from "../configurators/GlassCardConfigurator";
import { ButtonConfigurator } from "../configurators/ButtonConfigurator";
import { NavigationPattern } from "../configurators/NavigationConfigurator";
import { ModalConfigurator } from "../configurators/ModalConfigurator";
import { FormConfigurator } from "../configurators/FormConfigurator";
import { TableConfigurator } from "../configurators/TableConfigurator";
import { ToggleConfigurator } from "../configurators/ToggleConfigurator";
import { SwitchConfigurator } from "../configurators/SwitchConfigurator";
import { CheckboxConfigurator } from "../configurators/CheckboxConfigurator";
export const ConfiguratorsTab = () => {
const [activeSection, setActiveSection] = useState("typography");
const sections: SideNavigationSection[] = [
{ id: "typography", label: "Typography", icon: <Type className="w-3 h-3" /> },
{ id: "effects", label: "Effects", icon: <Sparkles className="w-3 h-3" /> },
{ id: "glass-card", label: "Glass Card", icon: <CreditCard className="w-3 h-3" /> },
{ id: "button", label: "Button", icon: <MousePointer className="w-3 h-3" /> },
{ id: "navigation", label: "Navigation", icon: <NavIcon className="w-3 h-3" /> },
{ id: "modal", label: "Modal", icon: <Square className="w-3 h-3" /> },
{ id: "form", label: "Form", icon: <FormInput className="w-3 h-3" /> },
{ id: "table", label: "Table", icon: <TableIcon className="w-3 h-3" /> },
{ id: "toggle", label: "Toggle", icon: <ToggleLeft className="w-3 h-3" /> },
{ id: "switch", label: "Switch", icon: <Power className="w-3 h-3" /> },
{ id: "checkbox", label: "Checkbox", icon: <CheckSquare className="w-3 h-3" /> },
];
// Render content based on active section
const renderContent = () => {
switch (activeSection) {
case "typography":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Typography Configurator
</h2>
<TypographyFoundation />
</div>
);
case "effects":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Effects Configurator
</h2>
<EffectsFoundation />
</div>
);
case "glass-card":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Glass Card Configurator
</h2>
<GlassCardConfigurator />
</div>
);
case "button":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Button Configurator
</h2>
<ButtonConfigurator />
</div>
);
case "navigation":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Navigation Configurator
</h2>
<NavigationPattern />
</div>
);
case "modal":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Modal Configurator
</h2>
<ModalConfigurator />
</div>
);
case "form":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Form Configurator
</h2>
<FormConfigurator />
</div>
);
case "table":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Table Configurator
</h2>
<TableConfigurator />
</div>
);
case "toggle":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Toggle Configurator
</h2>
<ToggleConfigurator />
</div>
);
case "switch":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Switch Configurator
</h2>
<SwitchConfigurator />
</div>
);
case "checkbox":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Checkbox Configurator
</h2>
<CheckboxConfigurator />
</div>
);
default:
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Glass Card Configurator
</h2>
<GlassCardConfigurator />
</div>
);
}
};
return (
<div className="flex gap-6">
{/* Side Navigation */}
<SideNavigation
sections={sections}
activeSection={activeSection}
onSectionClick={setActiveSection}
/>
{/* Main Content */}
<div className="flex-1 max-w-5xl">{renderContent()}</div>
</div>
);
};

View File

@@ -0,0 +1,106 @@
import { useState } from "react";
import { Navigation, FolderKanban, Settings, Database, FileText } from "lucide-react";
import { SideNavigation, type SideNavigationSection } from "../shared/SideNavigation";
import { NavigationExplanation } from "../layouts/NavigationExplanation";
import { ProjectsLayoutExample } from "../layouts/ProjectsLayoutExample";
import { SettingsLayoutExample } from "../layouts/SettingsLayoutExample";
import { KnowledgeLayoutExample } from "../layouts/KnowledgeLayoutExample";
import { DocumentBrowserExample } from "../layouts/DocumentBrowserExample";
export const LayoutsTab = () => {
const [activeSection, setActiveSection] = useState("navigation");
const sections: SideNavigationSection[] = [
{ id: "navigation", label: "Navigation", icon: <Navigation className="w-4 h-4" /> },
{ id: "projects", label: "Projects", icon: <FolderKanban className="w-4 h-4" /> },
{ id: "settings", label: "Settings", icon: <Settings className="w-4 h-4" /> },
{ id: "knowledge", label: "Knowledge", icon: <Database className="w-4 h-4" /> },
{ id: "document-browser", label: "Document Browser", icon: <FileText className="w-4 h-4" /> },
];
// Render content based on active section
const renderContent = () => {
switch (activeSection) {
case "navigation":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Navigation Patterns
</h2>
<NavigationExplanation />
</div>
);
case "projects":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Projects Layout
</h2>
<p className="text-gray-600 dark:text-gray-400 mb-4">
Project selection with Kanban board and table views. Uses orange pill navigation for Docs/Tasks tabs.
</p>
<ProjectsLayoutExample />
</div>
);
case "settings":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Settings Layout
</h2>
<p className="text-gray-600 dark:text-gray-400 mb-4">
Bento grid (2-column responsive) with collapsible cards using PowerButton toggles.
</p>
<SettingsLayoutExample />
</div>
);
case "knowledge":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Knowledge Layout
</h2>
<p className="text-gray-600 dark:text-gray-400 mb-4">
Switchable views (grid/table) with filters and search. Cards have top glass glow bars.
</p>
<KnowledgeLayoutExample />
</div>
);
case "document-browser":
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Document Browser
</h2>
<p className="text-gray-600 dark:text-gray-400 mb-4">
Modal or embedded display for documents and code with tabs, search, and expandable content.
</p>
<DocumentBrowserExample />
</div>
);
default:
return (
<div>
<h2 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">
Navigation Patterns
</h2>
<NavigationExplanation />
</div>
);
}
};
return (
<div className="flex gap-6">
{/* Side Navigation */}
<SideNavigation
sections={sections}
activeSection={activeSection}
onSectionClick={setActiveSection}
/>
{/* Main Content */}
<div className="flex-1 max-w-6xl">{renderContent()}</div>
</div>
);
};

View File

@@ -0,0 +1,68 @@
import { useState } from "react";
import { Type, Palette, Box, MousePointer, CreditCard, Table as TableIcon, FormInput, Power, Sparkles } from "lucide-react";
import { SideNavigation, type SideNavigationSection } from "../shared/SideNavigation";
import { StaticTypography } from "../showcases/StaticTypography";
import { StaticColors } from "../showcases/StaticColors";
import { StaticSpacing } from "../showcases/StaticSpacing";
import { StaticButtons } from "../showcases/StaticButtons";
import { StaticCards } from "../showcases/StaticCards";
import { StaticTables } from "../showcases/StaticTables";
import { StaticForms } from "../showcases/StaticForms";
import { StaticToggles } from "../showcases/StaticToggles";
import { StaticEffects } from "../showcases/StaticEffects";
export const StyleGuideTab = () => {
const [activeSection, setActiveSection] = useState("typography");
const sections: SideNavigationSection[] = [
{ id: "typography", label: "Typography", icon: <Type className="w-3 h-3" /> },
{ id: "colors", label: "Colors", icon: <Palette className="w-3 h-3" /> },
{ id: "spacing", label: "Spacing", icon: <Box className="w-3 h-3" /> },
{ id: "buttons", label: "Buttons", icon: <MousePointer className="w-3 h-3" /> },
{ id: "cards", label: "Cards", icon: <CreditCard className="w-3 h-3" /> },
{ id: "tables", label: "Tables", icon: <TableIcon className="w-3 h-3" /> },
{ id: "forms", label: "Forms", icon: <FormInput className="w-3 h-3" /> },
{ id: "toggles", label: "Toggles", icon: <Power className="w-3 h-3" /> },
{ id: "effects", label: "Effects", icon: <Sparkles className="w-3 h-3" /> },
];
// Render content based on active section
const renderContent = () => {
switch (activeSection) {
case "typography":
return <StaticTypography />;
case "colors":
return <StaticColors />;
case "spacing":
return <StaticSpacing />;
case "buttons":
return <StaticButtons />;
case "cards":
return <StaticCards />;
case "tables":
return <StaticTables />;
case "forms":
return <StaticForms />;
case "toggles":
return <StaticToggles />;
case "effects":
return <StaticEffects />;
default:
return <StaticTypography />;
}
};
return (
<div className="flex gap-6">
{/* Side Navigation */}
<SideNavigation
sections={sections}
activeSection={activeSection}
onSectionClick={setActiveSection}
/>
{/* Main Content */}
<div className="flex-1 max-w-5xl">{renderContent()}</div>
</div>
);
};