From 7483e697fc4202ca7d20cba1f00730d14f099d5e Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Fri, 16 Jan 2026 11:04:08 +1000 Subject: [PATCH] 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 --- apps/web/src/app/page.tsx | 17 + apps/web/src/app/style-guide/page.tsx | 312 ++++++++++----- apps/web/src/components/AppHeader.tsx | 6 +- apps/web/src/components/MobileMenu.tsx | 7 +- .../style-guide/SectionComponents.tsx | 354 +++++++++++++++++- .../web/src/components/style-guide/shared.tsx | 4 +- 6 files changed, 569 insertions(+), 131 deletions(-) diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index e93d5c4..b415a34 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -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 { {/* Hero Section - Dithered Design */} + {/* Architecture Diagram Section - temporarily disabled +
+ +
+

+ How It Works +

+

+ Publish once to npm, reach every AI agent. Your tool goes live in minutes. +

+
+ +
+
+ */} + {/* Featured Tools Section */}
diff --git a/apps/web/src/app/style-guide/page.tsx b/apps/web/src/app/style-guide/page.tsx index 5d374d0..1ab6d47 100644 --- a/apps/web/src/app/style-guide/page.tsx +++ b/apps/web/src/app/style-guide/page.tsx @@ -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,124 +29,233 @@ 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 (
-
- - {/* Hero Section */} -
-

- tpmjs design system -

-

- 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. -

-
- v2.0 - wcag aa - dark mode -
-
- - {/* Table of Contents */} - -
-
-

foundations

- 1. design principles - 2. color system - 3. typography - 4. spacing - 5. motion -
-
-

systems

- 6. accessibility - 7. layout & responsiveness - 8. content guidelines - 9. data visualization - 10. iconography -
-
-

implementation

- 11. theming - 12. components - 13. component apis -
-
-

patterns

- 14. navigation - 15. forms - 16. feedback - 17. tables - 18. search & filtering -
-
-

governance

- 19. a11y checklists - 20. content & writing - 21. icon system +
+ {/* Left Sidebar Navigation */} + - {/* Systems Sections */} - - - - - + {/* Main Content */} +
+ + {/* Hero Section */} +
+

+ tpmjs design system +

+

+ 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. +

+
+ v2.0 + wcag aa + dark mode +
+
- {/* Implementation Sections */} - - - + {/* Mobile Table of Contents */} + +
+ {navSections.map((section) => ( +
+

+ {section.title} +

+
    + {section.items.map((item) => ( +
  • + +
  • + ))} +
+
+ ))} +
+
- {/* Pattern Library Sections */} - - - - - + {/* Foundation Sections */} + + + + + - {/* Governance Sections */} - - - + {/* Systems Sections */} + + + + + - {/* Footer */} -
-

- tpmjs design system v2.0 -

-

- built with @tpmjs/ui • inspired by turbopuffer.com -

-
-
-
+ {/* Implementation Sections */} + + + + + {/* Pattern Library Sections */} + + + + + + + {/* Governance Sections */} + + + + + {/* Footer */} +
+

+ tpmjs design system v2.0 +

+

+ built with @tpmjs/ui • inspired by turbopuffer.com +

+
+ +
+
); } diff --git a/apps/web/src/components/AppHeader.tsx b/apps/web/src/components/AppHeader.tsx index 205275c..62d75d2 100644 --- a/apps/web/src/components/AppHeader.tsx +++ b/apps/web/src/components/AppHeader.tsx @@ -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 - - - {/* Separator */} | diff --git a/apps/web/src/components/MobileMenu.tsx b/apps/web/src/components/MobileMenu.tsx index 409c893..3e65c95 100644 --- a/apps/web/src/components/MobileMenu.tsx +++ b/apps/web/src/components/MobileMenu.tsx @@ -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' }, ], }, ]; diff --git a/apps/web/src/components/style-guide/SectionComponents.tsx b/apps/web/src/components/style-guide/SectionComponents.tsx index ae12cd8..7360055 100644 --- a/apps/web/src/components/style-guide/SectionComponents.tsx +++ b/apps/web/src/components/style-guide/SectionComponents.tsx @@ -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 (

@@ -74,7 +109,9 @@ export function SectionComponents({ - +

@@ -117,20 +154,63 @@ export function SectionComponents({ {/* Card */}
- {(['default', 'elevated', 'outline', 'blueprint', 'featured', 'brutalist'] as const).map((variant) => ( - - - {variant} card - card variant example - - -

card content goes here.

-
- - - -
- ))} + {(['default', 'elevated', 'outline', 'blueprint', 'featured', 'brutalist'] as const).map( + (variant) => ( + + + {variant} card + card variant example + + +

card content goes here.

+
+ + + +
+ ) + )} +
+
+ + {/* Accordion */} + + + + What is TPMJS? + + TPMJS is a tool package manager for JavaScript that helps you discover, publish, and + use AI tools. + + + + How do I publish a tool? + + Add the tpmjs keyword to your package.json and publish to npm. Your tool will be + automatically discovered. + + + + Is it free to use? + + Yes, TPMJS is free for open source tools. Enterprise features are available for + private registries. + + + + + + {/* Breadcrumbs */} + +
+
@@ -189,6 +269,36 @@ export function SectionComponents({
+ {/* Slider */} + +
+ +

Value: {sliderValue}

+
+
+ + {/* Progress Bar */} + +
+
+

25%

+ +
+
+

50%

+ +
+
+

75%

+ +
+
+

100%

+ +
+
+
+ {/* Tabs */}
@@ -240,6 +350,100 @@ export function SectionComponents({ + {/* Pagination */} + + + + + {/* Dropdown Menu */} + + + + + + + Profile + Settings + + Logout + + + + + {/* Popover */} + + + + + + +
+

Popover Title

+

+ This is the popover content. It can contain any elements. +

+
+
+
+
+ + {/* Tooltip */} + + +
+ + + + + +

This is a tooltip

+
+
+
+
+
+ + {/* Modal */} + + + + + + +
+

Modal content goes here.

+
+
+ + +
+
+
+
+ + {/* Drawer */} + + + + + + +
+

Drawer Content

+

+ This is the drawer content. It slides in from the bottom. +

+
+
+
+
+ {/* Spinner */}
@@ -266,6 +470,122 @@ export function SectionComponents({
+ {/* Skeleton */} + +
+ + + +
+ +
+ + +
+
+
+
+ + {/* State Components */} + +
+
+

empty state

+ Create Item} + /> +
+
+

error state

+ {}} + /> +
+
+

loading state

+ +
+
+
+ + {/* Page Header */} + +
+ + + +
+ } + /> +
+
+ + {/* Stat Card */} + +
+ + + +
+
+ + {/* Quality Score */} + +
+
+ +

excellent

+
+
+ +

good

+
+
+ +

average

+
+
+ +

poor

+
+
+
+ + {/* Install Snippet */} + + + + + {/* Toast */} + + +
+ + setShowToast(false)} + title="Success!" + description="Your action was completed successfully." + variant="success" + /> +

+ Toast variants: default, success, error, warning, info +

+
+
+
+ {/* Code Block */} +
{title}