@thewhatmatters/wmds 0.3.0 → 0.4.1
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.
- package/CHANGELOG.md +87 -0
- package/CONSUMING.md +9 -4
- package/dist/collapse.css +9 -1
- package/dist/colors.css +7 -0
- package/dist/components/atoms/Badge/Badge.d.ts +16 -4
- package/dist/components/atoms/Badge/Badge.d.ts.map +1 -1
- package/dist/components/atoms/Badge/Badge.js +54 -42
- package/dist/components/atoms/Badge/badgeStyles.d.ts +12 -2
- package/dist/components/atoms/Badge/badgeStyles.d.ts.map +1 -1
- package/dist/components/atoms/Badge/badgeStyles.js +24 -13
- package/dist/components/atoms/Button/Button.d.ts +11 -3
- package/dist/components/atoms/Button/Button.d.ts.map +1 -1
- package/dist/components/atoms/Button/Button.js +118 -98
- package/dist/components/atoms/Button/ButtonStatusButton.d.ts +3 -1
- package/dist/components/atoms/Button/ButtonStatusButton.d.ts.map +1 -1
- package/dist/components/atoms/Button/ButtonStatusButton.js +19 -18
- package/dist/components/atoms/Button/ButtonStatusContent.d.ts +7 -1
- package/dist/components/atoms/Button/ButtonStatusContent.d.ts.map +1 -1
- package/dist/components/atoms/Button/ButtonStatusContent.js +9 -6
- package/dist/components/atoms/Button/buttonStatusStyles.d.ts +5 -0
- package/dist/components/atoms/Button/buttonStatusStyles.d.ts.map +1 -1
- package/dist/components/atoms/Button/buttonStatusStyles.js +10 -10
- package/dist/components/atoms/Button/buttonStyles.d.ts +2 -0
- package/dist/components/atoms/Button/buttonStyles.d.ts.map +1 -1
- package/dist/components/atoms/Button/buttonStyles.js +12 -12
- package/dist/components/atoms/Checkbox/Checkbox.d.ts +7 -0
- package/dist/components/atoms/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/atoms/Checkbox/Checkbox.js +86 -69
- package/dist/components/atoms/Checkbox/checkboxStyles.d.ts +6 -0
- package/dist/components/atoms/Checkbox/checkboxStyles.d.ts.map +1 -1
- package/dist/components/atoms/Checkbox/checkboxStyles.js +11 -11
- package/dist/components/atoms/IconButton/IconButton.d.ts +5 -0
- package/dist/components/atoms/IconButton/IconButton.d.ts.map +1 -1
- package/dist/components/atoms/IconButton/IconButton.js +73 -68
- package/dist/components/atoms/IconButton/iconButtonStyles.d.ts +5 -0
- package/dist/components/atoms/IconButton/iconButtonStyles.d.ts.map +1 -1
- package/dist/components/atoms/IconButton/iconButtonStyles.js +4 -4
- package/dist/components/atoms/Kbd/useKbdChoiceKeys.d.ts +13 -4
- package/dist/components/atoms/Kbd/useKbdChoiceKeys.d.ts.map +1 -1
- package/dist/components/atoms/Kbd/useKbdChoiceKeys.js +32 -13
- package/dist/components/atoms/Prose/Prose.d.ts +23 -0
- package/dist/components/atoms/Prose/Prose.d.ts.map +1 -0
- package/dist/components/atoms/Prose/Prose.js +15 -0
- package/dist/components/atoms/Prose/proseStyles.d.ts +17 -0
- package/dist/components/atoms/Prose/proseStyles.d.ts.map +1 -0
- package/dist/components/atoms/Prose/proseStyles.js +16 -0
- package/dist/components/atoms/SectionCaption/SectionCaption.d.ts +26 -0
- package/dist/components/atoms/SectionCaption/SectionCaption.d.ts.map +1 -0
- package/dist/components/atoms/SectionCaption/SectionCaption.js +25 -0
- package/dist/components/atoms/SectionCaption/sectionCaptionStyles.d.ts +11 -0
- package/dist/components/atoms/SectionCaption/sectionCaptionStyles.d.ts.map +1 -0
- package/dist/components/atoms/SectionCaption/sectionCaptionStyles.js +12 -0
- package/dist/components/atoms/TextLink/TextLink.d.ts +10 -2
- package/dist/components/atoms/TextLink/TextLink.d.ts.map +1 -1
- package/dist/components/atoms/TextLink/TextLink.js +15 -15
- package/dist/components/atoms/TextLink/textLinkStyles.d.ts +13 -0
- package/dist/components/atoms/TextLink/textLinkStyles.d.ts.map +1 -1
- package/dist/components/atoms/TextLink/textLinkStyles.js +7 -3
- package/dist/components/molecules/Accordion/Accordion.d.ts +6 -1
- package/dist/components/molecules/Accordion/Accordion.d.ts.map +1 -1
- package/dist/components/molecules/Accordion/Accordion.js +57 -50
- package/dist/components/molecules/Accordion/accordionStyles.d.ts +9 -0
- package/dist/components/molecules/Accordion/accordionStyles.d.ts.map +1 -1
- package/dist/components/molecules/Accordion/accordionStyles.js +2 -2
- package/dist/components/molecules/CheckboxGroup/CheckboxGroupItem.d.ts +5 -1
- package/dist/components/molecules/CheckboxGroup/CheckboxGroupItem.d.ts.map +1 -1
- package/dist/components/molecules/CheckboxGroup/CheckboxGroupItem.js +12 -10
- package/dist/components/molecules/DescriptionList/DescriptionList.d.ts +37 -0
- package/dist/components/molecules/DescriptionList/DescriptionList.d.ts.map +1 -0
- package/dist/components/molecules/DescriptionList/DescriptionList.js +50 -0
- package/dist/components/molecules/DescriptionList/descriptionListStyles.d.ts +21 -0
- package/dist/components/molecules/DescriptionList/descriptionListStyles.d.ts.map +1 -0
- package/dist/components/molecules/DescriptionList/descriptionListStyles.js +27 -0
- package/dist/components/molecules/IndexList/IndexList.d.ts +58 -0
- package/dist/components/molecules/IndexList/IndexList.d.ts.map +1 -0
- package/dist/components/molecules/IndexList/IndexList.js +96 -0
- package/dist/components/molecules/IndexList/indexListStyles.d.ts +29 -0
- package/dist/components/molecules/IndexList/indexListStyles.d.ts.map +1 -0
- package/dist/components/molecules/IndexList/indexListStyles.js +24 -0
- package/dist/components/molecules/PromptBar/PromptBar.d.ts +11 -1
- package/dist/components/molecules/PromptBar/PromptBar.d.ts.map +1 -1
- package/dist/components/molecules/PromptBar/PromptBar.js +54 -43
- package/dist/components/molecules/PromptBar/promptBarStyles.d.ts +16 -0
- package/dist/components/molecules/PromptBar/promptBarStyles.d.ts.map +1 -1
- package/dist/components/molecules/PromptBar/promptBarStyles.js +5 -2
- package/dist/components/organisms/ChatDock/ChatDock.d.ts +203 -0
- package/dist/components/organisms/ChatDock/ChatDock.d.ts.map +1 -0
- package/dist/components/organisms/ChatDock/ChatDock.js +697 -0
- package/dist/components/organisms/ChatDock/ChatDockGate.d.ts +52 -0
- package/dist/components/organisms/ChatDock/ChatDockGate.d.ts.map +1 -0
- package/dist/components/organisms/ChatDock/ChatDockGate.js +161 -0
- package/dist/components/organisms/ChatDock/chatDockGateStyles.d.ts +16 -0
- package/dist/components/organisms/ChatDock/chatDockGateStyles.d.ts.map +1 -0
- package/dist/components/organisms/ChatDock/chatDockGateStyles.js +8 -0
- package/dist/components/organisms/ChatDock/chatDockStyles.d.ts +98 -0
- package/dist/components/organisms/ChatDock/chatDockStyles.d.ts.map +1 -0
- package/dist/components/organisms/ChatDock/chatDockStyles.js +21 -0
- package/dist/components/organisms/ChatDock/chatDockViewport.d.ts +21 -0
- package/dist/components/organisms/ChatDock/chatDockViewport.d.ts.map +1 -0
- package/dist/components/organisms/ChatDock/chatDockViewport.js +46 -0
- package/dist/components/organisms/Dialog/AlertDialog.js +11 -11
- package/dist/components/organisms/Dialog/Dialog.js +44 -44
- package/dist/components/organisms/Sheet/Sheet.js +38 -38
- package/dist/components/organisms/Toast/Toast.js +5 -5
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -110
- package/dist/lib/compositionAudit.d.ts.map +1 -1
- package/dist/lib/typography.d.ts +2 -2
- package/dist/lib/typography.d.ts.map +1 -1
- package/dist/lib/typography.js +27 -1
- package/dist/styles.css +1 -1
- package/dist/theme.css +1 -0
- package/dist/typography.css +34 -0
- package/docs/README.md +1 -1
- package/docs/component-contracts.md +16 -1
- package/docs/components.md +16 -11
- package/docs/exports.json +81 -4
- package/docs/patterns/components-accordion--flush.tsx +29 -0
- package/docs/patterns/components-avatar--dropdown-row.tsx +1 -1
- package/docs/patterns/components-badge--outline-tags.tsx +25 -0
- package/docs/patterns/components-badge--with-avatar.tsx +1 -1
- package/docs/patterns/components-button-button--copy-button.tsx +39 -0
- package/docs/patterns/components-button-button--destructive-action.tsx +1 -1
- package/docs/patterns/components-button-button--external-link.tsx +30 -0
- package/docs/patterns/components-button-button--ghost-action.tsx +1 -1
- package/docs/patterns/components-button-button--inverse-action.tsx +1 -1
- package/docs/patterns/components-button-button--link-render.tsx +1 -1
- package/docs/patterns/components-button-button--multi-state-badge.tsx +1 -1
- package/docs/patterns/components-button-button--outline-mono.tsx +1 -1
- package/docs/patterns/components-button-button--primary-action.tsx +1 -1
- package/docs/patterns/components-button-button--row-hug.tsx +1 -1
- package/docs/patterns/components-button-button--row-layout.tsx +1 -1
- package/docs/patterns/components-button-button--secondary-action.tsx +1 -1
- package/docs/patterns/components-button-button--suggestion-pills.tsx +1 -1
- package/docs/patterns/components-button-button--with-count.tsx +1 -1
- package/docs/patterns/components-button-button--with-icon.tsx +1 -1
- package/docs/patterns/components-button-floatingactionbutton--vertical-actions.tsx +1 -1
- package/docs/patterns/components-calembed--pattern-skip-in-footer.tsx +1 -1
- package/docs/patterns/components-card-card--body-slot-occupancy-history.tsx +1 -1
- package/docs/patterns/components-card-card--headerless-media.tsx +1 -1
- package/docs/patterns/components-card-card--outlined-layout.tsx +1 -1
- package/docs/patterns/components-card-card--pinned-height.tsx +1 -1
- package/docs/patterns/components-card-selectablecard--selectable-cards-pattern.tsx +1 -1
- package/docs/patterns/components-chart--audience-activity-heatmap.tsx +1 -1
- package/docs/patterns/components-chart--cartesian-no-data-gaps.tsx +1 -1
- package/docs/patterns/components-chart--occupancy-history-in-card.tsx +1 -1
- package/docs/patterns/components-chart--occupancy-in-card.tsx +1 -1
- package/docs/patterns/components-chart--post-reach-distribution.tsx +1 -1
- package/docs/patterns/components-chart--ranked-audience-breakdown.tsx +1 -1
- package/docs/patterns/components-chart--unit-grid-composition.tsx +1 -1
- package/docs/patterns/components-chatdock--pattern-chat-dock.tsx +158 -0
- package/docs/patterns/components-chatdock--pattern-start-project-gate.tsx +180 -0
- package/docs/patterns/components-chatqa--pattern-qa-with-reply.tsx +1 -1
- package/docs/patterns/components-checkbox-checkbox--default.tsx +1 -1
- package/docs/patterns/components-checkbox-checkbox--with-count.tsx +19 -0
- package/docs/patterns/components-checkbox-checkbox--with-description.tsx +1 -1
- package/docs/patterns/components-checkbox-checkboxgroup--default.tsx +1 -1
- package/docs/patterns/components-checkbox-checkboxgroup--option-counts.tsx +17 -0
- package/docs/patterns/components-descriptionlist--details.tsx +21 -0
- package/docs/patterns/components-descriptionlist--post-metadata.tsx +52 -0
- package/docs/patterns/components-dialog--alert-dialog-destructive.tsx +1 -1
- package/docs/patterns/components-dialog--default-dialog.tsx +1 -1
- package/docs/patterns/components-dialog--form-dialog.tsx +1 -1
- package/docs/patterns/components-displaycontrols--page-utilities.tsx +1 -1
- package/docs/patterns/components-field--horizontal-input.tsx +1 -1
- package/docs/patterns/components-field--horizontal-text-area.tsx +1 -1
- package/docs/patterns/components-field--multi-control.tsx +1 -1
- package/docs/patterns/components-footerreveal--marketing-hero-pattern.tsx +1 -1
- package/docs/patterns/components-footerreveal--marketing-hero-ruled-pattern.tsx +1 -1
- package/docs/patterns/components-footerreveal--marketing-hero-with-gallery-intro.tsx +1 -1
- package/docs/patterns/components-footerreveal--marketing-page-pattern.tsx +1 -1
- package/docs/patterns/components-footerreveal--ruled-grid-footer-pattern.tsx +1 -1
- package/docs/patterns/components-footerreveal--sequenced-marketing-hero.tsx +1 -1
- package/docs/patterns/components-herointro--two-line-intro.tsx +1 -1
- package/docs/patterns/components-herotilestack--marketing-hero-pattern.tsx +1 -1
- package/docs/patterns/components-herotilestack--marketing-hero-text-sequence.tsx +1 -1
- package/docs/patterns/components-herotilestack--marketing-hero-with-gallery-intro.tsx +1 -1
- package/docs/patterns/components-indexlist--post-index.tsx +36 -0
- package/docs/patterns/components-intakeconfirmation--booked-pattern.tsx +1 -1
- package/docs/patterns/components-intakeconfirmation--emailed-pattern.tsx +1 -1
- package/docs/patterns/components-intakeform--about-you-pattern.tsx +1 -1
- package/docs/patterns/components-intakemodal--intake-modal-pattern.tsx +1 -1
- package/docs/patterns/components-kbd--command-row.tsx +1 -1
- package/docs/patterns/components-kbd--numbered-choices.tsx +1 -1
- package/docs/patterns/components-kbd--shortcut.tsx +1 -1
- package/docs/patterns/components-moremenu--action-menu.tsx +1 -1
- package/docs/patterns/components-moremenu--in-card-header.tsx +1 -1
- package/docs/patterns/components-navlist--side-nav-settings.tsx +1 -1
- package/docs/patterns/components-pageheader--app-header-pattern.tsx +1 -1
- package/docs/patterns/components-pageheader--page-section-header.tsx +1 -1
- package/docs/patterns/components-pageheader--toolbar-header.tsx +1 -1
- package/docs/patterns/components-panel--end-detail-rail.tsx +1 -1
- package/docs/patterns/components-pillgroup--pill-group-pattern.tsx +1 -1
- package/docs/patterns/components-promptbar--pattern-prompt-bar.tsx +1 -1
- package/docs/patterns/components-prose--article-body.tsx +11 -0
- package/docs/patterns/components-radio-radiogroup--default.tsx +1 -1
- package/docs/patterns/components-scrollhorizontal--project-gallery-pattern.tsx +1 -1
- package/docs/patterns/components-scrollhorizontal--with-intro.tsx +1 -1
- package/docs/patterns/components-sectioncaption--column-caption.tsx +16 -0
- package/docs/patterns/components-sectioncaption--with-action.tsx +19 -0
- package/docs/patterns/components-sheet--bottom-sheet.tsx +1 -1
- package/docs/patterns/components-sheet--end-sheet.tsx +1 -1
- package/docs/patterns/components-sitenav--brand-and-cta.tsx +1 -1
- package/docs/patterns/components-sitenav--centered-links.tsx +1 -1
- package/docs/patterns/components-sitenav--compact.tsx +1 -1
- package/docs/patterns/components-sitenav--marketing-header.tsx +1 -1
- package/docs/patterns/components-sitenav--mega-menu.tsx +1 -1
- package/docs/patterns/components-stat--insights-row.tsx +1 -1
- package/docs/patterns/components-stepprogress--step-progress-pattern.tsx +1 -1
- package/docs/patterns/components-switch--default.tsx +1 -1
- package/docs/patterns/components-switch--settings-row.tsx +1 -1
- package/docs/patterns/components-tab--settings-pages.tsx +1 -1
- package/docs/patterns/components-taskrows--action-details.tsx +1 -1
- package/docs/patterns/components-taskrows--capsules.tsx +1 -1
- package/docs/patterns/components-taskrows--card-with-status-rows.tsx +1 -1
- package/docs/patterns/components-taskrows--controlled-expand.tsx +1 -1
- package/docs/patterns/components-taskrows--custom-slots.tsx +1 -1
- package/docs/patterns/components-taskrows--status-list.tsx +1 -1
- package/docs/patterns/components-taskrows--tag-chips.tsx +1 -1
- package/docs/patterns/components-textlink--external-destination.tsx +1 -1
- package/docs/patterns/components-textlink--inline-prose.tsx +1 -1
- package/docs/patterns/components-textlink--quiet-title.tsx +15 -0
- package/docs/patterns/components-textlink--supporting-copy.tsx +1 -1
- package/docs/patterns/components-textsequence--default.tsx +1 -1
- package/docs/patterns/components-textsequence--reduced-motion.tsx +1 -1
- package/docs/patterns/components-textsequence--shapes.tsx +1 -1
- package/docs/patterns/components-toast--stacked-notifications.tsx +1 -1
- package/docs/patterns/components-tooltip--controlled.tsx +1 -1
- package/docs/patterns/components-tooltip--disabled-control.tsx +1 -1
- package/docs/patterns/components-tooltip--icon-action.tsx +1 -1
- package/docs/patterns/components-tooltip--keyboard-shortcut.tsx +1 -1
- package/docs/patterns/components-tooltip--placement.tsx +1 -1
- package/docs/patterns/foundations-scroll-fade--horizontal-rail.tsx +1 -1
- package/docs/patterns/foundations-scroll-fade--overflowing-list.tsx +1 -1
- package/docs/patterns/guides-chart-explorations--comparison-gallery.tsx +1 -1
- package/docs/patterns/guides-filter-panel--filtered-index.tsx +174 -0
- package/docs/patterns/guides-overlay-flows--notification-preferences.tsx +1 -1
- package/docs/patterns/guides-post-page--post-page.tsx +143 -0
- package/docs/patterns/guides-profile-typography--editorial-profile.tsx +1 -1
- package/docs/patterns/index.json +137 -9
- package/package.json +1 -1
- package/docs/patterns/components-promptbar--pattern-marketing-composer.tsx +0 -37
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// @thewhatmatters/wmds@0.4.1 · Pattern — filtered index
|
|
2
|
+
// Storybook: Guides/Filter panel → Pattern — filtered index (?path=/story/guides-filter-panel--filtered-index)
|
|
3
|
+
// Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
|
|
4
|
+
|
|
5
|
+
import { useId, useState } from "react";
|
|
6
|
+
import { SlidersHorizontal } from "lucide-react";
|
|
7
|
+
import { Accordion, Button, CheckboxGroup, IndexList, SectionCaption, Sheet } from "@thewhatmatters/wmds";
|
|
8
|
+
|
|
9
|
+
export interface FilterGroupDef {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
options: { value: string; label: string }[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface FilteredPost {
|
|
16
|
+
slug: string;
|
|
17
|
+
title: string;
|
|
18
|
+
href: string;
|
|
19
|
+
/** ISO date, for the time element. */
|
|
20
|
+
date: string;
|
|
21
|
+
/** The date as readers see it, for example "Sep 14, 2026". */
|
|
22
|
+
dateLabel: string;
|
|
23
|
+
description: string;
|
|
24
|
+
/** The post's option in each filter group, by group id — for example { topic: "guides" }. */
|
|
25
|
+
facets: Record<string, string>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type Selection = Record<string, string[]>;
|
|
29
|
+
|
|
30
|
+
function postsLabel(count: number) {
|
|
31
|
+
return count === 1 ? "1 post" : `${count} posts`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function matches(post: FilteredPost, groups: FilterGroupDef[], selection: Selection) {
|
|
35
|
+
return groups.every((group) => {
|
|
36
|
+
const values = selection[group.id] ?? [];
|
|
37
|
+
return values.length === 0 || values.includes(post.facets[group.id] ?? "");
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function FilterGroups({
|
|
42
|
+
groups,
|
|
43
|
+
posts,
|
|
44
|
+
selection,
|
|
45
|
+
onGroupChange,
|
|
46
|
+
}: {
|
|
47
|
+
groups: FilterGroupDef[];
|
|
48
|
+
posts: FilteredPost[];
|
|
49
|
+
selection: Selection;
|
|
50
|
+
onGroupChange: (groupId: string, values: string[]) => void;
|
|
51
|
+
}) {
|
|
52
|
+
return (
|
|
53
|
+
<Accordion variant="plain" flush>
|
|
54
|
+
{groups.map((group) => (
|
|
55
|
+
<Accordion.Item key={group.id} label={group.label} defaultOpen>
|
|
56
|
+
<CheckboxGroup
|
|
57
|
+
label={group.label}
|
|
58
|
+
labelHidden
|
|
59
|
+
size="sm"
|
|
60
|
+
values={selection[group.id] ?? []}
|
|
61
|
+
onValuesChange={(values) => onGroupChange(group.id, values)}
|
|
62
|
+
>
|
|
63
|
+
{group.options.map((option) => {
|
|
64
|
+
const count = posts.filter((post) => post.facets[group.id] === option.value).length;
|
|
65
|
+
return (
|
|
66
|
+
<CheckboxGroup.Item
|
|
67
|
+
key={option.value}
|
|
68
|
+
value={option.value}
|
|
69
|
+
label={option.label}
|
|
70
|
+
count={count}
|
|
71
|
+
countLabel={postsLabel(count)}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
})}
|
|
75
|
+
</CheckboxGroup>
|
|
76
|
+
</Accordion.Item>
|
|
77
|
+
))}
|
|
78
|
+
</Accordion>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function FilteredIndex({
|
|
83
|
+
title,
|
|
84
|
+
posts,
|
|
85
|
+
groups,
|
|
86
|
+
}: {
|
|
87
|
+
title: string;
|
|
88
|
+
posts: FilteredPost[];
|
|
89
|
+
groups: FilterGroupDef[];
|
|
90
|
+
}) {
|
|
91
|
+
const filtersHeadingId = useId();
|
|
92
|
+
const [selection, setSelection] = useState<Selection>({});
|
|
93
|
+
const [sheetOpen, setSheetOpen] = useState(false);
|
|
94
|
+
const activeCount = Object.values(selection).reduce((total, values) => total + values.length, 0);
|
|
95
|
+
const shown = posts.filter((post) => matches(post, groups, selection));
|
|
96
|
+
|
|
97
|
+
function setGroup(groupId: string, values: string[]) {
|
|
98
|
+
setSelection((current) => ({ ...current, [groupId]: values }));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<main className="grid-page bg-body">
|
|
103
|
+
<div className="band py-6 sm:py-10 lg:py-14">
|
|
104
|
+
<header className="col-span-full mb-4 flex items-end justify-between gap-4 sm:mb-8">
|
|
105
|
+
<h1 className="type-display-2 text-fg">
|
|
106
|
+
{title} <span className="tabular-nums text-muted">{shown.length}</span>
|
|
107
|
+
</h1>
|
|
108
|
+
<Button
|
|
109
|
+
role="secondary"
|
|
110
|
+
icon={<SlidersHorizontal />}
|
|
111
|
+
count={activeCount > 0 ? activeCount : undefined}
|
|
112
|
+
className="md:hidden"
|
|
113
|
+
onClick={() => setSheetOpen(true)}
|
|
114
|
+
>
|
|
115
|
+
Filters
|
|
116
|
+
</Button>
|
|
117
|
+
</header>
|
|
118
|
+
<p role="status" className="sr-only">
|
|
119
|
+
{postsLabel(shown.length)}
|
|
120
|
+
</p>
|
|
121
|
+
|
|
122
|
+
<aside aria-labelledby={filtersHeadingId} className="hidden md:col-span-3 md:block">
|
|
123
|
+
<SectionCaption
|
|
124
|
+
id={filtersHeadingId}
|
|
125
|
+
end={
|
|
126
|
+
<Button role="ghost" size="xs" disabled={activeCount === 0} onClick={() => setSelection({})}>
|
|
127
|
+
Clear all
|
|
128
|
+
</Button>
|
|
129
|
+
}
|
|
130
|
+
>
|
|
131
|
+
Filters
|
|
132
|
+
</SectionCaption>
|
|
133
|
+
<FilterGroups groups={groups} posts={posts} selection={selection} onGroupChange={setGroup} />
|
|
134
|
+
</aside>
|
|
135
|
+
|
|
136
|
+
<div className="col-span-full md:col-span-5 lg:col-span-9">
|
|
137
|
+
<IndexList
|
|
138
|
+
aria-label="Posts"
|
|
139
|
+
captions={{ meta: "Date", title: "Name" }}
|
|
140
|
+
empty={<p className="type-body text-muted">No posts match these filters.</p>}
|
|
141
|
+
>
|
|
142
|
+
{shown.map((post) => (
|
|
143
|
+
<IndexList.Item
|
|
144
|
+
key={post.slug}
|
|
145
|
+
title={post.title}
|
|
146
|
+
href={post.href}
|
|
147
|
+
meta={<time dateTime={post.date}>{post.dateLabel}</time>}
|
|
148
|
+
preview={<p>{post.description}</p>}
|
|
149
|
+
/>
|
|
150
|
+
))}
|
|
151
|
+
</IndexList>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
|
|
156
|
+
<Sheet.Content
|
|
157
|
+
title="Filters"
|
|
158
|
+
footer={
|
|
159
|
+
<div className="flex items-center justify-end gap-2">
|
|
160
|
+
<Button role="secondary" size="sm" disabled={activeCount === 0} onClick={() => setSelection({})}>
|
|
161
|
+
Clear all
|
|
162
|
+
</Button>
|
|
163
|
+
<Button role="primary" size="sm" onClick={() => setSheetOpen(false)}>
|
|
164
|
+
Show {postsLabel(shown.length)}
|
|
165
|
+
</Button>
|
|
166
|
+
</div>
|
|
167
|
+
}
|
|
168
|
+
>
|
|
169
|
+
<FilterGroups groups={groups} posts={posts} selection={selection} onGroupChange={setGroup} />
|
|
170
|
+
</Sheet.Content>
|
|
171
|
+
</Sheet>
|
|
172
|
+
</main>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @thewhatmatters/wmds@0.
|
|
1
|
+
// @thewhatmatters/wmds@0.4.1 · Pattern — notification preferences
|
|
2
2
|
// Storybook: Guides/Overlay flows → Pattern — notification preferences (?path=/story/guides-overlay-flows--notification-preferences)
|
|
3
3
|
// Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
|
|
4
4
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// @thewhatmatters/wmds@0.4.1 · Pattern — post page
|
|
2
|
+
// Storybook: Guides/Post page → Pattern — post page (?path=/story/guides-post-page--post-page)
|
|
3
|
+
// Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
|
|
4
|
+
|
|
5
|
+
import { useEffect, useId, useState, type ReactNode } from "react";
|
|
6
|
+
import { Copy, FileText } from "lucide-react";
|
|
7
|
+
import {
|
|
8
|
+
Badge,
|
|
9
|
+
Button,
|
|
10
|
+
DescriptionList,
|
|
11
|
+
Prose,
|
|
12
|
+
SectionCaption,
|
|
13
|
+
buttonStatusHoldMs,
|
|
14
|
+
type ButtonStatus,
|
|
15
|
+
} from "@thewhatmatters/wmds";
|
|
16
|
+
|
|
17
|
+
export interface PostCategory {
|
|
18
|
+
label: string;
|
|
19
|
+
href: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface PostPageData {
|
|
23
|
+
title: string;
|
|
24
|
+
description: string;
|
|
25
|
+
/** ISO date, for the time element. */
|
|
26
|
+
date: string;
|
|
27
|
+
/** The date as readers see it, for example "Sep 14, 2026". */
|
|
28
|
+
dateLabel: string;
|
|
29
|
+
author: string;
|
|
30
|
+
/** For example "6 min". */
|
|
31
|
+
readingTime: string;
|
|
32
|
+
categories: PostCategory[];
|
|
33
|
+
/** The post's own address, for the share links. */
|
|
34
|
+
url: string;
|
|
35
|
+
/** The post's markdown source, for Copy for LLM. */
|
|
36
|
+
markdown: string;
|
|
37
|
+
/** The post as plain markdown, for View as Markdown. */
|
|
38
|
+
markdownHref: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function CopyButton({ text, label }: { text: string; label: string }) {
|
|
42
|
+
const [status, setStatus] = useState<ButtonStatus>("idle");
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (status !== "success" && status !== "error") return;
|
|
46
|
+
const timer = window.setTimeout(() => setStatus("idle"), buttonStatusHoldMs);
|
|
47
|
+
return () => window.clearTimeout(timer);
|
|
48
|
+
}, [status]);
|
|
49
|
+
|
|
50
|
+
async function copy() {
|
|
51
|
+
try {
|
|
52
|
+
await navigator.clipboard.writeText(text);
|
|
53
|
+
setStatus("success");
|
|
54
|
+
} catch {
|
|
55
|
+
setStatus("error");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Button
|
|
61
|
+
role="secondary"
|
|
62
|
+
size="sm"
|
|
63
|
+
icon={<Copy />}
|
|
64
|
+
status={status}
|
|
65
|
+
statusLabels={{ success: "Copied", error: "Couldn't copy" }}
|
|
66
|
+
onClick={copy}
|
|
67
|
+
>
|
|
68
|
+
{label}
|
|
69
|
+
</Button>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** A blog post: the title, a metadata panel, and the article, which is the rendered markdown. */
|
|
74
|
+
export function PostPage({ post, children }: { post: PostPageData; children: ReactNode }) {
|
|
75
|
+
const metadataHeadingId = useId();
|
|
76
|
+
const encodedUrl = encodeURIComponent(post.url);
|
|
77
|
+
const encodedTitle = encodeURIComponent(post.title);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<main className="grid-page bg-body">
|
|
81
|
+
<article className="band py-6 sm:py-10 lg:py-14">
|
|
82
|
+
<header className="col-span-full mb-4 flex flex-col gap-3 sm:mb-8 lg:col-span-10">
|
|
83
|
+
<h1 className="type-display-2 text-balance text-fg">{post.title}</h1>
|
|
84
|
+
<p className="type-reading max-w-[40rem] text-muted">{post.description}</p>
|
|
85
|
+
</header>
|
|
86
|
+
|
|
87
|
+
<aside
|
|
88
|
+
aria-labelledby={metadataHeadingId}
|
|
89
|
+
className="col-span-full lg:sticky lg:top-[calc(var(--site-nav-height)+1rem)] lg:col-span-4"
|
|
90
|
+
>
|
|
91
|
+
<SectionCaption id={metadataHeadingId}>Metadata</SectionCaption>
|
|
92
|
+
<DescriptionList variant="mono" rule="dotted">
|
|
93
|
+
<DescriptionList.Item name="Date">
|
|
94
|
+
<time dateTime={post.date}>{post.dateLabel}</time>
|
|
95
|
+
</DescriptionList.Item>
|
|
96
|
+
<DescriptionList.Item name="Author">
|
|
97
|
+
<Badge emphasis="outline" mono>
|
|
98
|
+
{post.author}
|
|
99
|
+
</Badge>
|
|
100
|
+
</DescriptionList.Item>
|
|
101
|
+
<DescriptionList.Item name="Reading time">{post.readingTime}</DescriptionList.Item>
|
|
102
|
+
<DescriptionList.Item name="Categories">
|
|
103
|
+
{post.categories.map((category) => (
|
|
104
|
+
<Badge key={category.href} emphasis="outline" mono render={<a href={category.href} />}>
|
|
105
|
+
{category.label}
|
|
106
|
+
</Badge>
|
|
107
|
+
))}
|
|
108
|
+
</DescriptionList.Item>
|
|
109
|
+
<DescriptionList.Item name="Agents" layout="stacked">
|
|
110
|
+
<CopyButton text={post.markdown} label="Copy for LLM" />
|
|
111
|
+
<Button role="secondary" size="sm" icon={<FileText />} render={<a href={post.markdownHref} />}>
|
|
112
|
+
View as Markdown
|
|
113
|
+
</Button>
|
|
114
|
+
</DescriptionList.Item>
|
|
115
|
+
<DescriptionList.Item name="Share" layout="stacked">
|
|
116
|
+
<Button
|
|
117
|
+
role="secondary"
|
|
118
|
+
size="sm"
|
|
119
|
+
external
|
|
120
|
+
render={<a href={"https://x.com/intent/post?url=" + encodedUrl + "&text=" + encodedTitle} />}
|
|
121
|
+
>
|
|
122
|
+
Twitter/X
|
|
123
|
+
</Button>
|
|
124
|
+
<Button
|
|
125
|
+
role="secondary"
|
|
126
|
+
size="sm"
|
|
127
|
+
external
|
|
128
|
+
render={<a href={"https://www.linkedin.com/sharing/share-offsite/?url=" + encodedUrl} />}
|
|
129
|
+
>
|
|
130
|
+
LinkedIn
|
|
131
|
+
</Button>
|
|
132
|
+
</DescriptionList.Item>
|
|
133
|
+
</DescriptionList>
|
|
134
|
+
</aside>
|
|
135
|
+
|
|
136
|
+
<div className="col-span-full mt-6 lg:col-span-8 lg:mt-0">
|
|
137
|
+
<SectionCaption as="p">Article</SectionCaption>
|
|
138
|
+
<Prose className="mt-6">{children}</Prose>
|
|
139
|
+
</div>
|
|
140
|
+
</article>
|
|
141
|
+
</main>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @thewhatmatters/wmds@0.
|
|
1
|
+
// @thewhatmatters/wmds@0.4.1 · Pattern — editorial profile
|
|
2
2
|
// Storybook: Guides/Profile typography → Pattern — editorial profile (?path=/story/guides-profile-typography--editorial-profile)
|
|
3
3
|
// Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
|
|
4
4
|
|
package/docs/patterns/index.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "@thewhatmatters/wmds",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"patterns": [
|
|
5
|
+
{
|
|
6
|
+
"id": "components-accordion--flush",
|
|
7
|
+
"title": "Components/Accordion",
|
|
8
|
+
"name": "Pattern — flush",
|
|
9
|
+
"file": "patterns/components-accordion--flush.tsx",
|
|
10
|
+
"storybook": "?path=/story/components-accordion--flush",
|
|
11
|
+
"source": "src/components/molecules/Accordion/Accordion.stories.tsx"
|
|
12
|
+
},
|
|
5
13
|
{
|
|
6
14
|
"id": "components-avatar--dropdown-row",
|
|
7
15
|
"title": "Components/Avatar",
|
|
@@ -10,6 +18,14 @@
|
|
|
10
18
|
"storybook": "?path=/story/components-avatar--dropdown-row",
|
|
11
19
|
"source": "src/components/atoms/Avatar/Avatar.stories.tsx"
|
|
12
20
|
},
|
|
21
|
+
{
|
|
22
|
+
"id": "components-badge--outline-tags",
|
|
23
|
+
"title": "Components/Badge",
|
|
24
|
+
"name": "Pattern — outline tags",
|
|
25
|
+
"file": "patterns/components-badge--outline-tags.tsx",
|
|
26
|
+
"storybook": "?path=/story/components-badge--outline-tags",
|
|
27
|
+
"source": "src/components/atoms/Badge/Badge.stories.tsx"
|
|
28
|
+
},
|
|
13
29
|
{
|
|
14
30
|
"id": "components-badge--with-avatar",
|
|
15
31
|
"title": "Components/Badge",
|
|
@@ -18,6 +34,14 @@
|
|
|
18
34
|
"storybook": "?path=/story/components-badge--with-avatar",
|
|
19
35
|
"source": "src/components/atoms/Badge/Badge.stories.tsx"
|
|
20
36
|
},
|
|
37
|
+
{
|
|
38
|
+
"id": "components-button-button--copy-button",
|
|
39
|
+
"title": "Components/Button/Button",
|
|
40
|
+
"name": "Pattern — copy button",
|
|
41
|
+
"file": "patterns/components-button-button--copy-button.tsx",
|
|
42
|
+
"storybook": "?path=/story/components-button-button--copy-button",
|
|
43
|
+
"source": "src/components/atoms/Button/Button.stories.tsx"
|
|
44
|
+
},
|
|
21
45
|
{
|
|
22
46
|
"id": "components-button-button--destructive-action",
|
|
23
47
|
"title": "Components/Button/Button",
|
|
@@ -26,6 +50,14 @@
|
|
|
26
50
|
"storybook": "?path=/story/components-button-button--destructive-action",
|
|
27
51
|
"source": "src/components/atoms/Button/Button.stories.tsx"
|
|
28
52
|
},
|
|
53
|
+
{
|
|
54
|
+
"id": "components-button-button--external-link",
|
|
55
|
+
"title": "Components/Button/Button",
|
|
56
|
+
"name": "Pattern — external link",
|
|
57
|
+
"file": "patterns/components-button-button--external-link.tsx",
|
|
58
|
+
"storybook": "?path=/story/components-button-button--external-link",
|
|
59
|
+
"source": "src/components/atoms/Button/Button.stories.tsx"
|
|
60
|
+
},
|
|
29
61
|
{
|
|
30
62
|
"id": "components-button-button--ghost-action",
|
|
31
63
|
"title": "Components/Button/Button",
|
|
@@ -234,6 +266,22 @@
|
|
|
234
266
|
"storybook": "?path=/story/components-chart--unit-grid-composition",
|
|
235
267
|
"source": "src/components/organisms/Chart/Chart.stories.tsx"
|
|
236
268
|
},
|
|
269
|
+
{
|
|
270
|
+
"id": "components-chatdock--pattern-chat-dock",
|
|
271
|
+
"title": "Components/ChatDock",
|
|
272
|
+
"name": "Pattern — chat dock",
|
|
273
|
+
"file": "patterns/components-chatdock--pattern-chat-dock.tsx",
|
|
274
|
+
"storybook": "?path=/story/components-chatdock--pattern-chat-dock",
|
|
275
|
+
"source": "src/components/organisms/ChatDock/ChatDock.stories.tsx"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"id": "components-chatdock--pattern-start-project-gate",
|
|
279
|
+
"title": "Components/ChatDock",
|
|
280
|
+
"name": "Pattern — start a project gate",
|
|
281
|
+
"file": "patterns/components-chatdock--pattern-start-project-gate.tsx",
|
|
282
|
+
"storybook": "?path=/story/components-chatdock--pattern-start-project-gate",
|
|
283
|
+
"source": "src/components/organisms/ChatDock/ChatDock.stories.tsx"
|
|
284
|
+
},
|
|
237
285
|
{
|
|
238
286
|
"id": "components-chatqa--pattern-qa-with-reply",
|
|
239
287
|
"title": "Components/ChatQa",
|
|
@@ -250,6 +298,14 @@
|
|
|
250
298
|
"storybook": "?path=/story/components-checkbox-checkbox--default",
|
|
251
299
|
"source": "src/components/atoms/Checkbox/Checkbox.stories.tsx"
|
|
252
300
|
},
|
|
301
|
+
{
|
|
302
|
+
"id": "components-checkbox-checkbox--with-count",
|
|
303
|
+
"title": "Components/Checkbox/Checkbox",
|
|
304
|
+
"name": "Pattern — with count",
|
|
305
|
+
"file": "patterns/components-checkbox-checkbox--with-count.tsx",
|
|
306
|
+
"storybook": "?path=/story/components-checkbox-checkbox--with-count",
|
|
307
|
+
"source": "src/components/atoms/Checkbox/Checkbox.stories.tsx"
|
|
308
|
+
},
|
|
253
309
|
{
|
|
254
310
|
"id": "components-checkbox-checkbox--with-description",
|
|
255
311
|
"title": "Components/Checkbox/Checkbox",
|
|
@@ -266,6 +322,30 @@
|
|
|
266
322
|
"storybook": "?path=/story/components-checkbox-checkboxgroup--default",
|
|
267
323
|
"source": "src/components/molecules/CheckboxGroup/CheckboxGroup.stories.tsx"
|
|
268
324
|
},
|
|
325
|
+
{
|
|
326
|
+
"id": "components-checkbox-checkboxgroup--option-counts",
|
|
327
|
+
"title": "Components/Checkbox/CheckboxGroup",
|
|
328
|
+
"name": "Pattern — option counts",
|
|
329
|
+
"file": "patterns/components-checkbox-checkboxgroup--option-counts.tsx",
|
|
330
|
+
"storybook": "?path=/story/components-checkbox-checkboxgroup--option-counts",
|
|
331
|
+
"source": "src/components/molecules/CheckboxGroup/CheckboxGroup.stories.tsx"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"id": "components-descriptionlist--details",
|
|
335
|
+
"title": "Components/DescriptionList",
|
|
336
|
+
"name": "Pattern — details",
|
|
337
|
+
"file": "patterns/components-descriptionlist--details.tsx",
|
|
338
|
+
"storybook": "?path=/story/components-descriptionlist--details",
|
|
339
|
+
"source": "src/components/molecules/DescriptionList/DescriptionList.stories.tsx"
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"id": "components-descriptionlist--post-metadata",
|
|
343
|
+
"title": "Components/DescriptionList",
|
|
344
|
+
"name": "Pattern — post metadata",
|
|
345
|
+
"file": "patterns/components-descriptionlist--post-metadata.tsx",
|
|
346
|
+
"storybook": "?path=/story/components-descriptionlist--post-metadata",
|
|
347
|
+
"source": "src/components/molecules/DescriptionList/DescriptionList.stories.tsx"
|
|
348
|
+
},
|
|
269
349
|
{
|
|
270
350
|
"id": "components-dialog--alert-dialog-destructive",
|
|
271
351
|
"title": "Components/Dialog",
|
|
@@ -402,6 +482,14 @@
|
|
|
402
482
|
"storybook": "?path=/story/components-herotilestack--marketing-hero-with-gallery-intro",
|
|
403
483
|
"source": "src/components/organisms/HeroTileStack/HeroTileStack.galleryIntro.stories.tsx"
|
|
404
484
|
},
|
|
485
|
+
{
|
|
486
|
+
"id": "components-indexlist--post-index",
|
|
487
|
+
"title": "Components/IndexList",
|
|
488
|
+
"name": "Pattern — post index",
|
|
489
|
+
"file": "patterns/components-indexlist--post-index.tsx",
|
|
490
|
+
"storybook": "?path=/story/components-indexlist--post-index",
|
|
491
|
+
"source": "src/components/molecules/IndexList/IndexList.stories.tsx"
|
|
492
|
+
},
|
|
405
493
|
{
|
|
406
494
|
"id": "components-intakeconfirmation--booked-pattern",
|
|
407
495
|
"title": "Components/IntakeConfirmation",
|
|
@@ -522,14 +610,6 @@
|
|
|
522
610
|
"storybook": "?path=/story/components-pillgroup--pill-group-pattern",
|
|
523
611
|
"source": "src/components/molecules/PillGroup/PillGroup.stories.tsx"
|
|
524
612
|
},
|
|
525
|
-
{
|
|
526
|
-
"id": "components-promptbar--pattern-marketing-composer",
|
|
527
|
-
"title": "Components/PromptBar",
|
|
528
|
-
"name": "Pattern — marketing composer",
|
|
529
|
-
"file": "patterns/components-promptbar--pattern-marketing-composer.tsx",
|
|
530
|
-
"storybook": "?path=/story/components-promptbar--pattern-marketing-composer",
|
|
531
|
-
"source": "src/components/molecules/PromptBar/PromptBar.stories.tsx"
|
|
532
|
-
},
|
|
533
613
|
{
|
|
534
614
|
"id": "components-promptbar--pattern-prompt-bar",
|
|
535
615
|
"title": "Components/PromptBar",
|
|
@@ -538,6 +618,14 @@
|
|
|
538
618
|
"storybook": "?path=/story/components-promptbar--pattern-prompt-bar",
|
|
539
619
|
"source": "src/components/molecules/PromptBar/PromptBar.stories.tsx"
|
|
540
620
|
},
|
|
621
|
+
{
|
|
622
|
+
"id": "components-prose--article-body",
|
|
623
|
+
"title": "Components/Prose",
|
|
624
|
+
"name": "Pattern — article body",
|
|
625
|
+
"file": "patterns/components-prose--article-body.tsx",
|
|
626
|
+
"storybook": "?path=/story/components-prose--article-body",
|
|
627
|
+
"source": "src/components/atoms/Prose/Prose.stories.tsx"
|
|
628
|
+
},
|
|
541
629
|
{
|
|
542
630
|
"id": "components-radio-radiogroup--default",
|
|
543
631
|
"title": "Components/Radio/RadioGroup",
|
|
@@ -562,6 +650,22 @@
|
|
|
562
650
|
"storybook": "?path=/story/components-scrollhorizontal--with-intro",
|
|
563
651
|
"source": "src/components/organisms/ScrollHorizontal/ScrollHorizontal.stories.tsx"
|
|
564
652
|
},
|
|
653
|
+
{
|
|
654
|
+
"id": "components-sectioncaption--column-caption",
|
|
655
|
+
"title": "Components/SectionCaption",
|
|
656
|
+
"name": "Pattern — column caption",
|
|
657
|
+
"file": "patterns/components-sectioncaption--column-caption.tsx",
|
|
658
|
+
"storybook": "?path=/story/components-sectioncaption--column-caption",
|
|
659
|
+
"source": "src/components/atoms/SectionCaption/SectionCaption.stories.tsx"
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
"id": "components-sectioncaption--with-action",
|
|
663
|
+
"title": "Components/SectionCaption",
|
|
664
|
+
"name": "Pattern — caption with an action",
|
|
665
|
+
"file": "patterns/components-sectioncaption--with-action.tsx",
|
|
666
|
+
"storybook": "?path=/story/components-sectioncaption--with-action",
|
|
667
|
+
"source": "src/components/atoms/SectionCaption/SectionCaption.stories.tsx"
|
|
668
|
+
},
|
|
565
669
|
{
|
|
566
670
|
"id": "components-sheet--bottom-sheet",
|
|
567
671
|
"title": "Components/Sheet",
|
|
@@ -730,6 +834,14 @@
|
|
|
730
834
|
"storybook": "?path=/story/components-textlink--inline-prose",
|
|
731
835
|
"source": "src/components/atoms/TextLink/TextLink.stories.tsx"
|
|
732
836
|
},
|
|
837
|
+
{
|
|
838
|
+
"id": "components-textlink--quiet-title",
|
|
839
|
+
"title": "Components/TextLink",
|
|
840
|
+
"name": "Pattern — quiet title link",
|
|
841
|
+
"file": "patterns/components-textlink--quiet-title.tsx",
|
|
842
|
+
"storybook": "?path=/story/components-textlink--quiet-title",
|
|
843
|
+
"source": "src/components/atoms/TextLink/TextLink.stories.tsx"
|
|
844
|
+
},
|
|
733
845
|
{
|
|
734
846
|
"id": "components-textlink--supporting-copy",
|
|
735
847
|
"title": "Components/TextLink",
|
|
@@ -834,6 +946,14 @@
|
|
|
834
946
|
"storybook": "?path=/story/guides-chart-explorations--comparison-gallery",
|
|
835
947
|
"source": "src/guides/ChartExplorations/ChartExplorations.stories.tsx"
|
|
836
948
|
},
|
|
949
|
+
{
|
|
950
|
+
"id": "guides-filter-panel--filtered-index",
|
|
951
|
+
"title": "Guides/Filter panel",
|
|
952
|
+
"name": "Pattern — filtered index",
|
|
953
|
+
"file": "patterns/guides-filter-panel--filtered-index.tsx",
|
|
954
|
+
"storybook": "?path=/story/guides-filter-panel--filtered-index",
|
|
955
|
+
"source": "src/guides/FilterPanel/FilterPanel.stories.tsx"
|
|
956
|
+
},
|
|
837
957
|
{
|
|
838
958
|
"id": "guides-overlay-flows--notification-preferences",
|
|
839
959
|
"title": "Guides/Overlay flows",
|
|
@@ -842,6 +962,14 @@
|
|
|
842
962
|
"storybook": "?path=/story/guides-overlay-flows--notification-preferences",
|
|
843
963
|
"source": "src/guides/OverlayFlows/OverlayFlows.stories.tsx"
|
|
844
964
|
},
|
|
965
|
+
{
|
|
966
|
+
"id": "guides-post-page--post-page",
|
|
967
|
+
"title": "Guides/Post page",
|
|
968
|
+
"name": "Pattern — post page",
|
|
969
|
+
"file": "patterns/guides-post-page--post-page.tsx",
|
|
970
|
+
"storybook": "?path=/story/guides-post-page--post-page",
|
|
971
|
+
"source": "src/guides/PostPage/PostPage.stories.tsx"
|
|
972
|
+
},
|
|
845
973
|
{
|
|
846
974
|
"id": "guides-profile-typography--editorial-profile",
|
|
847
975
|
"title": "Guides/Profile typography",
|
package/package.json
CHANGED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// @thewhatmatters/wmds@0.3.0 · Pattern — marketing composer
|
|
2
|
-
// Storybook: Components/PromptBar → Pattern — marketing composer (?path=/story/components-promptbar--pattern-marketing-composer)
|
|
3
|
-
// Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
|
|
4
|
-
|
|
5
|
-
import { useState } from "react";
|
|
6
|
-
import { PromptBar } from "@thewhatmatters/wmds";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Marketing homepage composer, pinned to the bottom of the viewport on the page grid.
|
|
10
|
-
* Sending hands off to the app's ask page: route to /ask?q=<prompt>, and the ask page
|
|
11
|
-
* starts the conversation with `q` as its first prompt.
|
|
12
|
-
* Next.js: onHandOff={(prompt) => router.push(`/ask?q=${encodeURIComponent(prompt)}`)}
|
|
13
|
-
*/
|
|
14
|
-
export function MarketingComposer({ onHandOff }: { onHandOff: (prompt: string) => void }) {
|
|
15
|
-
const [draft, setDraft] = useState("");
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<div className="pointer-events-none fixed inset-x-0 bottom-0 z-40 pb-[max(1rem,env(safe-area-inset-bottom))]">
|
|
19
|
-
<div className="grid-page [--grid-max:40rem]">
|
|
20
|
-
<div className="band">
|
|
21
|
-
<div className="pointer-events-auto col-span-full">
|
|
22
|
-
<PromptBar
|
|
23
|
-
value={draft}
|
|
24
|
-
onValueChange={setDraft}
|
|
25
|
-
onSend={(value) => {
|
|
26
|
-
const prompt = value.trim();
|
|
27
|
-
if (prompt.length === 0) return;
|
|
28
|
-
setDraft("");
|
|
29
|
-
onHandOff(prompt);
|
|
30
|
-
}}
|
|
31
|
-
/>
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
);
|
|
37
|
-
}
|