@alexgorbatchev/shadcn 0.0.37 → 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +34 -0
  2. package/THIRD_PARTY_NOTICES.md +4 -0
  3. package/dist/{chunk-6grcm62s.js → chunk-1hj251b8.js} +1 -1
  4. package/dist/{chunk-r9qrb6b6.js → chunk-5bw5h08v.js} +1 -1
  5. package/dist/{chunk-kmvvw1vr.js → chunk-sb00e3gj.js} +1 -1
  6. package/dist/{chunk-f71469fs.js → chunk-v0va5w5c.js} +1 -1
  7. package/dist/components/data-grid/index.js +2 -2
  8. package/dist/components/gantt/index.js +2 -2
  9. package/dist/components/json-render/index.js +3 -3
  10. package/dist/components/virtual-data-grid/index.js +2 -2
  11. package/dist/index.js +3 -3
  12. package/dist/prototype.js +3665 -0
  13. package/dist/theme.css +20 -0
  14. package/licenses/commander-MIT.txt +22 -0
  15. package/llms/components/forms/NativeSelect.md +8 -0
  16. package/llms/setup.md +34 -0
  17. package/package.json +9 -3
  18. package/templates/prototype/AGENTS.md +23 -0
  19. package/templates/prototype/gitignore +5 -0
  20. package/templates/prototype/index.html +12 -0
  21. package/templates/prototype/justfile +18 -0
  22. package/templates/prototype/src/components/ScenarioContent.tsx +41 -0
  23. package/templates/prototype/src/components/Workbench.tsx +132 -0
  24. package/templates/prototype/src/main.tsx +12 -0
  25. package/templates/prototype/src/prototypes/dashboard/components/Dashboard.tsx +80 -0
  26. package/templates/prototype/src/prototypes/dashboard/data.ts +5 -0
  27. package/templates/prototype/src/prototypes/dashboard/prototype.ts +9 -0
  28. package/templates/prototype/src/prototypes/projects/components/Projects.tsx +151 -0
  29. package/templates/prototype/src/prototypes/projects/data.ts +5 -0
  30. package/templates/prototype/src/prototypes/projects/prototype.ts +9 -0
  31. package/templates/prototype/src/prototypes/settings/components/Settings.tsx +72 -0
  32. package/templates/prototype/src/prototypes/settings/prototype.ts +9 -0
  33. package/templates/prototype/src/styles.css +7 -0
  34. package/templates/prototype/src/types.ts +9 -0
  35. package/templates/prototype/tsconfig.json +13 -0
  36. package/templates/prototype/vite.config.ts +8 -0
package/dist/theme.css CHANGED
@@ -10,6 +10,11 @@
10
10
  --color-popover: var(--popover);
11
11
  --color-popover-foreground: var(--popover-foreground);
12
12
  --color-primary: var(--primary);
13
+ --color-chart-1: var(--chart-1);
14
+ --color-chart-2: var(--chart-2);
15
+ --color-chart-3: var(--chart-3);
16
+ --color-chart-4: var(--chart-4);
17
+ --color-chart-5: var(--chart-5);
13
18
  --color-primary-foreground: var(--primary-foreground);
14
19
  --color-secondary: var(--secondary);
15
20
  --color-secondary-foreground: var(--secondary-foreground);
@@ -104,6 +109,11 @@
104
109
  --success-foreground: #00210f;
105
110
  --warning: #ffb224;
106
111
  --warning-foreground: #231500;
112
+ --chart-1: #3987e5;
113
+ --chart-2: #d95926;
114
+ --chart-3: #199e70;
115
+ --chart-4: #c98500;
116
+ --chart-5: #d55181;
107
117
  --border: #353b44;
108
118
  --input: #6f7783;
109
119
  --ring: #ff5cd6;
@@ -138,6 +148,11 @@
138
148
  --success-foreground: #00210f;
139
149
  --warning: #ffb224;
140
150
  --warning-foreground: #231500;
151
+ --chart-1: #3987e5;
152
+ --chart-2: #d95926;
153
+ --chart-3: #199e70;
154
+ --chart-4: #c98500;
155
+ --chart-5: #d55181;
141
156
  --border: #353b44;
142
157
  --input: #6f7783;
143
158
  --ring: #ff5cd6;
@@ -172,6 +187,11 @@
172
187
  --success-foreground: #ffffff;
173
188
  --warning: #a35400;
174
189
  --warning-foreground: #ffffff;
190
+ --chart-1: #2a78d6;
191
+ --chart-2: #eb6834;
192
+ --chart-3: #1baf7a;
193
+ --chart-4: #eda100;
194
+ --chart-5: #e87ba4;
175
195
  --border: #c7ccd4;
176
196
  --input: #747c88;
177
197
  --ring: #b8168c;
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -69,6 +69,14 @@ Storybook CSF excerpts. Default args and render apply unless overridden. Local h
69
69
  }
70
70
  ```
71
71
 
72
+ ### CompactSmall
73
+
74
+ ```tsx
75
+ {
76
+ args: { density: "compact", size: "sm" }
77
+ }
78
+ ```
79
+
72
80
  ### Disabled
73
81
 
74
82
  ```tsx
package/llms/setup.md CHANGED
@@ -194,6 +194,40 @@ Override tokens after the theme imports. This example uses the existing success
194
194
  }
195
195
  ```
196
196
 
197
+ # Local React Prototypes
198
+
199
+ The package includes `shadcn-prototype`, a local runner for editable React mockups. Its generated workspace includes a preview host and complete dashboard, editable project directory, and settings recipes. Helpers and sample data are included; the recipes do not import Storybook files.
200
+
201
+ 1. Create a workspace using Bun:
202
+
203
+ ```sh
204
+ bunx --bun --package @alexgorbatchev/shadcn shadcn-prototype workspace create ./mockups
205
+ ```
206
+
207
+ 2. Install its declared dependencies and start the preview:
208
+
209
+ ```sh
210
+ cd mockups
211
+ bun install
212
+ bun node_modules/.bin/shadcn-prototype workspace start .
213
+ ```
214
+
215
+ 3. Edit a recipe under `src/prototypes/`, or copy a recipe folder and update its `prototype.ts`. The preview discovers each folder automatically. Use the workbench controls for scenarios, themes, density, viewport sizes, and reset. Open screen gives a direct URL to the canvas.
216
+
217
+ 4. Run `just check` in the generated workspace to typecheck and build. `dist/` contains the static site. Preview requires Bun; the `just` recipes require [just](https://just.systems).
218
+
219
+ The runner creates a new directory and rejects existing destinations. It does not install dependencies automatically. The generated manifest pins this package to the runner's version and declares the libraries used by the recipes and preview. The component package's dependency-installation contract is unchanged. State is in memory and resets when the canvas reloads; the recipes do not contact real services.
220
+
221
+ | Command | Options | Behavior |
222
+ | ------------------------------ | -------------------------------------------------- | ----------------------------------------------------------------------------------- |
223
+ | `workspace create <directory>` | `-h, --help` | Write a complete workspace to a new directory. |
224
+ | `workspace start [directory]` | `-p, --port <number>` (default 5173), `-h, --help` | Run the local preview; directory defaults to `.`. Port 0 chooses an available port. |
225
+ | `workspace build [directory]` | `-h, --help` | Build static output; directory defaults to `.`. |
226
+ | `skill` | `-h, --help` | Print the agent skill installation instructions. |
227
+ | Root | `-V, --version`, `-h, --help` | Show the package version or command tree. |
228
+
229
+ Use `AGENT=1` for concise agent output. Read the [prototype agent skill](https://github.com/alexgorbatchev/shadcn/blob/main/skills/shadcn-prototype/SKILL.md) for the complete workflow, URL parameters, environment, and error handling. The generated recipes are runnable consumer examples; the Storybook excerpts below remain component references.
230
+
197
231
  # LLM Documentation
198
232
 
199
233
  Storybook serves a generated `llms.txt` index at its site root, with linked setup instructions and a reference page for each story file. Pages contain public package imports, documented story controls, default args, and Storybook CSF examples with interaction tests omitted. The excerpts can depend on local helpers and fixtures; each page links to its full source. Story controls describe the configured controls, rather than the complete TypeScript props API.
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@alexgorbatchev/shadcn",
3
- "version": "0.0.37",
3
+ "version": "0.0.41",
4
4
  "description": "Sharp, monospace React components with compact and comfortable densities.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/alexgorbatchev/shadcn.git"
9
9
  },
10
+ "bin": {
11
+ "shadcn-prototype": "dist/prototype.js"
12
+ },
10
13
  "files": [
11
14
  "dist",
12
15
  "llms",
@@ -15,7 +18,8 @@
15
18
  "LICENSE",
16
19
  "THIRD_PARTY_NOTICES.md",
17
20
  "assistant-ui-catalog.json",
18
- "licenses"
21
+ "licenses",
22
+ "templates/prototype"
19
23
  ],
20
24
  "type": "module",
21
25
  "sideEffects": [
@@ -1050,12 +1054,13 @@
1050
1054
  "test": "vitest run --config .storybook/vitest.config.ts && bun run test:native && bun run test:package",
1051
1055
  "test:package": "bun run build && bun test scripts/__tests__ ./.storybook/__tests__/createStorybookViteConfig.test.ts",
1052
1056
  "test:preview": "bun test scripts/storybookPreview.test.ts",
1057
+ "test:prototype": "bun test --config=./cli/bunfig.toml --coverage cli && vitest run --config .storybook/vitest.prototype.config.ts --coverage",
1053
1058
  "test:native": "vitest run --config .storybook/vitest.native.config.ts",
1054
1059
  "test:coverage": "vitest run --config .storybook/vitest.coverage.config.ts --coverage",
1055
1060
  "test:contrast": "vitest run --config .storybook/vitest.contrast.config.ts",
1056
1061
  "build": "bun scripts/build.ts",
1057
1062
  "typecheck": "tsc --noEmit",
1058
- "lint": "oxlint --deny-warnings src .storybook scripts && oxfmt --check . && bun run lint:unused",
1063
+ "lint": "oxlint --deny-warnings src .storybook scripts cli templates/prototype/src templates/prototype/vite.config.ts && oxfmt --check . && bun run lint:unused",
1059
1064
  "lint:unused": "ts-unused check tsconfig.json",
1060
1065
  "storybook": "bun scripts/buildLlmDocs.ts && storybook dev --host 127.0.0.1 -p 6006 --no-open",
1061
1066
  "build-storybook": "bun scripts/buildLlmDocs.ts && storybook build",
@@ -1118,6 +1123,7 @@
1118
1123
  "clsx": "^2.1.1",
1119
1124
  "cmdk": "^1.1.1",
1120
1125
  "colorjs.io": "0.7.1",
1126
+ "commander": "^15.0.0",
1121
1127
  "cssesc": "3.0.0",
1122
1128
  "date-fns": "4.4.0",
1123
1129
  "diff": "9.0.0",
@@ -0,0 +1,23 @@
1
+ # Prototype workspace
2
+
3
+ Build interactive React screens using the installed `@alexgorbatchev/shadcn` package.
4
+
5
+ ## Commands
6
+
7
+ - Install: `just setup`
8
+ - Local preview: `just run`
9
+ - Agent preview: `just run-ai`
10
+ - Typecheck and production build: `just check`
11
+ - Static output: `just build` writes `dist/`
12
+
13
+ Read `node_modules/@alexgorbatchev/shadcn/llms.txt` before using components. Resolve its relative links from the package directory.
14
+
15
+ ## Authoring
16
+
17
+ - Each folder under `src/prototypes/` has a `prototype.ts` default export containing a title, description, and React component. The folder name is the prototype identifier. Copy a recipe folder to add a screen; Vite discovers it automatically.
18
+ - Keep components under the recipe's `components/` directory and sample data beside them. Shared host components and scenario rendering live in `src/components/`; all helpers are included locally.
19
+ - Compose the package's public components and semantic tokens. Install optional feature peers before importing their entry points. Keep reusable component capabilities in the library instead of overriding its internals.
20
+ - `PrototypeProps.scenario` selects populated, empty, loading, or error. Extend the example state handling to match the requested flow. Implement controls and state transitions; declare any simulated backend behavior in the delivery notes.
21
+ - The host renders each screen in an iframe so responsive styles and portals use its actual viewport. Open screen exposes a direct URL. Use one ThemeProvider per document; the host supplies theme and density to the canvas.
22
+ - Recipe state is in memory. Reset data, changing preview settings, or reloading the canvas restores the fixtures. Implement persistence only when required by the prototype.
23
+ - Validate primary interactions, form errors, empty/loading/error states, light/dark themes, both densities, and mobile sizing in a browser. Run `just check` before delivery and report any failures or unverified behavior.
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ .env.local
4
+ .tmp/
5
+ .cache/
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Prototype workbench</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,18 @@
1
+ default:
2
+ @just --list
3
+
4
+ setup:
5
+ bun install
6
+
7
+ run:
8
+ bun node_modules/.bin/shadcn-prototype workspace start .
9
+
10
+ run-ai:
11
+ AGENT=1 bun node_modules/.bin/shadcn-prototype workspace start .
12
+
13
+ build:
14
+ bun node_modules/.bin/shadcn-prototype workspace build .
15
+
16
+ check:
17
+ bun node_modules/.bin/tsc --noEmit
18
+ just build
@@ -0,0 +1,41 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ import {
3
+ Alert,
4
+ AlertDescription,
5
+ AlertTitle,
6
+ Empty,
7
+ EmptyHeader,
8
+ EmptyTitle,
9
+ EmptyDescription,
10
+ Spinner,
11
+ } from "@alexgorbatchev/shadcn";
12
+ import type { Scenario } from "../types";
13
+
14
+ type ScenarioContentProps = { scenario: Scenario; children: ReactNode };
15
+
16
+ export function ScenarioContent({ scenario, children }: ScenarioContentProps): ReactElement {
17
+ if (scenario === "loading")
18
+ return (
19
+ <div role="status" className="flex items-center gap-2">
20
+ <Spinner />
21
+ Loading sample data…
22
+ </div>
23
+ );
24
+ if (scenario === "error")
25
+ return (
26
+ <Alert variant="destructive">
27
+ <AlertTitle>Unable to load data</AlertTitle>
28
+ <AlertDescription>This is the error scenario. Choose Populated to recover.</AlertDescription>
29
+ </Alert>
30
+ );
31
+ if (scenario === "empty")
32
+ return (
33
+ <Empty>
34
+ <EmptyHeader>
35
+ <EmptyTitle>No data yet</EmptyTitle>
36
+ <EmptyDescription>This is the empty scenario. Choose Populated to explore the recipe.</EmptyDescription>
37
+ </EmptyHeader>
38
+ </Empty>
39
+ );
40
+ return <>{children}</>;
41
+ }
@@ -0,0 +1,132 @@
1
+ import { useState, type ReactElement } from "react";
2
+ import {
3
+ Button,
4
+ DensityProvider,
5
+ Field,
6
+ FieldGroup,
7
+ FieldLabel,
8
+ NativeSelect,
9
+ NativeSelectOption,
10
+ ThemeProvider,
11
+ } from "@alexgorbatchev/shadcn";
12
+ import type { PrototypeDefinition, Scenario } from "../types";
13
+
14
+ const prototypes = Object.entries(
15
+ import.meta.glob<PrototypeDefinition>("../prototypes/*/prototype.ts", { eager: true, import: "default" }),
16
+ ).map(([path, definition]) => ({ ...definition, id: path.split("/").at(-2) ?? "" }));
17
+
18
+ export function Workbench(): ReactElement {
19
+ const parameters = new URLSearchParams(window.location.search);
20
+ const [selected, setSelected] = useState(parameters.get("prototype") ?? "dashboard");
21
+ const [scenario, setScenario] = useState<Scenario>(() => {
22
+ const value = parameters.get("scenario");
23
+ return value === "empty" || value === "loading" || value === "error" ? value : "populated";
24
+ });
25
+ const [theme, setTheme] = useState<"light" | "dark">(parameters.get("theme") === "light" ? "light" : "dark");
26
+ const [density, setDensity] = useState<"comfortable" | "compact">(
27
+ parameters.get("density") === "compact" ? "compact" : "comfortable",
28
+ );
29
+ const [viewport, setViewport] = useState("responsive");
30
+ const [revision, setRevision] = useState(0);
31
+ const definition = prototypes.find((prototype) => prototype.id === selected);
32
+ const canvasParameters = new URLSearchParams({ canvas: "1", prototype: selected, scenario, theme, density });
33
+ const Component = definition?.component;
34
+ const isCanvas = parameters.get("canvas") === "1";
35
+
36
+ return (
37
+ <ThemeProvider forcedTheme={theme}>
38
+ <DensityProvider density={density}>
39
+ {isCanvas ? (
40
+ Component ? (
41
+ <Component scenario={scenario} />
42
+ ) : (
43
+ <p role="alert">Unknown prototype: {selected}</p>
44
+ )
45
+ ) : (
46
+ <div className="flex h-dvh flex-col" data-scroll="none">
47
+ <header className="shrink-0 border-b border-border p-4" data-scroll="none">
48
+ <h1 className="mb-3 text-lg font-semibold">Prototype workbench</h1>
49
+ <FieldGroup>
50
+ <div className="grid grid-cols-2 items-end gap-4 md:grid-cols-4 xl:grid-cols-7">
51
+ <Field>
52
+ <FieldLabel htmlFor="prototype">Prototype</FieldLabel>
53
+ <NativeSelect id="prototype" value={selected} onChange={(event) => setSelected(event.target.value)}>
54
+ {prototypes.map((prototype) => (
55
+ <NativeSelectOption key={prototype.id} value={prototype.id}>
56
+ {prototype.title}
57
+ </NativeSelectOption>
58
+ ))}
59
+ </NativeSelect>
60
+ </Field>
61
+ <Field>
62
+ <FieldLabel htmlFor="scenario">Scenario</FieldLabel>
63
+ <NativeSelect
64
+ id="scenario"
65
+ value={scenario}
66
+ onChange={(event) => {
67
+ const value = event.target.value;
68
+ if (value === "populated" || value === "empty" || value === "loading" || value === "error")
69
+ setScenario(value);
70
+ }}
71
+ >
72
+ <NativeSelectOption value="populated">Populated</NativeSelectOption>
73
+ <NativeSelectOption value="empty">Empty</NativeSelectOption>
74
+ <NativeSelectOption value="loading">Loading</NativeSelectOption>
75
+ <NativeSelectOption value="error">Error</NativeSelectOption>
76
+ </NativeSelect>
77
+ </Field>
78
+ <Field>
79
+ <FieldLabel htmlFor="theme">Theme</FieldLabel>
80
+ <NativeSelect
81
+ id="theme"
82
+ value={theme}
83
+ onChange={(event) => setTheme(event.target.value === "light" ? "light" : "dark")}
84
+ >
85
+ <NativeSelectOption value="dark">Dark</NativeSelectOption>
86
+ <NativeSelectOption value="light">Light</NativeSelectOption>
87
+ </NativeSelect>
88
+ </Field>
89
+ <Field>
90
+ <FieldLabel htmlFor="density">Density</FieldLabel>
91
+ <NativeSelect
92
+ id="density"
93
+ value={density}
94
+ onChange={(event) => setDensity(event.target.value === "compact" ? "compact" : "comfortable")}
95
+ >
96
+ <NativeSelectOption value="comfortable">Comfortable</NativeSelectOption>
97
+ <NativeSelectOption value="compact">Compact</NativeSelectOption>
98
+ </NativeSelect>
99
+ </Field>
100
+ <Field>
101
+ <FieldLabel htmlFor="viewport">Viewport</FieldLabel>
102
+ <NativeSelect id="viewport" value={viewport} onChange={(event) => setViewport(event.target.value)}>
103
+ <NativeSelectOption value="responsive">Responsive</NativeSelectOption>
104
+ <NativeSelectOption value="390">Mobile · 390px</NativeSelectOption>
105
+ <NativeSelectOption value="1280">Desktop · 1280px</NativeSelectOption>
106
+ </NativeSelect>
107
+ </Field>
108
+ <Button onClick={() => setRevision((value) => value + 1)}>Reset data</Button>
109
+ <a className="text-sm underline" href={`?${canvasParameters}`} target="_blank" rel="noreferrer">
110
+ Open screen
111
+ </a>
112
+ </div>
113
+ </FieldGroup>
114
+ <p className="mt-3 text-sm text-muted-foreground">
115
+ {definition?.description ?? "Choose a prototype"} · Reset or reload restores sample data.
116
+ </p>
117
+ </header>
118
+ <main className="min-h-0 flex-1 overflow-auto p-4" aria-label="Preview viewport">
119
+ <iframe
120
+ key={revision}
121
+ title="Prototype preview"
122
+ src={`?${canvasParameters}`}
123
+ className="mx-auto block h-full min-h-96 outline outline-border"
124
+ style={{ width: viewport === "responsive" ? "100%" : `${viewport}px` }}
125
+ />
126
+ </main>
127
+ </div>
128
+ )}
129
+ </DensityProvider>
130
+ </ThemeProvider>
131
+ );
132
+ }
@@ -0,0 +1,12 @@
1
+ import { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import { Workbench } from "./components/Workbench";
4
+ import "./styles.css";
5
+
6
+ const root = document.getElementById("root");
7
+ if (!root) throw new Error("Missing application root");
8
+ createRoot(root).render(
9
+ <StrictMode>
10
+ <Workbench />
11
+ </StrictMode>,
12
+ );
@@ -0,0 +1,80 @@
1
+ import { useState, type ReactElement } from "react";
2
+ import {
3
+ AppShell,
4
+ Badge,
5
+ Card,
6
+ CardHeader,
7
+ CardTitle,
8
+ CardDescription,
9
+ CardContent,
10
+ Field,
11
+ FieldGroup,
12
+ FieldLabel,
13
+ NativeSelect,
14
+ NativeSelectOption,
15
+ PageHeader,
16
+ StatCard,
17
+ Table,
18
+ TableBody,
19
+ TableCell,
20
+ TableHead,
21
+ TableHeader,
22
+ TableRow,
23
+ } from "@alexgorbatchev/shadcn";
24
+ import type { PrototypeProps } from "../../../types";
25
+ import { ScenarioContent } from "../../../components/ScenarioContent";
26
+ import { deliveries } from "../data";
27
+
28
+ export function Dashboard({ scenario }: PrototypeProps): ReactElement {
29
+ const [team, setTeam] = useState("All teams");
30
+ const visible = deliveries.filter((delivery) => team === "All teams" || delivery.team === team);
31
+ return (
32
+ <AppShell brand="Northstar" header="Overview" navigation={[]}>
33
+ <PageHeader title="Delivery overview" description="A shared view of the work moving this week." />
34
+ <ScenarioContent scenario={scenario}>
35
+ <FieldGroup>
36
+ <Field>
37
+ <FieldLabel htmlFor="team">Team</FieldLabel>
38
+ <NativeSelect id="team" value={team} onChange={(event) => setTeam(event.target.value)}>
39
+ <NativeSelectOption>All teams</NativeSelectOption>
40
+ <NativeSelectOption>Product</NativeSelectOption>
41
+ <NativeSelectOption>Engineering</NativeSelectOption>
42
+ </NativeSelect>
43
+ </Field>
44
+ </FieldGroup>
45
+ <div className="grid gap-4 sm:grid-cols-2">
46
+ <StatCard label="Active projects" value={visible.length} />
47
+ <StatCard label="Ready for review" value={visible.filter((delivery) => delivery.status === "Ready").length} />
48
+ </div>
49
+ <Card>
50
+ <CardHeader>
51
+ <CardTitle>Delivery queue</CardTitle>
52
+ <CardDescription>Projects for {team.toLowerCase()}.</CardDescription>
53
+ </CardHeader>
54
+ <CardContent>
55
+ <Table>
56
+ <TableHeader>
57
+ <TableRow>
58
+ <TableHead>Project</TableHead>
59
+ <TableHead>Team</TableHead>
60
+ <TableHead>Status</TableHead>
61
+ </TableRow>
62
+ </TableHeader>
63
+ <TableBody>
64
+ {visible.map((delivery) => (
65
+ <TableRow key={delivery.name}>
66
+ <TableCell>{delivery.name}</TableCell>
67
+ <TableCell>{delivery.team}</TableCell>
68
+ <TableCell>
69
+ <Badge variant="secondary">{delivery.status}</Badge>
70
+ </TableCell>
71
+ </TableRow>
72
+ ))}
73
+ </TableBody>
74
+ </Table>
75
+ </CardContent>
76
+ </Card>
77
+ </ScenarioContent>
78
+ </AppShell>
79
+ );
80
+ }
@@ -0,0 +1,5 @@
1
+ export const deliveries = [
2
+ { name: "Onboarding redesign", team: "Product", status: "In progress" },
3
+ { name: "Usage reporting", team: "Engineering", status: "Ready" },
4
+ { name: "Customer interviews", team: "Product", status: "Ready" },
5
+ ];
@@ -0,0 +1,9 @@
1
+ import type { PrototypeDefinition } from "../../types";
2
+ import { Dashboard } from "./components/Dashboard";
3
+
4
+ const prototype: PrototypeDefinition = {
5
+ title: "Dashboard",
6
+ description: "Review activity and filter a delivery dashboard.",
7
+ component: Dashboard,
8
+ };
9
+ export default prototype;