Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ router: apps pass their own link component in through `UiProvider`.
Install a release by URL. No registry account or token is needed:

```sh
npm install --save-exact https://github.com/project-graphite/graphite-ui/releases/download/v0.3.0/project-graphite-ui-0.3.0.tgz
npm install --save-exact https://github.com/project-graphite/graphite-ui/releases/download/v0.4.0/project-graphite-ui-0.4.0.tgz
```

Load the theme after Tailwind. `@source` lets Tailwind see the classes the components use, and its
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@project-graphite/ui",
"version": "0.3.0",
"version": "0.4.0",
"description": "Project Graphite design tokens, theme and React components.",
"license": "MIT",
"repository": {
Expand Down
50 changes: 42 additions & 8 deletions preview/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
AppShell,
Avatar,
CodeInput,
ColorSwatches,
CommandPalette,
ConfirmDialog,
DatePicker,
Dialog,
EmptyState,
ErrorState,
Expand All @@ -20,13 +22,16 @@ import {
Pagination,
Popover,
Sidebar,
Select,
SuggestField,
SmoothImage,
SnackbarProvider,
Tabs,
TagChip,
tagColors,
TextAreaField,
TextField,
TimePicker,
Toggle,
timeAgo,
useCommandShortcut,
Expand Down Expand Up @@ -210,13 +215,35 @@ function Preview() {
<TextField hint="At least 12 characters." label="Password" type="password" />
<TextField error="Enter a handle." label="Handle" />
<TextAreaField label="Bio" rows={3} />
<label className="field-label">
Category
<select defaultValue="notes">
<option value="notes">Notes</option>
<option value="tasks">Tasks</option>
</select>
</label>
<div className="grid gap-4 sm:grid-cols-2">
<TextField label="Name" placeholder="Garden" />
<Select
defaultValue="notes"
label="Category"
options={[
{ value: 'notes', label: 'Notes' },
{ value: 'tasks', label: 'Tasks' },
{ value: 'events', label: 'Events' },
]}
/>
</div>
<Select
label="Time zone"
options={Intl.supportedValuesOf('timeZone').map((zone) => ({ value: zone, label: zone.replaceAll('_', ' ') }))}
placeholder="Choose a time zone"
searchable
/>
<SuggestField hint="Try “ne”." label="Service" suggestions={['Netflix', 'Nebula', 'Spotify', 'YouTube Premium']} />
<div className="grid gap-4 sm:grid-cols-2">
<DatePicker defaultValue="2026-10-14" label="Due date" />
<TimePicker defaultValue="09:00" label="Time" />
</div>
<div className="flex flex-wrap items-center gap-2">
<Select aria-label="Group by" defaultValue="status" options={[{ value: 'status', label: 'Status' }, { value: 'owner', label: 'Owner' }]} size="small" />
<DatePicker aria-label="Due" quiet size="small" />
<TimePicker aria-label="At" quiet size="small" />
</div>
<ColorSwatches defaultValue="teal" label="Colour" name="color" />
<GridListbox
defaultValue=""
emptyLabel="Any year"
Expand All @@ -228,7 +255,14 @@ function Preview() {
name="year"
/>
<Toggle checked={checked} description="Shown on your profile." label="Public profile" onChange={setChecked} />
<Toggle checked={false} disabled label="Disabled toggle" onChange={() => {}} />
<div className="panel-rows">
<Toggle checked={checked} description="Grouped toggles share one frame." label="Weekly summary" onChange={setChecked} />
<Toggle checked={false} disabled label="Disabled toggle" onChange={() => {}} />
</div>
<ul className="panel-rows">
<li className="panel-row">A framed list row</li>
<li className="panel-row">Rows share one padding</li>
</ul>
<p className="notice m-0">A notice explains something calmly.</p>
<p className="error-message m-0">Something went wrong. Try again.</p>
</div>
Expand Down
13 changes: 8 additions & 5 deletions src/components/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,21 @@ export function AppShell({
<aside className="sidebar-panel hidden md:block" data-collapsed={collapsed} id="app-sidebar">
{sidebar}
</aside>
<div className="min-w-0 flex-1">
<div className="flex min-w-0 flex-1 flex-col justify-between">
<main className="shell py-8 sm:py-14" id="content">
{children}
</main>
{footer}
</div>
</div>
) : (
<main className="shell flex-1 py-8 sm:py-14" id="content">
{children}
</main>
<>
<main className="shell flex-1 py-8 sm:py-14" id="content">
{children}
</main>
{footer}
</>
)}
{footer}
<nav aria-label="Main" className="tab-bar md:hidden" style={{ '--tab-count': tabs.length } as CSSProperties}>
{tabs.map((tab) =>
tab.loading ? (
Expand Down
39 changes: 39 additions & 0 deletions src/components/ColorSwatches.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { ReactNode } from 'react';
import { tagColors, type TagColor } from './TagChip.js';

export function ColorSwatches({
defaultValue,
label,
name,
onChange,
value,
}: {
defaultValue?: TagColor;
label: ReactNode;
name: string;
onChange?: (color: TagColor) => void;
value?: TagColor;
}) {
return (
<fieldset className="field-label m-0 border-0 p-0">
<legend className="mb-1.5 p-0">{label}</legend>
<div className="swatches">
{tagColors.map((color) => (
<label className="swatch" key={color} title={color}>
<input
aria-label={color}
checked={value === undefined ? undefined : value === color}
className="sr-only"
defaultChecked={value === undefined ? (defaultValue ?? 'gray') === color : undefined}
name={name}
onChange={() => onChange?.(color)}
type="radio"
value={color}
/>
<span aria-hidden="true" className={`swatch-dot tag-${color}`} />
</label>
))}
</div>
</fieldset>
);
}
Loading
Loading