diff --git a/examples/index.tsx b/examples/index.tsx index 01f8874..32ffbc3 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -70,6 +70,11 @@ export const IndexPage = () => (

Buttons

Button component with intent, size, and disabled variants

+ + +

Navigation

+

Navigation patterns including tabs, pills, vertical nav, and breadcrumbs

+
diff --git a/examples/navigation.tsx b/examples/navigation.tsx new file mode 100644 index 0000000..571285b --- /dev/null +++ b/examples/navigation.tsx @@ -0,0 +1,335 @@ +import { define } from '../src' +import { Layout, ExampleSection } from './helpers' + +const Tabs = define('Tabs', { + layout: { + display: 'flex', + gap: 0, + }, + look: { + borderBottom: '2px solid #e5e7eb', + }, + + parts: { + Tab: { + base: 'button', + layout: { + padding: '12px 24px', + position: 'relative', + marginBottom: -2, + }, + look: { + background: 'transparent', + border: 'none', + borderBottom: '2px solid transparent', + color: '#6b7280', + fontSize: 14, + fontWeight: 500, + cursor: 'pointer', + transition: 'all 0.2s ease', + }, + states: { + ':hover': { + look: { + color: '#111827', + } + } + } + } + }, + + variants: { + active: { + parts: { + Tab: { + look: { + color: '#3b82f6', + borderBottom: '2px solid #3b82f6', + }, + } + } + } + }, + + render({ props, parts: { Root, Tab } }) { + return ( + + {props.items?.map((item: any) => ( + console.log('Tab clicked:', item.label)} + > + {item.label} + + ))} + + ) + } +}) + +const Pills = define('Pills', { + layout: { + display: 'flex', + gap: 8, + flexWrap: 'wrap', + }, + + parts: { + Pill: { + base: 'button', + layout: { + padding: '8px 16px', + }, + look: { + background: '#f3f4f6', + border: 'none', + borderRadius: 20, + color: '#6b7280', + fontSize: 14, + fontWeight: 500, + cursor: 'pointer', + transition: 'all 0.2s ease', + }, + states: { + ':hover': { + look: { + background: '#e5e7eb', + color: '#111827', + } + } + } + } + }, + + variants: { + active: { + parts: { + Pill: { + look: { + background: '#3b82f6', + color: 'white', + }, + states: { + ':hover': { + look: { + background: '#2563eb', + color: 'white', + } + } + } + } + } + } + }, + + render({ props, parts: { Root, Pill } }) { + return ( + + {props.items?.map((item: any) => ( + console.log('Pill clicked:', item.label)} + > + {item.label} + + ))} + + ) + } +}) + +const VerticalNav = define('VerticalNav', { + layout: { + display: 'flex', + flexDirection: 'column', + gap: 4, + width: 240, + }, + + parts: { + NavItem: { + base: 'a', + layout: { + padding: '12px 16px', + display: 'flex', + alignItems: 'center', + gap: 12, + }, + look: { + background: 'transparent', + borderRadius: 8, + color: '#6b7280', + fontSize: 14, + fontWeight: 500, + textDecoration: 'none', + cursor: 'pointer', + transition: 'all 0.2s ease', + }, + states: { + ':hover': { + look: { + background: '#f3f4f6', + color: '#111827', + } + } + } + }, + Icon: { + layout: { + width: 20, + height: 20, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + look: { + fontSize: 18, + } + } + }, + + variants: { + active: { + parts: { + NavItem: { + look: { + background: '#eff6ff', + color: '#3b82f6', + }, + states: { + ':hover': { + look: { + background: '#dbeafe', + color: '#2563eb', + } + } + } + } + } + } + }, + + render({ props, parts: { Root, NavItem, Icon } }) { + return ( + + {props.items?.map((item: any) => ( + + {item.icon && {item.icon}} + {item.label} + + ))} + + ) + } +}) + +const Breadcrumbs = define('Breadcrumbs', { + layout: { + display: 'flex', + alignItems: 'center', + gap: 8, + flexWrap: 'wrap', + }, + + parts: { + Item: { + base: 'a', + look: { + color: '#6b7280', + fontSize: 14, + textDecoration: 'none', + transition: 'color 0.2s ease', + }, + states: { + ':hover': { + look: { + color: '#3b82f6', + } + } + } + }, + Separator: { + look: { + color: '#d1d5db', + fontSize: 14, + userSelect: 'none', + } + }, + Current: { + look: { + color: '#111827', + fontSize: 14, + fontWeight: 500, + } + } + }, + + render({ props, parts: { Root, Item, Separator, Current } }) { + return ( + + {props.items?.map((item: any, index: number) => ( + <> + {index === props.items.length - 1 ? ( + {item.label} + ) : ( + <> + + {item.label} + + / + + )} + + ))} + + ) + } +}) + +export const NavigationExamplesPage = () => ( + + + + + + + + + + + + + + + + + +) diff --git a/server.tsx b/server.tsx index 6a7918b..54f5e17 100644 --- a/server.tsx +++ b/server.tsx @@ -2,21 +2,31 @@ import { Hono } from 'hono' import { IndexPage } from './examples/index' import { ProfileExamplesPage } from './examples/profile' import { ButtonExamplesPage } from './examples/button' +import { NavigationExamplesPage } from './examples/navigation' +import { styles, stylesToCSS } from './src' const app = new Hono() -app.get('/', (c) => { +app.get('/', c => { return c.html() }) -app.get('/profile', (c) => { +app.get('/profile', c => { return c.html() }) -app.get('/buttons', (c) => { +app.get('/buttons', c => { return c.html() }) +app.get('/navigation', c => { + return c.html() +}) + +app.get('/styles', c => { + return c.text(stylesToCSS(styles)) +}) + export default { port: 3300, fetch: app.fetch,