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: 2 additions & 0 deletions docs/storybook-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ reader-facing control you can click before changing product CSS.
| `Workspace/AskAgentPanel` SavedHistory | Continue a saved evidence-grounded conversation. | `aria-current`, `AskAgentPanel` |
| `Workspace/AskAgentPanel` Unavailable | Retry loading conversation history. | `ExceptionAlert`, `AskAgentPanel` |
| `Workspace/AskAgentPanel` Phone | Review the anchored flow at the phone viewport. | `AskAgentPanel` phone breakpoint |
| `Workspace/WorkspaceNav` Desktop | Switch workspace destinations and expose the current page. | `WorkspaceNav`, `aria-current` |
| `Workspace/WorkspaceNav` PhoneDrawer | Review the phone drawer navigation without the admin destination. | `WorkspaceNav` drawer variant |
| `Workspace/ChatPanel` SeededDump | Read seeded questions on a post, then ask a new question. | `ChatPanel` |
| `Workspace/ChatPanel` SavedHistory | Select a saved post conversation, then start a new conversation. | `aria-current`, `ChatPanel` |
| `Workspace/ChatPanel` Phone | Review post Ask history at the phone viewport. | `ChatPanel` phone breakpoint |
Expand Down
73 changes: 73 additions & 0 deletions frontend/src/components/WorkspaceNav.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useState } from "react";
import { expect, userEvent, within } from "storybook/test";
import "../App.css";
import {
WorkspaceNav,
type WorkspaceDestination,
type WorkspaceNavProps,
} from "./WorkspaceNav";

function InteractiveNav(args: WorkspaceNavProps) {
const [destination, setDestination] = useState<WorkspaceDestination>(
args.destination,
);
return (
<WorkspaceNav
{...args}
destination={destination}
onChange={(next) => {
setDestination(next);
args.onChange(next);
}}
/>
);
}

const meta = {
title: "Workspace/WorkspaceNav",
component: WorkspaceNav,
args: {
destination: "board",
onChange: () => undefined,
},
parameters: { layout: "padded" },
} satisfies Meta<typeof WorkspaceNav>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Desktop: Story = {
render: (args) => <InteractiveNav {...args} />,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.getByRole("button", { name: "Board" })).toHaveAttribute(
"aria-current",
"page",
);
await userEvent.click(canvas.getByRole("button", { name: "Ask Agent" }));
await expect(
canvas.getByRole("button", { name: "Ask Agent" }),
).toHaveAttribute("aria-current", "page");
},
};

export const PhoneDrawer: Story = {
args: {
drawer: true,
id: "workspace-drawer-story",
showAdmin: false,
},
render: (args) => <InteractiveNav {...args} />,
parameters: {
layout: "padded",
viewport: { defaultViewport: "mobile1" },
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(
canvas.getByRole("navigation", { name: "Workspace navigation" }),
).toHaveClass("workspace-gnb-drawer");
await expect(canvas.queryByRole("button", { name: "Admin" })).toBeNull();
},
};