chore: catch up Storybook preview, coverage, and story hygiene

Stories were throwing without AuthModal/CreateFlow providers, autodocs was a no-op, and several DS/create-flow screens had no stories.
This commit is contained in:
adilallo committed 2026-08-17 19:25:46 -06:00
1 parent 1983a67ffd
commit db1581337c
44 files changed
+1215 -932

No files matched your search

+8 -3
View File
@@ -1,4 +1,9 @@
import Button from "../../app/components/buttons/Button";
import {
BUTTON_PALETTE_OPTIONS,
BUTTON_TYPE_OPTIONS,
SIZE_OPTIONS,
} from "../../lib/propNormalization";
export default {
title: "Components/Buttons/Button",
@@ -15,17 +20,17 @@ export default {
argTypes: {
buttonType: {
control: { type: "select" },
options: ["filled", "outline", "ghost", "danger"],
options: [...BUTTON_TYPE_OPTIONS],
description: "The button type (Figma prop)",
},
palette: {
control: { type: "select" },
options: ["default", "inverse"],
options: [...BUTTON_PALETTE_OPTIONS],
description: "The button palette (Figma prop)",
},
size: {
control: { type: "select" },
options: ["xsmall", "small", "medium", "large", "xlarge"],
options: [...SIZE_OPTIONS],
description: "The size of the button",
},
disabled: {
+1 -1
View File
@@ -33,7 +33,7 @@ export const Default = {
export const InParagraph = {
render: () => (
<p className="max-w-md font-inter text-[14px] leading-[20px] text-[color:var(--color-content-default-primary,#fff)]">
<p className="max-w-md text-small-paragraph text-[var(--color-content-default-primary)]">
Share a bit more detail so the group can weigh in. You can always{" "}
<InlineTextButton onClick={() => {}}>expand this later</InlineTextButton>{" "}
if you need more room.
+4 -4
View File
@@ -37,10 +37,10 @@ export const Default = {
<Icon
name="number"
size={32}
className="text-[var(--color-content-default-brand-primary,#fefcc9)]"
className="text-[var(--color-content-default-brand-primary)]"
/>
</span>
<span className="w-full text-center font-inter text-[14px] font-medium leading-[18px] text-[var(--color-content-default-brand-primary,#fefcc9)]">
<span className="w-full text-center text-small-paragraph font-medium text-[var(--color-content-default-brand-primary)]">
Number
</span>
</Vertical>
@@ -54,10 +54,10 @@ export const Disabled = {
<Icon
name="number"
size={32}
className="text-[var(--color-content-default-brand-primary,#fefcc9)]"
className="text-[var(--color-content-default-brand-primary)]"
/>
</span>
<span className="w-full text-center font-inter text-[14px] font-medium leading-[18px] text-[var(--color-content-default-brand-primary,#fefcc9)]">
<span className="w-full text-center text-small-paragraph font-medium text-[var(--color-content-default-brand-primary)]">
Number
</span>
</Vertical>
+3 -7
View File
@@ -1,7 +1,5 @@
import React, { useState } from "react";
import AddCustomField from "../../app/components/controls/AddCustomField";
import { MessagesProvider } from "../../app/contexts/MessagesContext";
import messages from "../../messages/en/index";
/** Figma: Add Custom Field — node `20235:12994` (Community Rule System). */
export default {
@@ -9,11 +7,9 @@ export default {
component: AddCustomField,
decorators: [
(Story) => (
<MessagesProvider messages={messages}>
<div className="w-[min(100%,546px)] bg-[var(--color-surface-default-primary)] p-6">
<Story />
</div>
</MessagesProvider>
<div className="w-[min(100%,546px)] bg-[var(--color-surface-default-primary)] p-6">
<Story />
</div>
),
],
};
+8 -3
View File
@@ -1,4 +1,9 @@
import Chip from "../../app/components/controls/Chip";
import {
CHIP_PALETTE_OPTIONS,
CHIP_SIZE_OPTIONS,
CHIP_STATE_OPTIONS,
} from "../../lib/propNormalization";
export default {
title: "Components/Controls/Chip",
@@ -13,17 +18,17 @@ export default {
},
state: {
control: "select",
options: ["unselected", "selected", "disabled", "custom"],
options: [...CHIP_STATE_OPTIONS],
description: "Visual state of the chip",
},
palette: {
control: "select",
options: ["default", "inverse"],
options: [...CHIP_PALETTE_OPTIONS],
description: "Color palette of the chip",
},
size: {
control: "select",
options: ["s", "m"],
options: [...CHIP_SIZE_OPTIONS],
description: "Size of the chip",
},
disabled: {
+37 -34
View File
@@ -44,43 +44,46 @@ const Template = (args) => {
};
// Default story
export const Default = Template.bind({});
Default.args = {
label: "Default Select Input",
placeholder: "Choose an option",
state: "default",
export const Default = {
args: {
label: "Default Select Input",
placeholder: "Choose an option",
state: "default",
},
render: Template,
}; // States
export const Active = {
args: {
label: "Active State",
placeholder: "Choose an option",
state: "active",
},
render: Template,
};
// States
export const Active = Template.bind({});
Active.args = {
label: "Active State",
placeholder: "Choose an option",
state: "active",
export const Focus = {
args: {
label: "Focus State",
placeholder: "Choose an option",
state: "focus",
},
render: Template,
};
export const Focus = Template.bind({});
Focus.args = {
label: "Focus State",
placeholder: "Choose an option",
state: "focus",
export const Error = {
args: {
label: "Error State",
placeholder: "Choose an option",
error: true,
},
render: Template,
};
export const Error = Template.bind({});
Error.args = {
label: "Error State",
placeholder: "Choose an option",
error: true,
};
export const Disabled = Template.bind({});
Disabled.args = {
label: "Disabled State",
placeholder: "Choose an option",
disabled: true,
};
// Interactive example
export const Disabled = {
args: {
label: "Disabled State",
placeholder: "Choose an option",
disabled: true,
},
render: Template,
}; // Interactive example
export const Interactive = (args) => {
const [value, setValue] = useState("");
+26 -22
View File
@@ -39,32 +39,36 @@ export default {
const Template = (args) => <Switch {...args} />;
export const Default = Template.bind({});
Default.args = {
propSwitch: false,
text: "Switch label",
export const Default = {
args: {
propSwitch: false,
text: "Switch label",
},
render: Template,
};
export const Checked = Template.bind({});
Checked.args = {
propSwitch: true,
text: "Switch label",
export const Checked = {
args: {
propSwitch: true,
text: "Switch label",
},
render: Template,
};
export const Focus = Template.bind({});
Focus.args = {
propSwitch: false,
state: "focus",
text: "Switch label",
export const Focus = {
args: {
propSwitch: false,
state: "focus",
text: "Switch label",
},
render: Template,
};
export const FocusChecked = Template.bind({});
FocusChecked.args = {
propSwitch: true,
state: "focus",
text: "Switch label",
export const FocusChecked = {
args: {
propSwitch: true,
state: "focus",
text: "Switch label",
},
render: Template,
};
export const States = () => (
<div className="space-y-4">
<div className="space-y-2">
+71 -54
View File
@@ -1,5 +1,11 @@
import React from "react";
import TextArea from "../../app/components/controls/TextArea";
import {
INPUT_STATE_OPTIONS,
LABEL_VARIANT_OPTIONS,
SMALL_MEDIUM_LARGE_OPTIONS,
TEXT_AREA_APPEARANCE_OPTIONS,
} from "../../lib/propNormalization";
export default {
title: "Components/Controls/TextArea",
@@ -10,15 +16,19 @@ export default {
argTypes: {
size: {
control: { type: "select" },
options: ["small", "medium", "large"],
options: [...SMALL_MEDIUM_LARGE_OPTIONS],
},
labelVariant: {
control: { type: "select" },
options: ["default", "horizontal"],
options: [...LABEL_VARIANT_OPTIONS],
},
appearance: {
control: { type: "select" },
options: [...TEXT_AREA_APPEARANCE_OPTIONS],
},
state: {
control: { type: "select" },
options: ["default", "active", "hover", "focus", "error"],
options: [...INPUT_STATE_OPTIONS],
},
disabled: {
control: { type: "boolean" },
@@ -31,64 +41,71 @@ export default {
const Template = (args) => <TextArea {...args} />;
export const Default = Template.bind({});
Default.args = {
label: "Text Area",
placeholder: "Enter text...",
value: "",
export const Default = {
args: {
label: "Text Area",
placeholder: "Enter text...",
value: "",
},
render: Template,
};
export const WithValue = Template.bind({});
WithValue.args = {
label: "Text Area",
placeholder: "Enter text...",
value:
"This is some sample text content that demonstrates how the text area looks with content.",
export const WithValue = {
args: {
label: "Text Area",
placeholder: "Enter text...",
value:
"This is some sample text content that demonstrates how the text area looks with content.",
},
render: Template,
};
export const Small = Template.bind({});
Small.args = {
size: "small",
label: "Small Text Area",
placeholder: "Enter text...",
value: "",
export const Small = {
args: {
size: "small",
label: "Small Text Area",
placeholder: "Enter text...",
value: "",
},
render: Template,
};
export const Medium = Template.bind({});
Medium.args = {
size: "medium",
label: "Medium Text Area",
placeholder: "Enter text...",
value: "",
export const Medium = {
args: {
size: "medium",
label: "Medium Text Area",
placeholder: "Enter text...",
value: "",
},
render: Template,
};
export const Large = Template.bind({});
Large.args = {
size: "large",
label: "Large Text Area",
placeholder: "Enter text...",
value: "",
export const Large = {
args: {
size: "large",
label: "Large Text Area",
placeholder: "Enter text...",
value: "",
},
render: Template,
};
export const Embedded = Template.bind({});
Embedded.args = {
label: "Section content",
placeholder: "Enter text...",
value:
"Embedded appearance used in create-flow modals: borderless, darker grey block.",
appearance: "embedded",
size: "large",
rows: 4,
export const Embedded = {
args: {
label: "Section content",
placeholder: "Enter text...",
value:
"Embedded appearance used in create-flow modals: borderless, darker grey block.",
appearance: "embedded",
size: "large",
rows: 4,
},
render: Template,
};
export const HorizontalLabel = Template.bind({});
HorizontalLabel.args = {
labelVariant: "horizontal",
label: "Horizontal Label",
placeholder: "Enter text...",
value: "",
export const HorizontalLabel = {
args: {
labelVariant: "horizontal",
label: "Horizontal Label",
placeholder: "Enter text...",
value: "",
},
render: Template,
};
export const AllSizes = () => (
<div className="space-y-6">
<div className="space-y-4">
+75 -66
View File
@@ -1,5 +1,9 @@
import React from "react";
import TextInput from "../../app/components/controls/TextInput";
import {
INPUT_STATE_OPTIONS,
TEXT_INPUT_SIZE_OPTIONS,
} from "../../lib/propNormalization";
export default {
title: "Components/Controls/TextInput",
@@ -10,11 +14,11 @@ export default {
argTypes: {
inputSize: {
control: { type: "select" },
options: ["small", "medium", "Small", "Medium"],
options: [...TEXT_INPUT_SIZE_OPTIONS],
},
state: {
control: { type: "select" },
options: ["default", "active", "hover", "focus", "error", "disabled"],
options: [...INPUT_STATE_OPTIONS],
},
disabled: {
control: { type: "boolean" },
@@ -37,75 +41,80 @@ export default {
const Template = (args) => <TextInput {...args} />;
// Default story
export const Default = Template.bind({});
Default.args = {
label: "Default Text Input",
placeholder: "Enter text...",
inputSize: "medium",
state: "default",
export const Default = {
args: {
label: "Default Text Input",
placeholder: "Enter text...",
inputSize: "medium",
state: "default",
},
render: Template,
}; // Size variants
export const Small = {
args: {
label: "Small Text Input",
placeholder: "Small size",
inputSize: "small",
state: "default",
},
render: Template,
};
// Size variants
export const Small = Template.bind({});
Small.args = {
label: "Small Text Input",
placeholder: "Small size",
inputSize: "small",
state: "default",
export const Medium = {
args: {
label: "Medium Text Input",
placeholder: "Medium size",
inputSize: "medium",
state: "default",
},
render: Template,
}; // States
export const Active = {
args: {
label: "Active State",
placeholder: "Active input",
inputSize: "medium",
state: "active",
},
render: Template,
};
export const Medium = Template.bind({});
Medium.args = {
label: "Medium Text Input",
placeholder: "Medium size",
inputSize: "medium",
state: "default",
export const Hover = {
args: {
label: "Hover State",
placeholder: "Hover input",
inputSize: "medium",
state: "hover",
},
render: Template,
};
// States
export const Active = Template.bind({});
Active.args = {
label: "Active State",
placeholder: "Active input",
inputSize: "medium",
state: "active",
export const Focus = {
args: {
label: "Focus State",
placeholder: "Focused input",
inputSize: "medium",
state: "focus",
},
render: Template,
};
export const Hover = Template.bind({});
Hover.args = {
label: "Hover State",
placeholder: "Hover input",
inputSize: "medium",
state: "hover",
export const Error = {
args: {
label: "Error State",
placeholder: "Error input",
inputSize: "medium",
state: "default",
error: true,
},
render: Template,
};
export const Focus = Template.bind({});
Focus.args = {
label: "Focus State",
placeholder: "Focused input",
inputSize: "medium",
state: "focus",
};
export const Error = Template.bind({});
Error.args = {
label: "Error State",
placeholder: "Error input",
inputSize: "medium",
state: "default",
error: true,
};
export const Disabled = Template.bind({});
Disabled.args = {
label: "Disabled State",
placeholder: "Disabled input",
inputSize: "medium",
state: "default",
disabled: true,
};
// Interactive example
export const Disabled = {
args: {
label: "Disabled State",
placeholder: "Disabled input",
inputSize: "medium",
state: "default",
disabled: true,
},
render: Template,
}; // Interactive example
export const Interactive = (args) => {
const [value, setValue] = React.useState("");
+16 -14
View File
@@ -44,22 +44,24 @@ export const States = () => (
</div>
);
export const WithText = Template.bind({});
WithText.args = {
label: "Text Toggle",
checked: false,
showText: true,
text: "Toggle",
export const WithText = {
args: {
label: "Text Toggle",
checked: false,
showText: true,
text: "Toggle",
},
render: Template,
};
export const WithIcon = Template.bind({});
WithIcon.args = {
label: "Icon Toggle",
checked: false,
showIcon: true,
icon: "I",
export const WithIcon = {
args: {
label: "Icon Toggle",
checked: false,
showIcon: true,
icon: "I",
},
render: Template,
};
export const Interactive = () => {
const [checked, setChecked] = React.useState(false);
const [state, setState] = React.useState("default");
+43 -34
View File
@@ -1,5 +1,9 @@
import React from "react";
import ToggleGroup from "../../app/components/controls/ToggleGroup";
import {
STATE_OPTIONS,
TOGGLE_GROUP_POSITION_OPTIONS,
} from "../../lib/propNormalization";
export default {
title: "Components/Controls/ToggleGroup",
@@ -10,11 +14,11 @@ export default {
argTypes: {
position: {
control: { type: "select" },
options: ["left", "middle", "right"],
options: [...TOGGLE_GROUP_POSITION_OPTIONS],
},
state: {
control: { type: "select" },
options: ["default", "hover", "focus", "selected"],
options: [...STATE_OPTIONS],
},
showText: {
control: { type: "boolean" },
@@ -24,27 +28,30 @@ export default {
const Template = (args) => <ToggleGroup {...args}>Toggle Item</ToggleGroup>;
export const Default = Template.bind({});
Default.args = {
position: "left",
state: "default",
showText: true,
export const Default = {
args: {
position: "left",
state: "default",
showText: true,
},
render: Template,
};
export const Middle = Template.bind({});
Middle.args = {
position: "middle",
state: "default",
showText: true,
export const Middle = {
args: {
position: "middle",
state: "default",
showText: true,
},
render: Template,
};
export const Right = Template.bind({});
Right.args = {
position: "right",
state: "default",
showText: true,
export const Right = {
args: {
position: "right",
state: "default",
showText: true,
},
render: Template,
};
export const States = () => (
<div className="space-y-4">
<div className="space-y-2">
@@ -89,22 +96,24 @@ export const Positions = () => (
</div>
);
export const WithText = Template.bind({});
WithText.args = {
position: "left",
state: "default",
showText: true,
children: "Active Deals",
export const WithText = {
args: {
position: "left",
state: "default",
showText: true,
children: "Active Deals",
},
render: Template,
};
export const WithoutText = Template.bind({});
WithoutText.args = {
position: "left",
state: "default",
showText: false,
children: "☰",
export const WithoutText = {
args: {
position: "left",
state: "default",
showText: false,
children: "☰",
},
render: Template,
};
export const WithIcons = () => (
<div className="space-y-4">
<div className="space-y-2">
+69 -59
View File
@@ -34,87 +34,97 @@ export default {
const Template = (args) => <Upload {...args} />;
// Default story
export const Default = Template.bind({});
Default.args = {
label: "Upload",
active: true,
showHelpIcon: true,
};
// Active state
export const Active = Template.bind({});
Active.args = {
label: "Upload",
active: true,
showHelpIcon: true,
};
Active.parameters = {
docs: {
description: {
story:
"Upload component in active state with white button and black text.",
export const Default = {
args: {
label: "Upload",
active: true,
showHelpIcon: true,
},
render: Template,
}; // Active state
export const Active = {
args: {
label: "Upload",
active: true,
showHelpIcon: true,
},
parameters: {
docs: {
description: {
story:
"Upload component in active state with white button and black text.",
},
},
},
render: Template,
};
// Inactive state
export const Inactive = Template.bind({});
Inactive.args = {
label: "Upload",
active: false,
showHelpIcon: true,
};
Inactive.parameters = {
docs: {
description: {
story:
"Upload component in inactive state with dark button and gray text.",
export const Inactive = {
args: {
label: "Upload",
active: false,
showHelpIcon: true,
},
parameters: {
docs: {
description: {
story:
"Upload component in inactive state with dark button and gray text.",
},
},
},
render: Template,
};
// Without help icon
export const WithoutHelpIcon = Template.bind({});
WithoutHelpIcon.args = {
label: "Upload",
active: true,
showHelpIcon: false,
};
WithoutHelpIcon.parameters = {
docs: {
description: {
story: "Upload component without help icon.",
export const WithoutHelpIcon = {
args: {
label: "Upload",
active: true,
showHelpIcon: false,
},
parameters: {
docs: {
description: {
story: "Upload component without help icon.",
},
},
},
render: Template,
};
// Without label
export const WithoutLabel = Template.bind({});
WithoutLabel.args = {
active: true,
showHelpIcon: false,
};
WithoutLabel.parameters = {
docs: {
description: {
story: "Upload component without label.",
export const WithoutLabel = {
args: {
active: true,
showHelpIcon: false,
},
parameters: {
docs: {
description: {
story: "Upload component without label.",
},
},
},
render: Template,
};
// Custom label
export const CustomLabel = Template.bind({});
CustomLabel.args = {
label: "Upload Files",
active: true,
showHelpIcon: true,
};
CustomLabel.parameters = {
docs: {
description: {
story: "Upload component with custom label text.",
export const CustomLabel = {
args: {
label: "Upload Files",
active: true,
showHelpIcon: true,
},
parameters: {
docs: {
description: {
story: "Upload component with custom label text.",
},
},
},
render: Template,
};
// All states comparison
@@ -1,16 +1,19 @@
import React from "react";
import HeaderLockup from "../../app/components/type/HeaderLockup";
import InfoMessageBox from "../../app/components/controls/InfoMessageBox";
import {
HEADER_LOCKUP_JUSTIFICATION_OPTIONS,
HEADER_LOCKUP_SIZE_OPTIONS,
} from "../../lib/propNormalization";
/**
* Compose pattern used by create-flow “decision approaches” rail: headline lockup
* plus bordered checklist — no standalone wrapper component.
*/
export default {
title: "Components/Controls/Rail header (lockup + info box)",
title: "Create Flow/Rail header (lockup + info box)",
parameters: {
layout: "centered",
backgrounds: { default: "dark" },
docs: {
description: {
component:
@@ -18,14 +21,23 @@ export default {
},
},
},
argTypes: {
size: {
control: { type: "select" },
options: [...HEADER_LOCKUP_SIZE_OPTIONS],
},
justification: {
control: { type: "select" },
options: [...HEADER_LOCKUP_JUSTIFICATION_OPTIONS],
},
},
decorators: [
(Story) => (
<div className="bg-black p-8 max-w-lg w-full">
<div className="w-full max-w-lg bg-[var(--color-surface-default-primary)] p-8">
<Story />
</div>
),
],
tags: ["autodocs"],
};
const messageItems = [
+73
View File
@@ -0,0 +1,73 @@
import ListItem from "../../app/components/layout/ListItem";
import { ICON_NAME_OPTIONS } from "../../app/components/asset/icon";
export default {
title: "Components/Layout/ListItem",
component: ListItem,
parameters: {
layout: "centered",
docs: {
description: {
component:
"Icon + label menuitem row used in Popover export menus and CreateFlowTopNav action menus. Distinct from List / ListEntry data rows.",
},
},
},
argTypes: {
label: { control: { type: "text" } },
leadingIcon: {
control: { type: "select" },
options: [...ICON_NAME_OPTIONS],
},
showDivider: { control: { type: "boolean" } },
variant: {
control: { type: "select" },
options: ["default", "destructive"],
},
onClick: { action: "clicked" },
},
decorators: [
(Story) => (
<div className="w-[240px] bg-[var(--color-surface-default-primary)]">
<Story />
</div>
),
],
};
export const Default = {
args: {
label: "PDF",
leadingIcon: "picture_as_pdf",
showDivider: true,
},
};
export const ExportMenu = {
render: (args) => (
<div>
<ListItem
{...args}
label="PDF"
leadingIcon="picture_as_pdf"
showDivider
/>
<ListItem {...args} label="CSV" leadingIcon="csv" showDivider />
<ListItem
{...args}
label="Markdown"
leadingIcon="markdown_copy"
showDivider={false}
/>
</div>
),
};
export const Destructive = {
args: {
label: "Log out",
leadingIcon: "log_out",
showDivider: false,
variant: "destructive",
},
};
+109 -96
View File
@@ -42,119 +42,132 @@ const Template = (args) => {
);
};
export const ToastDefault = Template.bind({});
ToastDefault.args = {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "default",
type: "toast",
export const ToastDefault = {
args: {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "default",
type: "toast",
},
render: Template,
};
export const ToastPositive = Template.bind({});
ToastPositive.args = {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "positive",
type: "toast",
export const ToastPositive = {
args: {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "positive",
type: "toast",
},
render: Template,
};
export const ToastWarning = Template.bind({});
ToastWarning.args = {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "warning",
type: "toast",
export const ToastWarning = {
args: {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "warning",
type: "toast",
},
render: Template,
};
export const ToastDanger = Template.bind({});
ToastDanger.args = {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "danger",
type: "toast",
export const ToastDanger = {
args: {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "danger",
type: "toast",
},
render: Template,
};
export const Banner = Template.bind({});
Banner.args = {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "default",
type: "banner",
export const Banner = {
args: {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "default",
type: "banner",
},
render: Template,
};
export const BannerPositive = Template.bind({});
BannerPositive.args = {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "positive",
type: "banner",
export const BannerPositive = {
args: {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "positive",
type: "banner",
},
render: Template,
};
export const BannerWarning = Template.bind({});
BannerWarning.args = {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "warning",
type: "banner",
export const BannerWarning = {
args: {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "warning",
type: "banner",
},
render: Template,
};
export const BannerDanger = Template.bind({});
BannerDanger.args = {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "danger",
type: "banner",
export const BannerDanger = {
args: {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "danger",
type: "banner",
},
render: Template,
};
export const TitleOnly = Template.bind({});
TitleOnly.args = {
title: "Short alert banner message goes here",
status: "default",
type: "toast",
export const TitleOnly = {
args: {
title: "Short alert banner message goes here",
status: "default",
type: "toast",
},
render: Template,
};
export const ToastSmall = Template.bind({});
ToastSmall.args = {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "default",
type: "toast",
size: "s",
export const ToastSmall = {
args: {
title: "Short alert toast message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "default",
type: "toast",
size: "s",
},
render: Template,
};
export const BannerSmall = Template.bind({});
BannerSmall.args = {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "positive",
type: "banner",
size: "s",
export const BannerSmall = {
args: {
title: "Short alert banner message goes here",
description:
"Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
status: "positive",
type: "banner",
size: "s",
},
render: Template,
};
const NoDismissTemplate = (args) => (
<div className="p-8 max-w-[600px]">
<Alert {...args} />
</div>
);
export const BannerNoDismiss = NoDismissTemplate.bind({});
BannerNoDismiss.args = {
title: "Non-dismissible banner (no onClose)",
description: "Used when the message clears via navigation or parent state only.",
status: "danger",
type: "banner",
size: "s",
export const BannerNoDismiss = {
args: {
title: "Non-dismissible banner (no onClose)",
description:
"Used when the message clears via navigation or parent state only.",
status: "danger",
type: "banner",
size: "s",
},
render: NoDismissTemplate,
};
export const AllStatuses = () => {
const [visible, setVisible] = useState({
default: true,
+157 -147
View File
@@ -54,158 +54,168 @@ const Template = (args) => {
);
};
export const Default = Template.bind({});
Default.args = {
isOpen: true,
title: "What do you call your group's new policy?",
description: "You can also combine or add new approaches to the list",
children: (
<div className="space-y-4">
<TextInput label="Label" placeholder="Policy name" value="" />
<p className="text-[12px] text-[var(--color-content-default-tertiary)]">
0/48
</p>
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Next",
nextButtonDisabled: false,
export const Default = {
args: {
isOpen: true,
title: "What do you call your group's new policy?",
description: "You can also combine or add new approaches to the list",
children: (
<div className="space-y-4">
<TextInput label="Label" placeholder="Policy name" value="" />
<p className="text-[12px] text-[var(--color-content-default-tertiary)]">
0/48
</p>
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Next",
nextButtonDisabled: false,
},
render: Template,
};
export const WithStepper = Template.bind({});
WithStepper.args = {
isOpen: true,
title: "What do you call your group's new policy?",
description: "You can also combine or add new approaches to the list",
children: (
<div className="space-y-4">
<TextInput label="Label" placeholder="Policy name" value="" />
<p className="text-[12px] text-[var(--color-content-default-tertiary)]">
0/48
</p>
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Next",
nextButtonDisabled: false,
currentStep: 1,
totalSteps: 3,
export const WithStepper = {
args: {
isOpen: true,
title: "What do you call your group's new policy?",
description: "You can also combine or add new approaches to the list",
children: (
<div className="space-y-4">
<TextInput label="Label" placeholder="Policy name" value="" />
<p className="text-[12px] text-[var(--color-content-default-tertiary)]">
0/48
</p>
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Next",
nextButtonDisabled: false,
currentStep: 1,
totalSteps: 3,
},
render: Template,
};
export const Step2 = Template.bind({});
Step2.args = {
isOpen: true,
title: "How should conflicts be resolved?",
description: "You can also combine or add new approaches to the list",
children: (
<div className="space-y-4">
<TextInput label="Label" placeholder="Enter text" value="" />
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Next",
nextButtonDisabled: false,
currentStep: 2,
totalSteps: 3,
export const Step2 = {
args: {
isOpen: true,
title: "How should conflicts be resolved?",
description: "You can also combine or add new approaches to the list",
children: (
<div className="space-y-4">
<TextInput label="Label" placeholder="Enter text" value="" />
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Next",
nextButtonDisabled: false,
currentStep: 2,
totalSteps: 3,
},
render: Template,
};
export const Step3 = Template.bind({});
Step3.args = {
isOpen: true,
title: "Final step",
description: "Review your settings",
children: (
<div className="space-y-4">
<p className="text-[var(--color-content-default-primary)]">
Review your policy configuration
</p>
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Finish",
nextButtonDisabled: false,
currentStep: 3,
totalSteps: 3,
export const Step3 = {
args: {
isOpen: true,
title: "Final step",
description: "Review your settings",
children: (
<div className="space-y-4">
<p className="text-[var(--color-content-default-primary)]">
Review your policy configuration
</p>
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Finish",
nextButtonDisabled: false,
currentStep: 3,
totalSteps: 3,
},
render: Template,
};
export const WithCustomHeader = Template.bind({});
WithCustomHeader.args = {
isOpen: true,
headerContent: <div className="text-lg font-semibold">Custom header</div>,
children: (
<div className="space-y-4">
<p className="text-[var(--color-content-default-primary)]">
When headerContent is provided, the default title and description are
not shown.
</p>
</div>
),
showBackButton: false,
showNextButton: true,
nextButtonText: "Continue",
export const WithCustomHeader = {
args: {
isOpen: true,
headerContent: <div className="text-lg font-semibold">Custom header</div>,
children: (
<div className="space-y-4">
<p className="text-[var(--color-content-default-primary)]">
When headerContent is provided, the default title and description are
not shown.
</p>
</div>
),
showBackButton: false,
showNextButton: true,
nextButtonText: "Continue",
},
render: Template,
};
export const WithoutFooter = Template.bind({});
WithoutFooter.args = {
isOpen: true,
title: "Simple Create Dialog",
description: "This create dialog has no footer buttons",
children: (
<div className="space-y-4">
<p className="text-[var(--color-content-default-primary)]">
Modal content without footer
</p>
</div>
),
showBackButton: false,
showNextButton: false,
export const WithoutFooter = {
args: {
isOpen: true,
title: "Simple Create Dialog",
description: "This create dialog has no footer buttons",
children: (
<div className="space-y-4">
<p className="text-[var(--color-content-default-primary)]">
Modal content without footer
</p>
</div>
),
showBackButton: false,
showNextButton: false,
},
render: Template,
};
export const LoginYellowBackdrop = Template.bind({});
LoginYellowBackdrop.args = {
isOpen: true,
title: "Horizontalism",
description: "Edit or add to this description to describe what this value means to your community.",
backdropVariant: "blurredYellow",
children: (
<div className="space-y-4">
<p className="text-[var(--color-content-default-primary)]">
Core value detail body (yellow blurred overlay like Login).
</p>
</div>
),
showBackButton: false,
showNextButton: true,
nextButtonText: "Add Value",
nextButtonDisabled: false,
export const LoginYellowBackdrop = {
args: {
isOpen: true,
title: "Horizontalism",
description:
"Edit or add to this description to describe what this value means to your community.",
backdropVariant: "blurredYellow",
children: (
<div className="space-y-4">
<p className="text-[var(--color-content-default-primary)]">
Core value detail body (yellow blurred overlay like Login).
</p>
</div>
),
showBackButton: false,
showNextButton: true,
nextButtonText: "Add Value",
nextButtonDisabled: false,
},
render: Template,
};
export const NextButtonDisabled = Template.bind({});
NextButtonDisabled.args = {
isOpen: true,
title: "What do you call your group's new policy?",
description: "You can also combine or add new approaches to the list",
children: (
<div className="space-y-4">
<TextInput label="Label" placeholder="Policy name" value="" />
<p className="text-[12px] text-[var(--color-content-default-tertiary)]">
0/48
</p>
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Next",
nextButtonDisabled: true,
currentStep: 1,
totalSteps: 3,
export const NextButtonDisabled = {
args: {
isOpen: true,
title: "What do you call your group's new policy?",
description: "You can also combine or add new approaches to the list",
children: (
<div className="space-y-4">
<TextInput label="Label" placeholder="Policy name" value="" />
<p className="text-[12px] text-[var(--color-content-default-tertiary)]">
0/48
</p>
</div>
),
showBackButton: true,
showNextButton: true,
backButtonText: "Back",
nextButtonText: "Next",
nextButtonDisabled: true,
currentStep: 1,
totalSteps: 3,
},
render: Template,
};
+15 -12
View File
@@ -1,6 +1,9 @@
import React, { Suspense, useEffect } from "react";
import Login from "../../app/components/modals/Login";
import LoginForm from "../../app/components/modals/Login/LoginForm";
import messages from "../../messages/en/index";
const backToHome = messages.pages.login.backToHome;
/**
* Storybook runs outside Next.js request context; successful "Send link" needs fetch mocked
@@ -43,11 +46,11 @@ function FakeMarketingPageBehindOverlay({
return (
<div className="relative min-h-[100dvh] overflow-hidden">
<div
className="absolute inset-0 bg-gradient-to-br from-amber-100 via-white to-amber-50"
className="absolute inset-0 bg-[var(--color-surface-inverse-brand-primary)]"
aria-hidden
/>
<div className="relative z-0 px-8 py-16">
<p className="font-inter max-w-md text-lg text-neutral-800">
<p className="max-w-md text-large-paragraph text-[var(--color-content-invert-primary)]">
Placeholder page content — the login overlay portals above this and
uses backdrop blur (`blurredYellow`).
</p>
@@ -107,13 +110,13 @@ export const HeaderOverlayBlurred = {
belowCard={
<a
href="/"
className="font-inter font-normal text-[14px] leading-[20px] text-[var(--color-content-invert-tertiary,#2d2d2d)] text-center hover:opacity-90"
className="text-center text-small-paragraph text-[var(--color-content-invert-tertiary)] hover:opacity-90"
>
← Back to home
{backToHome}
</a>
}
>
<Suspense fallback={<p className="font-inter p-6">Loading…</p>}>
<Suspense fallback={<p className="p-6 text-small-paragraph">Loading…</p>}>
<LoginForm />
</Suspense>
</Login>
@@ -152,13 +155,13 @@ export const FullPageRouteSolid = {
belowCard={
<a
href="/"
className="font-inter font-normal text-[14px] leading-[20px] text-[var(--color-content-invert-tertiary,#2d2d2d)] text-center hover:opacity-90"
className="text-center text-small-paragraph text-[var(--color-content-invert-tertiary)] hover:opacity-90"
>
← Back to home
{backToHome}
</a>
}
>
<Suspense fallback={<p className="font-inter p-6">Loading…</p>}>
<Suspense fallback={<p className="p-6 text-small-paragraph">Loading…</p>}>
<LoginForm />
</Suspense>
</Login>
@@ -178,15 +181,15 @@ export const ModalChromeOnly = {
belowCard={
<a
href="/"
className="font-inter font-normal text-[14px] leading-[20px] text-[var(--color-content-invert-tertiary,#2d2d2d)] text-center hover:opacity-90"
className="text-center text-small-paragraph text-[var(--color-content-invert-tertiary)] hover:opacity-90"
>
← Back to home
{backToHome}
</a>
}
>
<p
id="login-modal-heading"
className="font-inter px-2 py-4 text-[var(--color-content-default-primary)]"
className="px-2 py-4 text-[var(--color-content-default-primary)]"
>
Placeholder body — use &quot;Header overlay&quot; or &quot;Full-page
route&quot; for the real flow.
@@ -215,7 +218,7 @@ export const FormOnly = {
],
render: () => (
<div className="mx-auto max-w-[560px] rounded-[20px] bg-[var(--color-surface-default-primary)] p-6 shadow-lg">
<Suspense fallback={<p className="font-inter">Loading…</p>}>
<Suspense fallback={<p className="text-small-paragraph">Loading…</p>}>
<LoginForm />
</Suspense>
</div>
+28 -24
View File
@@ -1,41 +1,45 @@
import React, { useState } from "react";
import Share from "../../app/components/modals/Share";
import { MessagesProvider } from "../../app/contexts/MessagesContext";
import messages from "../../messages/en/index";
/** Figma: Modal / Share — node 22073-30884 (Community Rule System). */
export default {
title: "modals/Share",
title: "Components/Modals/Share",
component: Share,
parameters: {
layout: "fullscreen",
docs: {
description: {
component:
"Share modal for published rules (copy link and channel actions).",
},
},
},
};
function ShareStoryHost() {
const [open, setOpen] = useState(true);
return (
<MessagesProvider messages={messages}>
<div className="min-h-[100dvh] bg-[var(--color-surface-inverse-brand-primary)] p-6">
<button
type="button"
className="rounded-md bg-white px-4 py-2 text-sm text-black"
onClick={() => setOpen(true)}
>
Open Share
</button>
<Share
isOpen={open}
onClose={() => setOpen(false)}
onCopyLink={() => {}}
onEmailShare={() => {}}
onSignalShare={() => {}}
onSlackShare={() => {}}
onDiscordShare={() => {}}
/>
</div>
</MessagesProvider>
<div className="min-h-[100dvh] bg-[var(--color-surface-inverse-brand-primary)] p-6">
<button
type="button"
className="rounded-md bg-[var(--color-surface-default-primary)] px-4 py-2 text-small-paragraph text-[var(--color-content-default-primary)]"
onClick={() => setOpen(true)}
>
Open Share
</button>
<Share
isOpen={open}
onClose={() => setOpen(false)}
onCopyLink={() => {}}
onEmailShare={() => {}}
onSignalShare={() => {}}
onSlackShare={() => {}}
onDiscordShare={() => {}}
/>
</div>
);
}
export const Default = {
name: "Modal / Share",
render: () => <ShareStoryHost />,
};
+33 -27
View File
@@ -1,6 +1,7 @@
import React from "react";
import Tooltip from "../../app/components/modals/Tooltip";
import Button from "../../app/components/buttons/Button";
import { TOOLTIP_POSITION_OPTIONS } from "../../lib/propNormalization";
export default {
title: "Components/Modals/Tooltip",
@@ -8,7 +9,7 @@ export default {
argTypes: {
position: {
control: { type: "select" },
options: ["top", "bottom"],
options: [...TOOLTIP_POSITION_OPTIONS],
},
disabled: {
control: { type: "boolean" },
@@ -29,37 +30,42 @@ const Template = (args) => (
</div>
);
export const Default = Template.bind({});
Default.args = {
text: "Tooltip text goes here",
position: "top",
disabled: false,
export const Default = {
args: {
text: "Tooltip text goes here",
position: "top",
disabled: false,
},
render: Template,
};
export const Top = Template.bind({});
Top.args = {
text: "Tooltip positioned at top",
position: "top",
export const Top = {
args: {
text: "Tooltip positioned at top",
position: "top",
},
render: Template,
};
export const Bottom = Template.bind({});
Bottom.args = {
text: "Tooltip positioned at bottom",
position: "bottom",
export const Bottom = {
args: {
text: "Tooltip positioned at bottom",
position: "bottom",
},
render: Template,
};
export const Disabled = Template.bind({});
Disabled.args = {
text: "This tooltip is disabled",
disabled: true,
export const Disabled = {
args: {
text: "This tooltip is disabled",
disabled: true,
},
render: Template,
};
export const LongText = Template.bind({});
LongText.args = {
text: "This is a longer tooltip text that demonstrates how the component handles multiple words and extended content",
position: "top",
export const LongText = {
args: {
text: "This is a longer tooltip text that demonstrates how the component handles multiple words and extended content",
position: "top",
},
render: Template,
};
export const WithIcon = () => (
<div className="p-16 flex items-center justify-center min-h-[200px]">
<Tooltip text="Tooltip with icon button" position="top">
+6 -2
View File
@@ -1,4 +1,8 @@
import MenuItem from "../../app/components/navigation/MenuItem";
import {
MENU_ITEM_MODE_OPTIONS,
MENU_ITEM_SIZE_OPTIONS,
} from "../../lib/propNormalization";
export default {
title: "Components/Navigation/MenuItem",
@@ -15,12 +19,12 @@ export default {
argTypes: {
mode: {
control: { type: "select" },
options: ["default", "inverse"],
options: [...MENU_ITEM_MODE_OPTIONS],
description: "The visual style mode of the menu item",
},
size: {
control: { type: "select" },
options: ["X Small", "Small", "Medium", "Large", "X Large"],
options: [...MENU_ITEM_SIZE_OPTIONS],
description: "The size of the menu item",
},
disabled: {
@@ -0,0 +1,9 @@
import { CommunityStructureSelectScreen } from "../../app/(app)/create/screens/select/CommunityStructureSelectScreen";
export default {
title: "Pages/Create Flow/Community structure",
component: CommunityStructureSelectScreen,
parameters: { layout: "fullscreen" },
};
export const Default = {};
@@ -0,0 +1,17 @@
import { ConflictManagementScreen } from "../../app/(app)/create/screens/card/ConflictManagementScreen";
export default {
title: "Pages/Create Flow/Conflict management",
component: ConflictManagementScreen,
parameters: {
layout: "fullscreen",
docs: {
description: {
component:
"Conflict management step: card stack, customize modals, responsive layout.",
},
},
},
};
export const Default = {};
+9
View File
@@ -0,0 +1,9 @@
import { CoreValuesSelectScreen } from "../../app/(app)/create/screens/select/CoreValuesSelectScreen";
export default {
title: "Pages/Create Flow/Core values",
component: CoreValuesSelectScreen,
parameters: { layout: "fullscreen" },
};
export const Default = {};
+1 -1
View File
@@ -1,7 +1,7 @@
import { InformationalScreen } from "../../app/(app)/create/screens/informational/InformationalScreen";
export default {
title: "Pages/Create/Informational",
title: "Pages/Create Flow/Informational",
component: InformationalScreen,
parameters: { layout: "fullscreen" },
};
@@ -0,0 +1,17 @@
import { MembershipMethodsScreen } from "../../app/(app)/create/screens/card/MembershipMethodsScreen";
export default {
title: "Pages/Create Flow/Membership methods",
component: MembershipMethodsScreen,
parameters: {
layout: "fullscreen",
docs: {
description: {
component:
"Membership methods step: card stack, customize modals, responsive layout.",
},
},
},
};
export const Default = {};
@@ -0,0 +1,67 @@
import { useEffect, useRef } from "react";
import { PublishedStakeholdersManagePanel } from "../../app/(app)/create/screens/select/PublishedStakeholdersManagePanel";
function StakeholdersFetchMock({ children }) {
const origRef = useRef(undefined);
if (origRef.current === undefined) {
origRef.current = globalThis.fetch;
globalThis.fetch = async (input, init) => {
const url =
typeof input === "string"
? input
: input instanceof URL
? input.href
: input.url;
if (url.includes("/stakeholders")) {
if (init?.method && init.method !== "GET") {
return new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
return new Response(JSON.stringify({ stakeholders: [] }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
return origRef.current(input, init);
};
}
useEffect(() => {
return () => {
if (origRef.current) {
globalThis.fetch = origRef.current;
}
};
}, []);
return children;
}
export default {
title: "Pages/Create Flow/Published stakeholders",
component: PublishedStakeholdersManagePanel,
parameters: {
layout: "fullscreen",
docs: {
description: {
component:
"Manage invites on a published rule. Fetch is stubbed empty in this story.",
},
},
},
decorators: [
(Story) => (
<StakeholdersFetchMock>
<div className="min-h-screen bg-[var(--color-surface-default-primary)] p-8">
<Story />
</div>
</StakeholdersFetchMock>
),
],
};
export const Default = {
args: {
ruleId: "storybook-rule",
},
};
+1 -1
View File
@@ -1,7 +1,7 @@
import { CommunityReviewScreen } from "../../app/(app)/create/screens/review/CommunityReviewScreen";
export default {
title: "Pages/Create/Review",
title: "Pages/Create Flow/Review",
component: CommunityReviewScreen,
parameters: { layout: "fullscreen" },
};
+1 -1
View File
@@ -1,7 +1,7 @@
import { CommunitySizeSelectScreen } from "../../app/(app)/create/screens/select/CommunitySizeSelectScreen";
export default {
title: "Pages/Create/CommunitySize",
title: "Pages/Create Flow/Community size",
component: CommunitySizeSelectScreen,
parameters: { layout: "fullscreen" },
};
+1 -1
View File
@@ -1,7 +1,7 @@
import { CreateFlowTextFieldScreen } from "../../app/(app)/create/screens/text/CreateFlowTextFieldScreen";
export default {
title: "Pages/Create/CommunityName",
title: "Pages/Create Flow/Community name",
component: CreateFlowTextFieldScreen,
parameters: { layout: "fullscreen" },
};
+1 -1
View File
@@ -1,7 +1,7 @@
import { CommunityUploadScreen } from "../../app/(app)/create/screens/upload/CommunityUploadScreen";
export default {
title: "Pages/Create/CommunityUpload",
title: "Pages/Create Flow/Community upload",
component: CommunityUploadScreen,
parameters: { layout: "fullscreen" },
};
+38
View File
@@ -0,0 +1,38 @@
import FaqAccordion from "../../app/components/sections/Accordion";
import about from "../../messages/en/pages/about.json";
export default {
title: "Components/Sections/Accordion",
component: FaqAccordion,
parameters: {
layout: "fullscreen",
docs: {
description: {
component:
"About-page FAQ wrapper over layout/Accordion. Sizes: s below lg, m at lg, l at xl.",
},
},
},
argTypes: {
title: { control: { type: "text" } },
size: {
control: { type: "select" },
options: ["s", "m", "l"],
},
lgSize: {
control: { type: "select" },
options: ["s", "m", "l"],
},
xlSize: {
control: { type: "select" },
options: ["s", "m", "l"],
},
},
};
export const Default = {
args: {
title: about.faq.title,
items: about.faq.items,
},
};
@@ -1,248 +0,0 @@
import HeroBanner from "../../app/components/sections/HeroBanner";
import ContentLockup from "../../app/components/type/ContentLockup";
import HeroDecor from "../../app/components/sections/HeroBanner/HeroDecor";
export default {
title: "Systems/HeroBanner System",
parameters: {
layout: "fullscreen",
docs: {
description: {
component:
"Complete HeroBanner system showcasing all nested components working together. This demonstrates the full responsive behavior and component integration.",
},
},
},
tags: ["autodocs"],
};
export const CompleteSystem = {
render: () => (
<div className="min-h-screen bg-gray-50">
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
),
parameters: {
docs: {
description: {
story:
"Complete HeroBanner system with all components integrated. Resize your browser to see responsive behavior across all breakpoints.",
},
},
},
};
export const ComponentBreakdown = {
render: () => (
<div className="space-y-12 p-8">
<div>
<h2 className="text-2xl font-bold mb-6">HeroBanner Components</h2>
<div className="space-y-8">
<div>
<h3 className="text-lg font-semibold mb-4">
1. ContentLockup Component
</h3>
<div className="bg-[var(--color-surface-default-brand-primary)] p-8 rounded-lg">
<ContentLockup
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
</div>
<div>
<h3 className="text-lg font-semibold mb-4">
2. HeroDecor Component
</h3>
<div className="bg-[var(--color-surface-default-brand-primary)] p-8 rounded-lg relative overflow-hidden h-64">
<HeroDecor className="w-full h-full" />
<div className="relative z-10 text-white mt-4">
<p>Decoration appears behind content</p>
</div>
</div>
</div>
<div>
<h3 className="text-lg font-semibold mb-4">
3. Complete HeroBanner
</h3>
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
</div>
</div>
</div>
),
parameters: {
docs: {
description: {
story:
"Breakdown of individual components that make up the HeroBanner system, showing how they work together.",
},
},
},
};
export const ResponsiveBreakpoints = {
render: () => (
<div className="space-y-8 p-8">
<h2 className="text-2xl font-bold">Responsive Breakpoints</h2>
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold mb-2">XSmall (≤429px)</h3>
<div
className="border-2 border-gray-300 rounded-lg overflow-hidden"
style={{ width: "400px" }}
>
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Small (430px+)</h3>
<div
className="border-2 border-gray-300 rounded-lg overflow-hidden"
style={{ width: "600px" }}
>
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Medium (768px+)</h3>
<div
className="border-2 border-gray-300 rounded-lg overflow-hidden"
style={{ width: "900px" }}
>
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Large (1024px+)</h3>
<div
className="border-2 border-gray-300 rounded-lg overflow-hidden"
style={{ width: "1200px" }}
>
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">XLarge (1440px+)</h3>
<div
className="border-2 border-gray-300 rounded-lg overflow-hidden"
style={{ width: "1600px" }}
>
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
</div>
</div>
</div>
),
parameters: {
docs: {
description: {
story:
"HeroBanner system demonstrating responsive behavior at each breakpoint. Each container simulates a different screen size.",
},
},
},
};
export const ContentVariations = {
render: () => (
<div className="space-y-8 p-8">
<h2 className="text-2xl font-bold">Content Variations</h2>
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold mb-2">Standard Content</h3>
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Alternative Content</h3>
<HeroBanner
title="Build"
subtitle="better communities"
description="Create operating manuals that help your community thrive and make decisions together."
ctaText="Get started today"
ctaHref="/signup"
/>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Long Description</h3>
<HeroBanner
title="Collaborate"
subtitle="with clarity"
description="Help your community make important decisions in a way that reflects its unique values. Our platform provides the tools and frameworks needed to build successful, sustainable communities that can navigate complex challenges together."
ctaText="Learn how Community Rule works"
ctaHref="#"
/>
</div>
</div>
</div>
),
parameters: {
docs: {
description: {
story:
"HeroBanner system with different content variations to demonstrate flexibility and content handling.",
},
},
},
};
+2 -1
View File
@@ -1,4 +1,5 @@
import QuoteBlock from "../../app/components/sections/QuoteBlock";
import { QUOTE_BLOCK_VARIANT_OPTIONS } from "../../lib/propNormalization";
export default {
title: "Components/Sections/QuoteBlock",
@@ -34,7 +35,7 @@ A responsive quote section component that displays inspirational governance quot
argTypes: {
variant: {
control: { type: "select" },
options: ["compact", "standard", "extended", "statement"],
options: [...QUOTE_BLOCK_VARIANT_OPTIONS],
description: "Layout variant for different use cases",
},
quote: {
+6 -6
View File
@@ -1,23 +1,23 @@
import HeaderLockup from "../../app/components/type/HeaderLockup";
import {
HEADER_LOCKUP_JUSTIFICATION_OPTIONS,
HEADER_LOCKUP_SIZE_OPTIONS,
} from "../../lib/propNormalization";
export default {
title: "Components/Type/HeaderLockup",
component: HeaderLockup,
parameters: {
layout: "centered",
backgrounds: {
default: "dark",
values: [{ name: "dark", value: "#000000" }],
},
},
argTypes: {
justification: {
control: { type: "select" },
options: ["left", "center", "Left", "Center"],
options: [...HEADER_LOCKUP_JUSTIFICATION_OPTIONS],
},
size: {
control: { type: "select" },
options: ["L", "M", "l", "m"],
options: [...HEADER_LOCKUP_SIZE_OPTIONS],
},
},
};
+77
View File
@@ -0,0 +1,77 @@
import InputLabel from "../../app/components/type/InputLabel";
import {
INPUT_LABEL_PALETTE_OPTIONS,
INPUT_LABEL_SIZE_OPTIONS,
} from "../../lib/propNormalization";
export default {
title: "Components/Type/InputLabel",
component: InputLabel,
parameters: {
layout: "centered",
docs: {
description: {
component:
"Reusable form-input label with optional asterisk, help icon, and helper text. Figma Utility / InputLabel; canonical code under type/.",
},
},
},
argTypes: {
label: { control: { type: "text" } },
helpIcon: { control: { type: "boolean" } },
asterisk: { control: { type: "boolean" } },
helperText: { control: { type: "boolean" } },
size: {
control: { type: "select" },
options: [...INPUT_LABEL_SIZE_OPTIONS],
},
palette: {
control: { type: "select" },
options: [...INPUT_LABEL_PALETTE_OPTIONS],
},
},
};
export const Default = {
args: {
label: "Community name",
size: "s",
palette: "default",
},
};
export const Required = {
args: {
label: "Community name",
asterisk: true,
size: "s",
palette: "default",
},
};
export const WithHelp = {
args: {
label: "Applicable scope",
helpIcon: true,
size: "m",
palette: "default",
},
};
export const OptionalHelper = {
args: {
label: "Website",
helperText: true,
size: "s",
palette: "default",
},
};
export const Inverse = {
args: {
label: "Community name",
asterisk: true,
size: "m",
palette: "inverse",
},
};
+2 -5
View File
@@ -1,19 +1,16 @@
import NumberedList from "../../app/components/type/NumberedList";
import { NUMBERED_LIST_SIZE_OPTIONS } from "../../lib/propNormalization";
export default {
title: "Components/Type/NumberedList",
component: NumberedList,
parameters: {
layout: "centered",
backgrounds: {
default: "dark",
values: [{ name: "dark", value: "#000000" }],
},
},
argTypes: {
size: {
control: { type: "select" },
options: ["M", "S", "m", "s"],
options: [...NUMBERED_LIST_SIZE_OPTIONS],
},
},
};