design system token v0.6
This commit is contained in:
@@ -61,7 +61,7 @@
|
|||||||
| `color.dark.primary-foreground` | `#f9f9f7` | Dark primary foreground |
|
| `color.dark.primary-foreground` | `#f9f9f7` | Dark primary foreground |
|
||||||
| `color.dark.secondary` | `#575753` | Dark secondary |
|
| `color.dark.secondary` | `#575753` | Dark secondary |
|
||||||
| `color.dark.secondary-foreground` | `#f9f9f7` | Dark secondary text |
|
| `color.dark.secondary-foreground` | `#f9f9f7` | Dark secondary text |
|
||||||
| `color.dark.muted` | `#575753` | Dark muted |
|
| `color.dark.muted` | `#2f2f2c` | Dark muted — grey.8 (distinct from grey.7 border so outlines on bg-muted surfaces remain visible) |
|
||||||
| `color.dark.muted-foreground` | `#c4c4bd` | Dark muted text |
|
| `color.dark.muted-foreground` | `#c4c4bd` | Dark muted text |
|
||||||
| `color.dark.accent` | `#575753` | Dark accent/hover |
|
| `color.dark.accent` | `#575753` | Dark accent/hover |
|
||||||
| `color.dark.accent-foreground` | `#f9f9f7` | Dark accent text |
|
| `color.dark.accent-foreground` | `#f9f9f7` | Dark accent text |
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
--secondary: 87 87 83;
|
--secondary: 87 87 83;
|
||||||
/* Dark secondary text */
|
/* Dark secondary text */
|
||||||
--secondary-foreground: 249 249 247;
|
--secondary-foreground: 249 249 247;
|
||||||
/* Dark muted */
|
/* Dark muted — grey.8 (distinct from grey.7 border so outlines on bg-muted surfaces remain visible) */
|
||||||
--muted: 87 87 83;
|
--muted: 47 47 44;
|
||||||
/* Dark muted text */
|
/* Dark muted text */
|
||||||
--muted-foreground: 196 196 189;
|
--muted-foreground: 196 196 189;
|
||||||
/* Dark accent/hover */
|
/* Dark accent/hover */
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export const ColorTokens = {
|
|||||||
'dark.primary-foreground': '#f9f9f7',
|
'dark.primary-foreground': '#f9f9f7',
|
||||||
'dark.secondary': '#575753',
|
'dark.secondary': '#575753',
|
||||||
'dark.secondary-foreground': '#f9f9f7',
|
'dark.secondary-foreground': '#f9f9f7',
|
||||||
'dark.muted': '#575753',
|
'dark.muted': '#2f2f2c',
|
||||||
'dark.muted-foreground': '#c4c4bd',
|
'dark.muted-foreground': '#c4c4bd',
|
||||||
'dark.accent': '#575753',
|
'dark.accent': '#575753',
|
||||||
'dark.accent-foreground': '#f9f9f7',
|
'dark.accent-foreground': '#f9f9f7',
|
||||||
|
|||||||
63
components/ui/code.tsx
Normal file
63
components/ui/code.tsx
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import { cva, type VariantProps } from 'class-variance-authority'
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const codeVariants = cva(
|
||||||
|
'bg-muted border border-border font-mono text-foreground',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
inline: 'rounded text-xs px-1.5 py-0.5',
|
||||||
|
block: 'block rounded-md text-sm px-4 py-3 leading-relaxed break-all whitespace-pre-wrap',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'inline',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
interface CodeProps
|
||||||
|
extends React.ComponentProps<'code'>,
|
||||||
|
VariantProps<typeof codeVariants> {
|
||||||
|
/**
|
||||||
|
* Optional language hint for future syntax-highlighting support.
|
||||||
|
* Emitted as `data-language` and as a `language-{lang}` class so
|
||||||
|
* highlighters like Prism/Shiki can pick it up later.
|
||||||
|
*/
|
||||||
|
language?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function Code({
|
||||||
|
className,
|
||||||
|
variant,
|
||||||
|
language,
|
||||||
|
...props
|
||||||
|
}: CodeProps) {
|
||||||
|
const element = (
|
||||||
|
<code
|
||||||
|
data-slot="code"
|
||||||
|
data-language={language}
|
||||||
|
className={cn(
|
||||||
|
codeVariants({ variant, className }),
|
||||||
|
language && `language-${language}`,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
// For block variant, wrap in <pre> so copy-paste preserves whitespace
|
||||||
|
// and screen readers announce it as a code block.
|
||||||
|
if (variant === 'block') {
|
||||||
|
return (
|
||||||
|
<pre data-slot="code-block" className="not-prose">
|
||||||
|
{element}
|
||||||
|
</pre>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Code, codeVariants }
|
||||||
@@ -177,6 +177,15 @@ export const COMPONENT_CATALOG: ComponentSpec[] = [
|
|||||||
props: 'variant?: "default" | "outline"; size?: "default" | "sm" | "lg"; pressed?: boolean',
|
props: 'variant?: "default" | "outline"; size?: "default" | "sm" | "lg"; pressed?: boolean',
|
||||||
example: '<Toggle aria-label="Bold"><BoldIcon /></Toggle>',
|
example: '<Toggle aria-label="Bold"><BoldIcon /></Toggle>',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Code',
|
||||||
|
file: 'components/ui/code.tsx',
|
||||||
|
category: 'primitives',
|
||||||
|
exports: ['Code', 'codeVariants'],
|
||||||
|
description: 'Inline or block code snippet. Always use this instead of hand-rolling <code>/<pre> styling. Uses bg-muted + border-border so the outline stays visible in both light and dark modes. Block variant auto-wraps in <pre> for whitespace preservation and break-all for long commands.',
|
||||||
|
props: 'variant?: "inline" | "block"; language?: string (optional, for future syntax highlighting)',
|
||||||
|
example: '<p>Install with <Code>pnpm install</Code>.</p>\n\n<Code variant="block" language="bash">{`pnpm install\npnpm dev`}</Code>',
|
||||||
|
},
|
||||||
// ── Layout ──────────────────────────────────────────────────────────────
|
// ── Layout ──────────────────────────────────────────────────────────────
|
||||||
{
|
{
|
||||||
name: 'Card',
|
name: 'Card',
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ This project uses the **Greyhaven Design System**.
|
|||||||
|
|
||||||
## Component Summary
|
## Component Summary
|
||||||
|
|
||||||
37 components across 8 categories: primitives (10), layout (4), overlay (5), navigation (3), data (4), feedback (4), form (1), composition (6).
|
38 components across 8 categories: primitives (11), layout (4), overlay (5), navigation (3), data (4), feedback (4), form (1), composition (6).
|
||||||
|
|
||||||
For full component specs, props, and examples, refer to the SKILL.md file or use the MCP `get_component(name)` tool.
|
For full component specs, props, and examples, refer to the SKILL.md file or use the MCP `get_component(name)` tool.
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
> **Auto-generated** by `scripts/generate-skill.ts` -- DO NOT EDIT by hand.
|
> **Auto-generated** by `scripts/generate-skill.ts` -- DO NOT EDIT by hand.
|
||||||
> Re-generate: `pnpm skill:build`
|
> Re-generate: `pnpm skill:build`
|
||||||
>
|
>
|
||||||
> **Components**: 37 | **Style**: shadcn/ui "new-york"
|
> **Components**: 38 | **Style**: shadcn/ui "new-york"
|
||||||
> **Stack**: React 19, Radix UI, Tailwind CSS v4, CVA, tailwind-merge, clsx, Lucide icons
|
> **Stack**: React 19, Radix UI, Tailwind CSS v4, CVA, tailwind-merge, clsx, Lucide icons
|
||||||
> **Framework-agnostic**: No Next.js imports. Works with Vite, Remix, Astro, CRA, or any React setup.
|
> **Framework-agnostic**: No Next.js imports. Works with Vite, Remix, Astro, CRA, or any React setup.
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ Source of truth: `tokens/*.json` (W3C DTCG format).
|
|||||||
| `color.dark.primary-foreground` | `{color.primitive.off-white}` | Dark primary foreground |
|
| `color.dark.primary-foreground` | `{color.primitive.off-white}` | Dark primary foreground |
|
||||||
| `color.dark.secondary` | `{color.primitive.grey.7}` | Dark secondary |
|
| `color.dark.secondary` | `{color.primitive.grey.7}` | Dark secondary |
|
||||||
| `color.dark.secondary-foreground` | `{color.primitive.off-white}` | Dark secondary text |
|
| `color.dark.secondary-foreground` | `{color.primitive.off-white}` | Dark secondary text |
|
||||||
| `color.dark.muted` | `{color.primitive.grey.7}` | Dark muted |
|
| `color.dark.muted` | `{color.primitive.grey.8}` | Dark muted — grey.8 (distinct from grey.7 border so outlines on bg-muted surfaces remain visible) |
|
||||||
| `color.dark.muted-foreground` | `{color.primitive.grey.3}` | Dark muted text |
|
| `color.dark.muted-foreground` | `{color.primitive.grey.3}` | Dark muted text |
|
||||||
| `color.dark.accent` | `{color.primitive.grey.7}` | Dark accent/hover |
|
| `color.dark.accent` | `{color.primitive.grey.7}` | Dark accent/hover |
|
||||||
| `color.dark.accent-foreground` | `{color.primitive.off-white}` | Dark accent text |
|
| `color.dark.accent-foreground` | `{color.primitive.off-white}` | Dark accent text |
|
||||||
@@ -235,7 +235,7 @@ Source of truth: `tokens/*.json` (W3C DTCG format).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Component Catalog (37 components)
|
## Component Catalog (38 components)
|
||||||
|
|
||||||
All components live in `components/ui/`. Import with `@/components/ui/<name>`.
|
All components live in `components/ui/`. Import with `@/components/ui/<name>`.
|
||||||
|
|
||||||
@@ -341,6 +341,19 @@ All components live in `components/ui/`. Import with `@/components/ui/<name>`.
|
|||||||
<Toggle aria-label="Bold"><BoldIcon /></Toggle>
|
<Toggle aria-label="Bold"><BoldIcon /></Toggle>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Code
|
||||||
|
- **File**: `components/ui/code.tsx`
|
||||||
|
- **Exports**: `Code`, `codeVariants`
|
||||||
|
- **Description**: Inline or block code snippet. Always use this instead of hand-rolling <code>/<pre> styling. Uses bg-muted + border-border so the outline stays visible in both light and dark modes. Block variant auto-wraps in <pre> for whitespace preservation and break-all for long commands.
|
||||||
|
- **Props**: `variant?: "inline" | "block"; language?: string (optional, for future syntax highlighting)`
|
||||||
|
- **Example**:
|
||||||
|
```tsx
|
||||||
|
<p>Install with <Code>pnpm install</Code>.</p>
|
||||||
|
|
||||||
|
<Code variant="block" language="bash">{`pnpm install
|
||||||
|
pnpm dev`}</Code>
|
||||||
|
```
|
||||||
|
|
||||||
### Layout
|
### Layout
|
||||||
|
|
||||||
#### Card
|
#### Card
|
||||||
|
|||||||
90
stories/Primitives/Code.stories.tsx
Normal file
90
stories/Primitives/Code.stories.tsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
|
import { Code } from '@/components/ui/code'
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Primitives/Code',
|
||||||
|
component: Code,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: { layout: 'centered' },
|
||||||
|
argTypes: {
|
||||||
|
variant: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['inline', 'block'],
|
||||||
|
},
|
||||||
|
language: { control: 'text' },
|
||||||
|
},
|
||||||
|
} satisfies Meta<typeof Code>
|
||||||
|
|
||||||
|
export default meta
|
||||||
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
|
export const Inline: Story = {
|
||||||
|
args: {
|
||||||
|
variant: 'inline',
|
||||||
|
children: 'pnpm install',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InlineInSentence: Story = {
|
||||||
|
render: () => (
|
||||||
|
<p className="font-serif text-base leading-relaxed max-w-prose">
|
||||||
|
To get started, run <Code>pnpm install</Code> and then{' '}
|
||||||
|
<Code>pnpm dev</Code> to start the development server on{' '}
|
||||||
|
<Code>localhost:3000</Code>.
|
||||||
|
</p>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Block: Story = {
|
||||||
|
args: {
|
||||||
|
variant: 'block',
|
||||||
|
language: 'bash',
|
||||||
|
children: `pnpm install
|
||||||
|
pnpm dev
|
||||||
|
pnpm build`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BlockLongCommand: Story = {
|
||||||
|
args: {
|
||||||
|
variant: 'block',
|
||||||
|
language: 'bash',
|
||||||
|
children:
|
||||||
|
'curl -fsSL https://example.com/install.sh | bash -s -- --prefix=/usr/local --no-color --very-long-flag-that-should-wrap',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BlockTypescript: Story = {
|
||||||
|
args: {
|
||||||
|
variant: 'block',
|
||||||
|
language: 'ts',
|
||||||
|
children: `import { Code } from '@/components/ui/code'
|
||||||
|
|
||||||
|
export function Example() {
|
||||||
|
return <Code variant="block">Hello, world!</Code>
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AllVariants: Story = {
|
||||||
|
render: () => (
|
||||||
|
<div className="flex flex-col gap-6 max-w-2xl">
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-muted-foreground mb-2 font-sans">Inline</p>
|
||||||
|
<p className="font-serif">
|
||||||
|
Use <Code>cn()</Code> from <Code>@/lib/utils</Code> to merge Tailwind classes.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-muted-foreground mb-2 font-sans">Block</p>
|
||||||
|
<Code variant="block" language="bash">
|
||||||
|
{`# install and run
|
||||||
|
pnpm install
|
||||||
|
pnpm dev`}
|
||||||
|
</Code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}
|
||||||
@@ -287,8 +287,8 @@
|
|||||||
},
|
},
|
||||||
"muted": {
|
"muted": {
|
||||||
"$type": "color",
|
"$type": "color",
|
||||||
"$value": "{color.primitive.grey.7}",
|
"$value": "{color.primitive.grey.8}",
|
||||||
"$description": "Dark muted"
|
"$description": "Dark muted — grey.8 (distinct from grey.7 border so outlines on bg-muted surfaces remain visible)"
|
||||||
},
|
},
|
||||||
"muted-foreground": {
|
"muted-foreground": {
|
||||||
"$type": "color",
|
"$type": "color",
|
||||||
|
|||||||
Reference in New Issue
Block a user