diff --git a/stories/navigation/Link.stories.js b/stories/navigation/Link.stories.js
new file mode 100644
index 0000000..d95000e
--- /dev/null
+++ b/stories/navigation/Link.stories.js
@@ -0,0 +1,106 @@
+import Link from "../../app/components/navigation/Link";
+
+export default {
+ title: "Components/Navigation/Link",
+ component: Link,
+ parameters: {
+ layout: "centered",
+ docs: {
+ description: {
+ component:
+ "Figma Navigation / Link (21861:21428). States are CSS-only (hover, focus-visible, active).",
+ },
+ },
+ },
+ argTypes: {
+ type: {
+ control: { type: "select" },
+ options: ["primary", "secondary"],
+ },
+ variant: {
+ control: { type: "select" },
+ options: ["default", "paragraph"],
+ },
+ theme: {
+ control: { type: "select" },
+ options: ["light", "dark"],
+ },
+ leadingIcon: { control: { type: "boolean" } },
+ trailingIcon: { control: { type: "boolean" } },
+ href: { control: { type: "text" } },
+ children: { control: { type: "text" } },
+ },
+ tags: ["autodocs"],
+};
+
+export const Default = {
+ args: {
+ children: "Link Text",
+ type: "primary",
+ variant: "paragraph",
+ theme: "light",
+ href: "#",
+ },
+};
+
+/**
+ * Static grid: type × variant × theme (use browser :hover / Tab for states).
+ */
+export const Matrix = {
+ render: () => (
+
+
+
+ Light background
+
+
+
+
+ Primary / default
+
+
+ Primary / paragraph
+
+
+ Secondary / default
+
+
+ Secondary / paragraph
+
+
+
+
+
+
+ Dark background
+
+
+
+
+ Primary / default
+
+
+ Primary / paragraph
+
+
+ Secondary / default
+
+
+ Secondary / paragraph
+
+
+
+
+
+ ),
+};
+
+export const AsButton = {
+ args: {
+ children: "Action",
+ type: "primary",
+ variant: "paragraph",
+ theme: "light",
+ onClick: () => {},
+ },
+};
diff --git a/stories/pages/CompletedPage.stories.js b/stories/pages/CompletedPage.stories.js
index 3e3ce00..8da1e99 100644
--- a/stories/pages/CompletedPage.stories.js
+++ b/stories/pages/CompletedPage.stories.js
@@ -1,4 +1,24 @@
import { CompletedScreen } from "../../app/(app)/create/screens/completed/CompletedScreen";
+import { CREATE_FLOW_LAST_PUBLISHED_KEY } from "../../lib/create/lastPublishedRule";
+
+const storySessionFixture = {
+ id: "story-rule",
+ title: "Storybook Community Rule",
+ summary: "Preview copy loaded from sessionStorage for this story.",
+ document: {
+ sections: [
+ {
+ categoryName: "Values",
+ entries: [
+ {
+ title: "Preview value",
+ body: "Example body so the document column is populated in Storybook.",
+ },
+ ],
+ },
+ ],
+ },
+};
export default {
title: "Pages/Create Flow/Completed",
@@ -13,11 +33,19 @@ export default {
},
},
decorators: [
- (Story) => (
-
-
-
- ),
+ (Story) => {
+ if (typeof sessionStorage !== "undefined") {
+ sessionStorage.setItem(
+ CREATE_FLOW_LAST_PUBLISHED_KEY,
+ JSON.stringify(storySessionFixture),
+ );
+ }
+ return (
+
+
+
+ );
+ },
],
tags: ["autodocs"],
};
diff --git a/stories/utility/Divider.stories.js b/stories/utility/Divider.stories.js
new file mode 100644
index 0000000..47e9988
--- /dev/null
+++ b/stories/utility/Divider.stories.js
@@ -0,0 +1,74 @@
+import Divider from "../../app/components/utility/Divider";
+
+export default {
+ title: "Components/Utility/Divider",
+ component: Divider,
+ parameters: {
+ layout: "padded",
+ backgrounds: { default: "dark" },
+ docs: {
+ description: {
+ component:
+ "Figma Utility / Divider (450:1941). Content uses border secondary; Menu uses tertiary. Horizontal and vertical orientations.",
+ },
+ },
+ },
+ argTypes: {
+ orientation: { control: { type: "select" }, options: ["horizontal", "vertical"] },
+ type: { control: { type: "select" }, options: ["content", "menu"] },
+ },
+ tags: ["autodocs"],
+};
+
+export const ContentHorizontal = {
+ args: {
+ type: "content",
+ orientation: "horizontal",
+ },
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+};
+
+export const MenuHorizontal = {
+ args: {
+ type: "menu",
+ orientation: "horizontal",
+ },
+ decorators: [ContentHorizontal.decorators[0]],
+};
+
+export const ContentVertical = {
+ args: {
+ type: "content",
+ orientation: "vertical",
+ },
+ render: (args) => (
+
+ ),
+};
+
+export const Matrix = {
+ render: () => (
+
+ ),
+};
diff --git a/tests/components/CompletedPage.test.tsx b/tests/components/CompletedPage.test.tsx
index cc30bd0..3e6178b 100644
--- a/tests/components/CompletedPage.test.tsx
+++ b/tests/components/CompletedPage.test.tsx
@@ -1,47 +1,73 @@
-import { describe, it, expect } from "vitest";
+import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { renderWithProviders as render, screen } from "../utils/test-utils";
import "@testing-library/jest-dom/vitest";
import { CompletedScreen } from "../../app/(app)/create/screens/completed/CompletedScreen";
+import { CREATE_FLOW_LAST_PUBLISHED_KEY } from "../../lib/create/lastPublishedRule";
+
+const storedRuleFixture = {
+ id: "rule-fixture-1",
+ title: "Fixture Community Rule",
+ summary: "A short summary for tests.",
+ document: {
+ sections: [
+ {
+ categoryName: "Values",
+ entries: [
+ {
+ title: "Fixture value title",
+ body: "Fixture value body text for the test document.",
+ },
+ ],
+ },
+ {
+ categoryName: "Communication",
+ entries: [
+ {
+ title: "Fixture channel",
+ body: "How we talk to each other.",
+ },
+ ],
+ },
+ ],
+ },
+};
describe("CompletedScreen", () => {
+ beforeEach(() => {
+ sessionStorage.removeItem(CREATE_FLOW_LAST_PUBLISHED_KEY);
+ });
+
+ afterEach(() => {
+ sessionStorage.removeItem(CREATE_FLOW_LAST_PUBLISHED_KEY);
+ });
+
it("renders without crashing", () => {
render(
);
expect(screen.getByRole("heading", { level: 1 })).toBeInTheDocument();
});
- it("renders HeaderLockup with expected title", () => {
+ it("shows no placeholder title or document when session is empty", () => {
+ render(
);
+ const h1 = screen.getByRole("heading", { level: 1 });
+ expect(h1.textContent).toBe("");
+ expect(screen.queryByText("Values")).not.toBeInTheDocument();
+ });
+
+ it("renders header and document from sessionStorage", () => {
+ sessionStorage.setItem(
+ CREATE_FLOW_LAST_PUBLISHED_KEY,
+ JSON.stringify(storedRuleFixture),
+ );
render(
);
expect(
screen.getByRole("heading", {
- name: "Mutual Aid Mondays",
+ name: "Fixture Community Rule",
}),
).toBeInTheDocument();
- });
-
- it("renders HeaderLockup with expected description", () => {
- render(
);
- expect(
- screen.getByText(
- /Mutual Aid Monday is a grassroots community in Denver, founded in November 2020 by Kelsang Virya, dedicated to supporting neighbors experiencing homelessness./i,
- ),
- ).toBeInTheDocument();
- });
-
- it("renders Community Rule document with section labels", () => {
- render(
);
+ expect(screen.getByText("A short summary for tests.")).toBeInTheDocument();
expect(screen.getByText("Values")).toBeInTheDocument();
expect(screen.getByText("Communication")).toBeInTheDocument();
- expect(screen.getByText("Membership")).toBeInTheDocument();
- expect(screen.getByText("Decision-making")).toBeInTheDocument();
- expect(screen.getByText("Conflict management")).toBeInTheDocument();
- });
-
- it("renders document entry titles", () => {
- render(
);
- expect(screen.getByText("Solidarity Forever")).toBeInTheDocument();
- expect(screen.getByText("Shared Leadership")).toBeInTheDocument();
- expect(screen.getByText("Organizing Offline")).toBeInTheDocument();
- expect(screen.getByText("Circular Food Systems")).toBeInTheDocument();
+ expect(screen.getByText("Fixture value title")).toBeInTheDocument();
});
it("renders toast alert when page loads", () => {
diff --git a/tests/components/Create.test.tsx b/tests/components/Create.test.tsx
index 10686bc..897d79d 100644
--- a/tests/components/Create.test.tsx
+++ b/tests/components/Create.test.tsx
@@ -59,11 +59,11 @@ describe("Create", () => {
}
});
- it("uses login yellow backdrop when backdropVariant is loginYellow", () => {
+ it("uses blurred yellow backdrop when backdropVariant is blurredYellow", () => {
renderWithProviders(
Header }
/>,
);
diff --git a/tests/components/Dialog.test.tsx b/tests/components/Dialog.test.tsx
new file mode 100644
index 0000000..bf7a94a
--- /dev/null
+++ b/tests/components/Dialog.test.tsx
@@ -0,0 +1,60 @@
+import React from "react";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { screen, fireEvent } from "@testing-library/react";
+import "@testing-library/jest-dom/vitest";
+import { renderWithProviders } from "../utils/test-utils";
+import Dialog from "../../app/components/modals/Dialog";
+
+type Props = React.ComponentProps