feat(web): enhance style guide with left nav and all components
- Add sticky left-hand navigation with scroll-spy for active section - Add 20+ missing UI components to style guide showcase - Include Accordion, Breadcrumbs, Drawer, Modal, Pagination, etc. - Add state components: EmptyState, ErrorState, LoadingState - Remove Playground link from header and mobile menu - Comment out Architecture Diagram on homepage temporarily
This commit is contained in:
parent
76955bde18
commit
7483e697fc
6 changed files with 569 additions and 131 deletions
|
|
@ -4,6 +4,7 @@ import { Button } from '@tpmjs/ui/Button/Button';
|
|||
import { Container } from '@tpmjs/ui/Container/Container';
|
||||
import Link from 'next/link';
|
||||
import { AppHeader } from '../components/AppHeader';
|
||||
// import { ArchitectureDiagramWrapper } from '../components/home/ArchitectureDiagramWrapper';
|
||||
import { HeroSection } from '../components/home/HeroSection';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
|
@ -83,6 +84,22 @@ export default async function HomePage(): Promise<React.ReactElement> {
|
|||
{/* Hero Section - Dithered Design */}
|
||||
<HeroSection stats={data.stats} />
|
||||
|
||||
{/* Architecture Diagram Section - temporarily disabled
|
||||
<section className="py-16 bg-background border-b border-border">
|
||||
<Container size="xl" padding="lg">
|
||||
<div className="text-center mb-10">
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-4 text-foreground">
|
||||
How It Works
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary max-w-2xl mx-auto">
|
||||
Publish once to npm, reach every AI agent. Your tool goes live in minutes.
|
||||
</p>
|
||||
</div>
|
||||
<ArchitectureDiagramWrapper />
|
||||
</Container>
|
||||
</section>
|
||||
*/}
|
||||
|
||||
{/* Featured Tools Section */}
|
||||
<section className="py-16 bg-background">
|
||||
<Container size="xl" padding="lg">
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
import { Badge } from '@tpmjs/ui/Badge/Badge';
|
||||
import { Container } from '@tpmjs/ui/Container/Container';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { AppHeader } from '~/components/AppHeader';
|
||||
import {
|
||||
FieldsetSection,
|
||||
NavItem,
|
||||
SectionA11yChecklists,
|
||||
SectionAccessibility,
|
||||
SectionColors,
|
||||
|
|
@ -30,74 +29,182 @@ import {
|
|||
SectionTypography,
|
||||
} from '~/components/style-guide';
|
||||
|
||||
interface NavSection {
|
||||
title: string;
|
||||
items: { id: string; label: string }[];
|
||||
}
|
||||
|
||||
const navSections: NavSection[] = [
|
||||
{
|
||||
title: 'Foundations',
|
||||
items: [
|
||||
{ id: 'principles', label: 'Design Principles' },
|
||||
{ id: 'colors', label: 'Color System' },
|
||||
{ id: 'typography', label: 'Typography' },
|
||||
{ id: 'spacing', label: 'Spacing' },
|
||||
{ id: 'motion', label: 'Motion' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Systems',
|
||||
items: [
|
||||
{ id: 'accessibility', label: 'Accessibility' },
|
||||
{ id: 'layout', label: 'Layout' },
|
||||
{ id: 'content', label: 'Content' },
|
||||
{ id: 'data-viz', label: 'Data Visualization' },
|
||||
{ id: 'icons', label: 'Iconography' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Implementation',
|
||||
items: [
|
||||
{ id: 'theming', label: 'Theming' },
|
||||
{ id: 'components', label: 'Components' },
|
||||
{ id: 'api', label: 'Component APIs' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Patterns',
|
||||
items: [
|
||||
{ id: 'nav-patterns', label: 'Navigation' },
|
||||
{ id: 'form-patterns', label: 'Forms' },
|
||||
{ id: 'feedback-patterns', label: 'Feedback' },
|
||||
{ id: 'table-patterns', label: 'Tables' },
|
||||
{ id: 'search-patterns', label: 'Search & Filtering' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Governance',
|
||||
items: [
|
||||
{ id: 'a11y-checklists', label: 'A11y Checklists' },
|
||||
{ id: 'content-guidelines', label: 'Content & Writing' },
|
||||
{ id: 'icon-system', label: 'Icon System' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function StyleGuidePage(): React.ReactElement {
|
||||
const [activeTab, setActiveTab] = useState('all');
|
||||
const [radioValue, setRadioValue] = useState('option1');
|
||||
const [counterValue, setCounterValue] = useState(1234);
|
||||
const [density, setDensity] = useState<'compact' | 'comfortable' | 'spacious'>('comfortable');
|
||||
const [activeSection, setActiveSection] = useState('principles');
|
||||
|
||||
// Track active section on scroll
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
const sections = navSections.flatMap((s) => s.items.map((i) => i.id));
|
||||
for (const id of sections) {
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
if (rect.top <= 120 && rect.bottom > 120) {
|
||||
setActiveSection(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
const scrollToSection = (id: string) => {
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
const offset = 80;
|
||||
const elementPosition = element.getBoundingClientRect().top + window.scrollY;
|
||||
window.scrollTo({ top: elementPosition - offset, behavior: 'smooth' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col bg-background">
|
||||
<AppHeader />
|
||||
|
||||
<main className="flex-1 py-24">
|
||||
<div className="flex-1 flex">
|
||||
{/* Left Sidebar Navigation */}
|
||||
<aside className="hidden lg:block w-64 flex-shrink-0">
|
||||
<nav className="sticky top-16 h-[calc(100vh-4rem)] overflow-y-auto py-8 px-4 border-r border-border">
|
||||
<div className="mb-6">
|
||||
<h2 className="font-mono text-xs text-foreground-tertiary uppercase tracking-wider mb-2">
|
||||
Design System
|
||||
</h2>
|
||||
<div className="flex gap-2">
|
||||
<Badge variant="default" size="sm">v2.0</Badge>
|
||||
<Badge variant="outline" size="sm">wcag aa</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{navSections.map((section) => (
|
||||
<div key={section.title} className="mb-6">
|
||||
<h3 className="font-mono text-xs text-foreground-tertiary uppercase tracking-wider mb-2">
|
||||
{section.title}
|
||||
</h3>
|
||||
<ul className="space-y-1">
|
||||
{section.items.map((item) => (
|
||||
<li key={item.id}>
|
||||
<button
|
||||
onClick={() => scrollToSection(item.id)}
|
||||
className={`block w-full text-left px-3 py-1.5 text-sm rounded-md transition-colors ${
|
||||
activeSection === item.id
|
||||
? 'bg-primary/10 text-primary font-medium'
|
||||
: 'text-foreground-secondary hover:text-foreground hover:bg-surface'
|
||||
}`}
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="flex-1 min-w-0 py-12">
|
||||
<Container size="lg" padding="lg">
|
||||
{/* Hero Section */}
|
||||
<div className="mb-24">
|
||||
<div className="mb-16">
|
||||
<h1 className="font-mono text-4xl md:text-5xl lg:text-6xl font-semibold mb-6 text-foreground lowercase tracking-tight">
|
||||
tpmjs design system
|
||||
</h1>
|
||||
<p className="font-sans text-lg text-foreground-secondary max-w-2xl leading-relaxed mb-8">
|
||||
<p className="font-sans text-lg text-foreground-secondary max-w-2xl leading-relaxed mb-6">
|
||||
The comprehensive design system for TPMJS. This guide covers design principles,
|
||||
foundations, components, and governance rules that scale across teams, AI agents,
|
||||
and external contributors.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<div className="flex flex-wrap gap-3 lg:hidden">
|
||||
<Badge variant="default">v2.0</Badge>
|
||||
<Badge variant="outline">wcag aa</Badge>
|
||||
<Badge variant="outline">dark mode</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Table of Contents */}
|
||||
<FieldsetSection title="table of contents" id="toc">
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||
<div className="space-y-2">
|
||||
<p className="font-mono text-xs text-foreground-tertiary uppercase tracking-wide mb-3">foundations</p>
|
||||
<NavItem href="#principles">1. design principles</NavItem>
|
||||
<NavItem href="#colors">2. color system</NavItem>
|
||||
<NavItem href="#typography">3. typography</NavItem>
|
||||
<NavItem href="#spacing">4. spacing</NavItem>
|
||||
<NavItem href="#motion">5. motion</NavItem>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="font-mono text-xs text-foreground-tertiary uppercase tracking-wide mb-3">systems</p>
|
||||
<NavItem href="#accessibility">6. accessibility</NavItem>
|
||||
<NavItem href="#layout">7. layout & responsiveness</NavItem>
|
||||
<NavItem href="#content">8. content guidelines</NavItem>
|
||||
<NavItem href="#data-viz">9. data visualization</NavItem>
|
||||
<NavItem href="#icons">10. iconography</NavItem>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="font-mono text-xs text-foreground-tertiary uppercase tracking-wide mb-3">implementation</p>
|
||||
<NavItem href="#theming">11. theming</NavItem>
|
||||
<NavItem href="#components">12. components</NavItem>
|
||||
<NavItem href="#api">13. component apis</NavItem>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="font-mono text-xs text-foreground-tertiary uppercase tracking-wide mb-3">patterns</p>
|
||||
<NavItem href="#nav-patterns">14. navigation</NavItem>
|
||||
<NavItem href="#form-patterns">15. forms</NavItem>
|
||||
<NavItem href="#feedback-patterns">16. feedback</NavItem>
|
||||
<NavItem href="#table-patterns">17. tables</NavItem>
|
||||
<NavItem href="#search-patterns">18. search & filtering</NavItem>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="font-mono text-xs text-foreground-tertiary uppercase tracking-wide mb-3">governance</p>
|
||||
<NavItem href="#a11y-checklists">19. a11y checklists</NavItem>
|
||||
<NavItem href="#content-guidelines">20. content & writing</NavItem>
|
||||
<NavItem href="#icon-system">21. icon system</NavItem>
|
||||
{/* Mobile Table of Contents */}
|
||||
<FieldsetSection title="table of contents" id="toc" className="lg:hidden">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
{navSections.map((section) => (
|
||||
<div key={section.title}>
|
||||
<p className="font-mono text-xs text-foreground-tertiary uppercase tracking-wide mb-2">
|
||||
{section.title}
|
||||
</p>
|
||||
<ul className="space-y-1">
|
||||
{section.items.map((item) => (
|
||||
<li key={item.id}>
|
||||
<button
|
||||
onClick={() => scrollToSection(item.id)}
|
||||
className="text-sm text-foreground-secondary hover:text-primary transition-colors"
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</FieldsetSection>
|
||||
|
||||
|
|
@ -149,5 +256,6 @@ export default function StyleGuidePage(): React.ReactElement {
|
|||
</Container>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ const resourceItems: DropdownItem[] = [
|
|||
{ href: '/faq', label: 'FAQ', description: 'Common questions' },
|
||||
{ href: '/changelog', label: 'Changelog', description: 'Latest updates' },
|
||||
{ href: '/stats', label: 'Stats', description: 'Platform metrics' },
|
||||
{ href: '/style-guide', label: 'Style Guide', description: 'UI components' },
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -217,11 +218,6 @@ export function AppHeader(): React.ReactElement {
|
|||
Agents
|
||||
</Button>
|
||||
</Link>
|
||||
<a href="https://playground.tpmjs.com" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Playground
|
||||
</Button>
|
||||
</a>
|
||||
|
||||
{/* Separator */}
|
||||
<span className="text-foreground-tertiary mx-2">|</span>
|
||||
|
|
|
|||
|
|
@ -24,12 +24,6 @@ const navSections: NavSection[] = [
|
|||
{ href: '/tool/tool-search', label: 'Tools', description: 'Browse all tools' },
|
||||
{ href: '/collections', label: 'Collections', description: 'Discover curated tool sets' },
|
||||
{ href: '/agents', label: 'Agents', description: 'AI agents with tools' },
|
||||
{
|
||||
href: 'https://playground.tpmjs.com',
|
||||
label: 'Playground',
|
||||
description: 'Try tools live',
|
||||
external: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -50,6 +44,7 @@ const navSections: NavSection[] = [
|
|||
{ href: '/faq', label: 'FAQ', description: 'Common questions' },
|
||||
{ href: '/changelog', label: 'Changelog', description: 'Latest updates' },
|
||||
{ href: '/stats', label: 'Stats', description: 'Platform metrics' },
|
||||
{ href: '/style-guide', label: 'Style Guide', description: 'UI components' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
'use client';
|
||||
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from '@tpmjs/ui/Accordion/Accordion';
|
||||
import { Badge } from '@tpmjs/ui/Badge/Badge';
|
||||
import { Breadcrumbs } from '@tpmjs/ui/Breadcrumbs/Breadcrumbs';
|
||||
import { Button } from '@tpmjs/ui/Button/Button';
|
||||
import {
|
||||
Card,
|
||||
|
|
@ -12,15 +19,35 @@ import {
|
|||
} from '@tpmjs/ui/Card/Card';
|
||||
import { Checkbox } from '@tpmjs/ui/Checkbox/Checkbox';
|
||||
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
|
||||
import { Drawer, DrawerContent, DrawerTrigger } from '@tpmjs/ui/Drawer/Drawer';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@tpmjs/ui/DropdownMenu/DropdownMenu';
|
||||
import { EmptyState } from '@tpmjs/ui/EmptyState/EmptyState';
|
||||
import { ErrorState } from '@tpmjs/ui/ErrorState/ErrorState';
|
||||
import { FormField } from '@tpmjs/ui/FormField/FormField';
|
||||
import { Icon } from '@tpmjs/ui/Icon/Icon';
|
||||
import { Input } from '@tpmjs/ui/Input/Input';
|
||||
import { InstallSnippet } from '@tpmjs/ui/InstallSnippet/InstallSnippet';
|
||||
import { LoadingState } from '@tpmjs/ui/LoadingState/LoadingState';
|
||||
import { Modal, ModalContent, ModalTrigger } from '@tpmjs/ui/Modal/Modal';
|
||||
import { PageHeader } from '@tpmjs/ui/PageHeader/PageHeader';
|
||||
import { Pagination } from '@tpmjs/ui/Pagination/Pagination';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@tpmjs/ui/Popover/Popover';
|
||||
import { ProgressBar } from '@tpmjs/ui/ProgressBar/ProgressBar';
|
||||
import { QualityScore } from '@tpmjs/ui/QualityScore/QualityScore';
|
||||
import { Radio } from '@tpmjs/ui/Radio/Radio';
|
||||
import { RadioGroup } from '@tpmjs/ui/Radio/RadioGroup';
|
||||
import { Select } from '@tpmjs/ui/Select/Select';
|
||||
import { Skeleton } from '@tpmjs/ui/Skeleton/Skeleton';
|
||||
import { Slider } from '@tpmjs/ui/Slider/Slider';
|
||||
import { Spinner } from '@tpmjs/ui/Spinner/Spinner';
|
||||
import { StatCard } from '@tpmjs/ui/StatCard/StatCard';
|
||||
import { Switch } from '@tpmjs/ui/Switch/Switch';
|
||||
import { Tabs } from '@tpmjs/ui/Tabs/Tabs';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
|
@ -30,7 +57,11 @@ import {
|
|||
TableHeader,
|
||||
TableRow,
|
||||
} from '@tpmjs/ui/Table/Table';
|
||||
import { Tabs } from '@tpmjs/ui/Tabs/Tabs';
|
||||
import { Textarea } from '@tpmjs/ui/Textarea/Textarea';
|
||||
import { Toast, ToastProvider } from '@tpmjs/ui/Toast/Toast';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@tpmjs/ui/Tooltip/Tooltip';
|
||||
import { useState } from 'react';
|
||||
import { FieldsetSection, SubSection } from './shared';
|
||||
|
||||
interface SectionComponentsProps {
|
||||
|
|
@ -44,8 +75,12 @@ export function SectionComponents({
|
|||
activeTab,
|
||||
onTabChange,
|
||||
radioValue,
|
||||
onRadioChange
|
||||
onRadioChange,
|
||||
}: SectionComponentsProps): React.ReactElement {
|
||||
const [sliderValue, setSliderValue] = useState(50);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [showToast, setShowToast] = useState(false);
|
||||
|
||||
return (
|
||||
<FieldsetSection title="12. components" id="components">
|
||||
<p className="text-foreground-secondary mb-8 font-sans prose-width">
|
||||
|
|
@ -74,7 +109,9 @@ export function SectionComponents({
|
|||
<Button size="sm">small</Button>
|
||||
<Button size="md">medium</Button>
|
||||
<Button size="lg">large</Button>
|
||||
<Button size="icon"><Icon icon="plus" size="sm" /></Button>
|
||||
<Button size="icon">
|
||||
<Icon icon="plus" size="sm" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -117,7 +154,8 @@ export function SectionComponents({
|
|||
{/* Card */}
|
||||
<SubSection title="card">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{(['default', 'elevated', 'outline', 'blueprint', 'featured', 'brutalist'] as const).map((variant) => (
|
||||
{(['default', 'elevated', 'outline', 'blueprint', 'featured', 'brutalist'] as const).map(
|
||||
(variant) => (
|
||||
<Card key={variant} variant={variant}>
|
||||
<CardHeader>
|
||||
<CardTitle>{variant} card</CardTitle>
|
||||
|
|
@ -130,7 +168,49 @@ export function SectionComponents({
|
|||
<Button size="sm">action</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
))}
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Accordion */}
|
||||
<SubSection title="accordion">
|
||||
<Accordion type="single" collapsible className="w-full max-w-lg">
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>What is TPMJS?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
TPMJS is a tool package manager for JavaScript that helps you discover, publish, and
|
||||
use AI tools.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="item-2">
|
||||
<AccordionTrigger>How do I publish a tool?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Add the tpmjs keyword to your package.json and publish to npm. Your tool will be
|
||||
automatically discovered.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="item-3">
|
||||
<AccordionTrigger>Is it free to use?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes, TPMJS is free for open source tools. Enterprise features are available for
|
||||
private registries.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</SubSection>
|
||||
|
||||
{/* Breadcrumbs */}
|
||||
<SubSection title="breadcrumbs">
|
||||
<div className="space-y-4">
|
||||
<Breadcrumbs
|
||||
items={[
|
||||
{ label: 'Home', href: '/' },
|
||||
{ label: 'Tools', href: '/tools' },
|
||||
{ label: 'Category', href: '/tools/category' },
|
||||
{ label: 'Current Page' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
|
|
@ -189,6 +269,36 @@ export function SectionComponents({
|
|||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Slider */}
|
||||
<SubSection title="slider">
|
||||
<div className="max-w-md space-y-4">
|
||||
<Slider value={sliderValue} onChange={setSliderValue} min={0} max={100} step={1} />
|
||||
<p className="font-mono text-xs text-foreground-secondary">Value: {sliderValue}</p>
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Progress Bar */}
|
||||
<SubSection title="progress bar">
|
||||
<div className="space-y-6 max-w-md">
|
||||
<div>
|
||||
<p className="font-mono text-xs text-foreground-secondary mb-2">25%</p>
|
||||
<ProgressBar value={25} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-mono text-xs text-foreground-secondary mb-2">50%</p>
|
||||
<ProgressBar value={50} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-mono text-xs text-foreground-secondary mb-2">75%</p>
|
||||
<ProgressBar value={75} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-mono text-xs text-foreground-secondary mb-2">100%</p>
|
||||
<ProgressBar value={100} />
|
||||
</div>
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Tabs */}
|
||||
<SubSection title="tabs">
|
||||
<div className="space-y-6">
|
||||
|
|
@ -240,6 +350,100 @@ export function SectionComponents({
|
|||
</Table>
|
||||
</SubSection>
|
||||
|
||||
{/* Pagination */}
|
||||
<SubSection title="pagination">
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={10}
|
||||
onPageChange={setCurrentPage}
|
||||
/>
|
||||
</SubSection>
|
||||
|
||||
{/* Dropdown Menu */}
|
||||
<SubSection title="dropdown menu">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
Open Menu <Icon icon="chevronDown" size="sm" className="ml-2" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Logout</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SubSection>
|
||||
|
||||
{/* Popover */}
|
||||
<SubSection title="popover">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline">Open Popover</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<div className="space-y-2">
|
||||
<h4 className="font-medium text-foreground">Popover Title</h4>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
This is the popover content. It can contain any elements.
|
||||
</p>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</SubSection>
|
||||
|
||||
{/* Tooltip */}
|
||||
<SubSection title="tooltip">
|
||||
<TooltipProvider>
|
||||
<div className="flex gap-4">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="outline">Hover me</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>This is a tooltip</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</SubSection>
|
||||
|
||||
{/* Modal */}
|
||||
<SubSection title="modal">
|
||||
<Modal>
|
||||
<ModalTrigger asChild>
|
||||
<Button>Open Modal</Button>
|
||||
</ModalTrigger>
|
||||
<ModalContent title="Modal Title" description="This is a modal dialog.">
|
||||
<div className="py-4">
|
||||
<p className="text-foreground-secondary">Modal content goes here.</p>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant="outline">Cancel</Button>
|
||||
<Button>Confirm</Button>
|
||||
</div>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</SubSection>
|
||||
|
||||
{/* Drawer */}
|
||||
<SubSection title="drawer">
|
||||
<Drawer>
|
||||
<DrawerTrigger asChild>
|
||||
<Button variant="outline">Open Drawer</Button>
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<div className="p-6">
|
||||
<h3 className="text-lg font-semibold mb-4">Drawer Content</h3>
|
||||
<p className="text-foreground-secondary">
|
||||
This is the drawer content. It slides in from the bottom.
|
||||
</p>
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</SubSection>
|
||||
|
||||
{/* Spinner */}
|
||||
<SubSection title="spinner">
|
||||
<div className="flex flex-wrap gap-12 items-center">
|
||||
|
|
@ -266,6 +470,122 @@ export function SectionComponents({
|
|||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Skeleton */}
|
||||
<SubSection title="skeleton">
|
||||
<div className="space-y-4 max-w-md">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-3/4" />
|
||||
<Skeleton className="h-4 w-1/2" />
|
||||
<div className="flex items-center gap-4 mt-6">
|
||||
<Skeleton className="h-12 w-12 rounded-full" />
|
||||
<div className="space-y-2 flex-1">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-2/3" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* State Components */}
|
||||
<SubSection title="state components">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="border border-dashed border-border p-4">
|
||||
<p className="font-mono text-xs text-foreground-secondary mb-4">empty state</p>
|
||||
<EmptyState
|
||||
icon="inbox"
|
||||
title="No items yet"
|
||||
description="Get started by creating your first item."
|
||||
action={<Button size="sm">Create Item</Button>}
|
||||
/>
|
||||
</div>
|
||||
<div className="border border-dashed border-border p-4">
|
||||
<p className="font-mono text-xs text-foreground-secondary mb-4">error state</p>
|
||||
<ErrorState
|
||||
title="Something went wrong"
|
||||
message="Failed to load data. Please try again."
|
||||
onRetry={() => {}}
|
||||
/>
|
||||
</div>
|
||||
<div className="border border-dashed border-border p-4">
|
||||
<p className="font-mono text-xs text-foreground-secondary mb-4">loading state</p>
|
||||
<LoadingState message="Loading data..." />
|
||||
</div>
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Page Header */}
|
||||
<SubSection title="page header">
|
||||
<div className="border border-dashed border-border p-4">
|
||||
<PageHeader
|
||||
title="Page Title"
|
||||
description="This is a description of the page content."
|
||||
actions={
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm">
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="sm">Primary</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Stat Card */}
|
||||
<SubSection title="stat card">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<StatCard title="Total Tools" value="1,234" change="+12%" changeType="positive" />
|
||||
<StatCard title="Downloads" value="45.2K" change="-3%" changeType="negative" />
|
||||
<StatCard title="Users" value="892" change="0%" changeType="neutral" />
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Quality Score */}
|
||||
<SubSection title="quality score">
|
||||
<div className="flex flex-wrap gap-8 items-center">
|
||||
<div className="text-center">
|
||||
<QualityScore score={0.95} size="lg" />
|
||||
<p className="font-mono text-xs text-foreground-secondary mt-2">excellent</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<QualityScore score={0.75} size="lg" />
|
||||
<p className="font-mono text-xs text-foreground-secondary mt-2">good</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<QualityScore score={0.5} size="lg" />
|
||||
<p className="font-mono text-xs text-foreground-secondary mt-2">average</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<QualityScore score={0.25} size="lg" />
|
||||
<p className="font-mono text-xs text-foreground-secondary mt-2">poor</p>
|
||||
</div>
|
||||
</div>
|
||||
</SubSection>
|
||||
|
||||
{/* Install Snippet */}
|
||||
<SubSection title="install snippet">
|
||||
<InstallSnippet packageName="@tpmjs/example-tool" />
|
||||
</SubSection>
|
||||
|
||||
{/* Toast */}
|
||||
<SubSection title="toast">
|
||||
<ToastProvider>
|
||||
<div className="space-y-4">
|
||||
<Button onClick={() => setShowToast(true)}>Show Toast</Button>
|
||||
<Toast
|
||||
open={showToast}
|
||||
onClose={() => setShowToast(false)}
|
||||
title="Success!"
|
||||
description="Your action was completed successfully."
|
||||
variant="success"
|
||||
/>
|
||||
<p className="font-mono text-xs text-foreground-secondary">
|
||||
Toast variants: default, success, error, warning, info
|
||||
</p>
|
||||
</div>
|
||||
</ToastProvider>
|
||||
</SubSection>
|
||||
|
||||
{/* Code Block */}
|
||||
<SubSection title="code block">
|
||||
<CodeBlock
|
||||
|
|
|
|||
|
|
@ -9,13 +9,15 @@ export function FieldsetSection({
|
|||
title,
|
||||
children,
|
||||
id,
|
||||
className = '',
|
||||
}: {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
id?: string;
|
||||
className?: string;
|
||||
}): React.ReactElement {
|
||||
return (
|
||||
<fieldset id={id} className="border border-dashed border-border p-8 mb-16 scroll-mt-24">
|
||||
<fieldset id={id} className={`border border-dashed border-border p-8 mb-16 scroll-mt-24 ${className}`}>
|
||||
<legend className="font-mono text-sm text-foreground-secondary px-3 lowercase">
|
||||
{title}
|
||||
</legend>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue