Skip to content

Add a comprehensive kitchen-sink Storybook for the design system - #486

Merged
barnaby merged 3 commits into
mainfrom
barnaby/kitchensink-storybook-v1
Jul 10, 2026
Merged

Add a comprehensive kitchen-sink Storybook for the design system#486
barnaby merged 3 commits into
mainfrom
barnaby/kitchensink-storybook-v1

Conversation

@barnaby

@barnaby barnaby commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a comprehensive kitchen-sink Storybook to apps/studio for examining the whole design system in one place. Dev-tooling only — no product runtime code changes; the real app and packages/design are untouched.

  • Support code + preview config (8b8cc6b): a mock app shell with an in-memory router, fixtures, seven route mocks, and four component galleries under src/kitchen-sink/lib; plus a working dark-mode toolbar decorator and viewport options in .storybook/preview.tsx (renamed from .ts).
  • Stories (09b284b): the flagship kitchen-sink/app interactive mock (live sidebar nav, menus, sheets, dialogs, toasts; 10 variants incl. Mobile/Tablet/SidebarLoading/LoadingStates/EmptyStates/ErrorState/Onboarding/DarkMode), page-state sub-stories (library, global-states, OAuth connect), and galleries for every primitive/form/overlay/content component plus an all-components page.

Test Coverage

@director.run/studio has no unit-test suite. Correctness was verified by storybook build (compiles every story) and live browser QA via Playwright: sidebar navigation, actions dropdown to settings sheet, mobile hamburger nav, and gallery rendering, with zero console errors beyond expected offline icon 404s.

Pre-Landing Review

  • Codex adversarial pass: NO MATERIAL FINDINGS.
  • Claude review: 4 informational findings, no correctness bugs. 2 auto-fixed — added a Toaster to the forms gallery so submit feedback renders in its standalone story, and the onboarding install dialog now reflects the clicked registry entry instead of always GitHub. 2 skipped with reason: the object-cast-to-Error is intentional (the story export is named Error, which shadows the constructor — matches the repo's existing login stories), and the mockTools() cast is load-bearing (matches playbook-detail.stories.tsx).

Design Review

Frontend diff, but it showcases the existing design system rather than introducing new UI. No new design patterns; components are used per their real APIs.

Plan Completion

Complete. All planned milestones delivered: preview config, types + fixtures, app shell plus seven routes, ten app variants, three page-state story files, four galleries and an all-components page. lint, typecheck, and build all green.

Notes

  • @director.run/studio is in the changeset ignore list and is private, so no changeset or version bump applies.
  • Follow-ups (out of scope): dark mode is wired but visually minimal until .dark design tokens are defined; three real pages nest LayoutView inside the root layout's (the mock reproduces this faithfully); not-found-page.tsx bypasses the design system.

Test plan

  • bun run lint — clean (all packages)
  • bun run typecheck — clean (all packages)
  • bun run build (studio) — vite + storybook build succeed
  • Live Storybook QA via Playwright — navigation, menus, sheets, mobile nav, galleries

🤖 Generated with Claude Code

barnaby and others added 2 commits July 9, 2026 21:09
Adds the mock app shell, in-memory router, fixtures, route mocks and
component galleries under src/kitchen-sink/lib, plus a working dark-mode
decorator and viewport options in the Storybook preview.
Interactive mock of the whole Studio app (live sidebar nav, in-memory
router, menus/sheets/dialogs/toasts) plus per-page-state sub-stories
(library, global states, OAuth connect) and galleries covering every
design-system primitive, form, overlay and content component.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive "kitchen-sink" mock application and Storybook stories for Director Studio, adding several routes, component galleries, and mock fixtures. The review feedback is highly constructive and focuses on improving code quality and robustness. Key recommendations include centralizing the duplicated delay helper function into a shared fixture file, enhancing the slugify helper to strip non-alphanumeric characters, checking for navigator.clipboard availability to prevent silent failures in non-secure contexts, and updating mock server connection info to ensure the "Logout" action is testable.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +1 to +2
import type { ConnectionInfo } from "@director.run/design/components/playbooks-clients/playbook-section-connect.tsx";
import type { PlaybookDetail } from "@director.run/design/components/types.ts";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The delay helper function is currently duplicated across seven different route files. Centralizing it in a shared location like fixtures.ts improves maintainability and keeps the codebase DRY.

import type { ConnectionInfo } from "@director.run/design/components/playbooks-clients/playbook-section-connect.tsx";
import type { PlaybookDetail } from "@director.run/design/components/types.ts";

export const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 385c1f2delay is now a single exported helper in lib/fixtures.ts, imported by all seven route files.

Comment on lines +132 to +135
status: "connected",
lastConnectedAt: new Date("2026-06-02T14:05:00.000Z"),
},
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The github server's connection info does not specify isAuthenticated: true. Since the TargetActionsDropdown component conditionally renders the "Logout" option only when isAuthenticated is true, adding this property to the fixture ensures that the "Logout" action is rendered and testable in the Storybook.

          connectionInfo: {
            status: "connected",
            lastConnectedAt: new Date("2026-06-02T14:05:00.000Z"),
            isAuthenticated: true,
          },

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — added isAuthenticated: true to the github server fixture so the target-detail dropdown renders (and lets you exercise) the Logout action.

Comment on lines +8 to +11
import { kitchenSinkConnectionInfo } from "../fixtures";
import type { KitchenSinkNavigate } from "../types";

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import the centralized delay helper from fixtures.ts instead of redefining it locally.

Suggested change
import { kitchenSinkConnectionInfo } from "../fixtures";
import type { KitchenSinkNavigate } from "../types";
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
import { kitchenSinkConnectionInfo, delay } from "../fixtures";
import type { KitchenSinkNavigate } from "../types";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 385c1f2delay is now exported once from lib/fixtures.ts and imported here instead of redefined locally.

Comment on lines +6 to +9
import { kitchenSinkApiKey } from "../fixtures";
import type { KitchenSinkPageState } from "../types";

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import the centralized delay helper from fixtures.ts instead of redefining it locally.

Suggested change
import { kitchenSinkApiKey } from "../fixtures";
import type { KitchenSinkPageState } from "../types";
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
import { kitchenSinkApiKey, delay } from "../fixtures";
import type { KitchenSinkPageState } from "../types";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 385c1f2delay is now exported once from lib/fixtures.ts and imported here instead of redefined locally.

Comment on lines +45 to +51
onCopyApiKey={(text) => {
void navigator.clipboard?.writeText(text);
toast({
title: "Copied",
description: "The API key was copied to your clipboard.",
});
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In environments where navigator.clipboard is not available (e.g., non-secure contexts or certain iframe setups in Storybook), calling navigator.clipboard?.writeText will fail silently, but the success toast will still be shown. Adding a check for navigator.clipboard prevents this false positive.

          onCopyApiKey={(text) => {
            if (!navigator.clipboard) {
              toast({
                title: "Copy failed",
                description: "Clipboard access is not available.",
              });
              return;
            }
            void navigator.clipboard.writeText(text);
            toast({
              title: "Copied",
              description: "The API key was copied to your clipboard.",
            });
          }}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — the copy handler now returns early when navigator.clipboard is unavailable, so the success toast only appears on an actual copy.

Comment on lines +17 to +20
import { useState } from "react";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import the centralized delay helper from fixtures.ts instead of redefining it locally.

Suggested change
import { useState } from "react";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
import { useState } from "react";
import { delay } from "../fixtures";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 385c1f2delay is now exported once from lib/fixtures.ts and imported here instead of redefined locally.

Comment on lines +33 to +36
import { useState } from "react";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import the centralized delay helper from fixtures.ts instead of redefining it locally.

Suggested change
import { useState } from "react";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
import { useState } from "react";
import { delay } from "../fixtures";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 385c1f2delay is now exported once from lib/fixtures.ts and imported here instead of redefined locally.

Comment on lines +38 to +39
const slugify = (value: string) =>
value.trim().toLowerCase().replace(/\s+/g, "-") || "prompt";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The slugify helper only replaces spaces with hyphens, which leaves special characters (like ?, #, /) intact. This can cause issues if the generated slug is used in routing or identifiers. Stripping non-alphanumeric characters makes the slug generation much more robust.

const slugify = (value: string) =>
  value
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9\s-]/g, "")
    .replace(/\s+/g, "-") || "prompt";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — slugify now lowercases, collapses any run of non-alphanumerics to a single hyphen, trims leading/trailing hyphens, and falls back to prompt.

Comment on lines +6 to +8
import { useState } from "react";

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import the centralized delay helper from fixtures.ts instead of redefining it locally.

Suggested change
import { useState } from "react";
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
import { useState } from "react";
import { delay } from "../fixtures";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 385c1f2delay is now exported once from lib/fixtures.ts and imported here instead of redefined locally.

Comment on lines +49 to +52
import { useState } from "react";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import the centralized delay helper from fixtures.ts instead of redefining it locally.

Suggested change
import { useState } from "react";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
import { useState } from "react";
import { delay } from "../fixtures";
import type { KitchenSinkNavigate, KitchenSinkPageState } from "../types";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 385c1f2delay is now exported once from lib/fixtures.ts and imported here instead of redefined locally.

- Centralize the delay helper in fixtures.ts (was duplicated across 7 routes)
- Give the github fixture isAuthenticated so the target Logout action shows
- Guard the settings clipboard copy before showing the success toast
- Harden slugify to strip non-alphanumerics
- Whitelist hackernews/modelcontextprotocol/summarise/triaging in cspell

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@barnaby

barnaby commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review @gemini-code-assist — all points addressed in 385c1f2: centralized the duplicated delay helper into fixtures.ts, added isAuthenticated to the github fixture (so the Logout action renders), guarded the clipboard copy before the success toast, and hardened slugify to strip non-alphanumerics. Also fixed the failing Spellcheck check by whitelisting the legitimate terms (hackernews, modelcontextprotocol, summarise, triaging).

@gemini-code-assist

Copy link
Copy Markdown

Thanks for the update, barnaby. The changes look solid and address the points raised during the review. I have no further comments on this PR.

@barnaby
barnaby merged commit 395cc78 into main Jul 10, 2026
5 checks passed
@barnaby
barnaby deleted the barnaby/kitchensink-storybook-v1 branch July 10, 2026 04:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant