@thewhatmatters/wmds 0.2.0 → 0.4.0

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.
Files changed (153) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/CONSUMING.md +5 -4
  3. package/README.md +3 -3
  4. package/dist/components/molecules/PromptBar/PromptBar.d.ts +11 -1
  5. package/dist/components/molecules/PromptBar/PromptBar.d.ts.map +1 -1
  6. package/dist/components/molecules/PromptBar/PromptBar.js +54 -43
  7. package/dist/components/molecules/PromptBar/promptBarStyles.d.ts +15 -0
  8. package/dist/components/molecules/PromptBar/promptBarStyles.d.ts.map +1 -1
  9. package/dist/components/molecules/PromptBar/promptBarStyles.js +5 -2
  10. package/dist/components/organisms/ChatDock/ChatDock.d.ts +93 -0
  11. package/dist/components/organisms/ChatDock/ChatDock.d.ts.map +1 -0
  12. package/dist/components/organisms/ChatDock/ChatDock.js +255 -0
  13. package/dist/components/organisms/ChatDock/chatDockStyles.d.ts +48 -0
  14. package/dist/components/organisms/ChatDock/chatDockStyles.d.ts.map +1 -0
  15. package/dist/components/organisms/ChatDock/chatDockStyles.js +15 -0
  16. package/dist/components/organisms/Dialog/AlertDialog.js +11 -11
  17. package/dist/components/organisms/Dialog/Dialog.js +44 -44
  18. package/dist/components/organisms/Sheet/Sheet.js +38 -38
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +30 -28
  22. package/dist/styles.css +1 -1
  23. package/docs/component-contracts.md +1 -1
  24. package/docs/components.md +7 -6
  25. package/docs/exports.json +14 -14
  26. package/docs/patterns/components-avatar--dropdown-row.tsx +1 -1
  27. package/docs/patterns/components-badge--with-avatar.tsx +1 -1
  28. package/docs/patterns/components-button-button--destructive-action.tsx +1 -1
  29. package/docs/patterns/components-button-button--ghost-action.tsx +1 -1
  30. package/docs/patterns/components-button-button--inverse-action.tsx +1 -1
  31. package/docs/patterns/components-button-button--link-render.tsx +1 -1
  32. package/docs/patterns/components-button-button--multi-state-badge.tsx +1 -1
  33. package/docs/patterns/components-button-button--outline-mono.tsx +1 -1
  34. package/docs/patterns/components-button-button--primary-action.tsx +1 -1
  35. package/docs/patterns/components-button-button--row-hug.tsx +1 -1
  36. package/docs/patterns/components-button-button--row-layout.tsx +1 -1
  37. package/docs/patterns/components-button-button--secondary-action.tsx +1 -1
  38. package/docs/patterns/components-button-button--suggestion-pills.tsx +1 -1
  39. package/docs/patterns/components-button-button--with-count.tsx +1 -1
  40. package/docs/patterns/components-button-button--with-icon.tsx +1 -1
  41. package/docs/patterns/components-button-floatingactionbutton--vertical-actions.tsx +1 -1
  42. package/docs/patterns/components-calembed--pattern-skip-in-footer.tsx +1 -1
  43. package/docs/patterns/components-card-card--body-slot-occupancy-history.tsx +1 -1
  44. package/docs/patterns/components-card-card--headerless-media.tsx +1 -1
  45. package/docs/patterns/components-card-card--outlined-layout.tsx +1 -1
  46. package/docs/patterns/components-card-card--pinned-height.tsx +1 -1
  47. package/docs/patterns/components-card-selectablecard--selectable-cards-pattern.tsx +1 -1
  48. package/docs/patterns/components-chart--audience-activity-heatmap.tsx +1 -1
  49. package/docs/patterns/components-chart--cartesian-no-data-gaps.tsx +1 -1
  50. package/docs/patterns/components-chart--occupancy-history-in-card.tsx +1 -1
  51. package/docs/patterns/components-chart--occupancy-in-card.tsx +1 -1
  52. package/docs/patterns/components-chart--post-reach-distribution.tsx +1 -1
  53. package/docs/patterns/components-chart--ranked-audience-breakdown.tsx +1 -1
  54. package/docs/patterns/components-chart--unit-grid-composition.tsx +1 -1
  55. package/docs/patterns/components-chatdock--pattern-chat-dock.tsx +68 -0
  56. package/docs/patterns/components-chatqa--pattern-qa-with-reply.tsx +1 -1
  57. package/docs/patterns/components-checkbox-checkbox--default.tsx +1 -1
  58. package/docs/patterns/components-checkbox-checkbox--with-description.tsx +1 -1
  59. package/docs/patterns/components-checkbox-checkboxgroup--default.tsx +1 -1
  60. package/docs/patterns/components-dialog--alert-dialog-destructive.tsx +1 -1
  61. package/docs/patterns/components-dialog--default-dialog.tsx +1 -1
  62. package/docs/patterns/components-dialog--form-dialog.tsx +1 -1
  63. package/docs/patterns/components-displaycontrols--page-utilities.tsx +1 -1
  64. package/docs/patterns/components-field--horizontal-input.tsx +1 -1
  65. package/docs/patterns/components-field--horizontal-text-area.tsx +1 -1
  66. package/docs/patterns/components-field--multi-control.tsx +1 -1
  67. package/docs/patterns/components-footerreveal--marketing-hero-pattern.tsx +1 -1
  68. package/docs/patterns/components-footerreveal--marketing-hero-ruled-pattern.tsx +1 -1
  69. package/docs/patterns/components-footerreveal--marketing-hero-with-gallery-intro.tsx +1 -1
  70. package/docs/patterns/components-footerreveal--marketing-page-pattern.tsx +1 -1
  71. package/docs/patterns/components-footerreveal--ruled-grid-footer-pattern.tsx +1 -1
  72. package/docs/patterns/components-footerreveal--sequenced-marketing-hero.tsx +1 -1
  73. package/docs/patterns/components-herointro--two-line-intro.tsx +1 -1
  74. package/docs/patterns/components-herotilestack--marketing-hero-pattern.tsx +1 -1
  75. package/docs/patterns/components-herotilestack--marketing-hero-text-sequence.tsx +1 -1
  76. package/docs/patterns/components-herotilestack--marketing-hero-with-gallery-intro.tsx +1 -1
  77. package/docs/patterns/components-intakeconfirmation--booked-pattern.tsx +1 -1
  78. package/docs/patterns/components-intakeconfirmation--emailed-pattern.tsx +1 -1
  79. package/docs/patterns/components-intakeform--about-you-pattern.tsx +1 -1
  80. package/docs/patterns/components-intakemodal--intake-modal-pattern.tsx +1 -1
  81. package/docs/patterns/components-kbd--command-row.tsx +1 -1
  82. package/docs/patterns/components-kbd--numbered-choices.tsx +1 -1
  83. package/docs/patterns/components-kbd--shortcut.tsx +1 -1
  84. package/docs/patterns/components-moremenu--action-menu.tsx +1 -1
  85. package/docs/patterns/components-moremenu--in-card-header.tsx +1 -1
  86. package/docs/patterns/components-navlist--side-nav-settings.tsx +1 -1
  87. package/docs/patterns/components-pageheader--app-header-pattern.tsx +1 -1
  88. package/docs/patterns/components-pageheader--page-section-header.tsx +1 -1
  89. package/docs/patterns/components-pageheader--toolbar-header.tsx +1 -1
  90. package/docs/patterns/components-panel--end-detail-rail.tsx +1 -1
  91. package/docs/patterns/components-pillgroup--pill-group-pattern.tsx +1 -1
  92. package/docs/patterns/components-promptbar--pattern-prompt-bar.tsx +1 -1
  93. package/docs/patterns/components-radio-radiogroup--default.tsx +1 -1
  94. package/docs/patterns/components-scrollhorizontal--project-gallery-pattern.tsx +1 -1
  95. package/docs/patterns/components-scrollhorizontal--with-intro.tsx +1 -1
  96. package/docs/patterns/components-sheet--bottom-sheet.tsx +1 -1
  97. package/docs/patterns/components-sheet--end-sheet.tsx +1 -1
  98. package/docs/patterns/components-sitenav--brand-and-cta.tsx +1 -1
  99. package/docs/patterns/components-sitenav--centered-links.tsx +1 -1
  100. package/docs/patterns/components-sitenav--compact.tsx +1 -1
  101. package/docs/patterns/components-sitenav--marketing-header.tsx +1 -1
  102. package/docs/patterns/components-sitenav--mega-menu.tsx +1 -1
  103. package/docs/patterns/components-stat--insights-row.tsx +1 -1
  104. package/docs/patterns/components-stepprogress--step-progress-pattern.tsx +1 -1
  105. package/docs/patterns/components-switch--default.tsx +1 -1
  106. package/docs/patterns/components-switch--settings-row.tsx +1 -1
  107. package/docs/patterns/components-tab--settings-pages.tsx +1 -1
  108. package/docs/patterns/components-taskrows--action-details.tsx +1 -1
  109. package/docs/patterns/components-taskrows--capsules.tsx +1 -1
  110. package/docs/patterns/components-taskrows--card-with-status-rows.tsx +1 -1
  111. package/docs/patterns/components-taskrows--controlled-expand.tsx +1 -1
  112. package/docs/patterns/components-taskrows--custom-slots.tsx +1 -1
  113. package/docs/patterns/components-taskrows--status-list.tsx +1 -1
  114. package/docs/patterns/components-taskrows--tag-chips.tsx +1 -1
  115. package/docs/patterns/components-textlink--external-destination.tsx +1 -1
  116. package/docs/patterns/components-textlink--inline-prose.tsx +1 -1
  117. package/docs/patterns/components-textlink--supporting-copy.tsx +1 -1
  118. package/docs/patterns/components-textsequence--default.tsx +1 -1
  119. package/docs/patterns/components-textsequence--reduced-motion.tsx +1 -1
  120. package/docs/patterns/components-textsequence--shapes.tsx +1 -1
  121. package/docs/patterns/components-toast--stacked-notifications.tsx +1 -1
  122. package/docs/patterns/components-tooltip--controlled.tsx +1 -1
  123. package/docs/patterns/components-tooltip--disabled-control.tsx +1 -1
  124. package/docs/patterns/components-tooltip--icon-action.tsx +1 -1
  125. package/docs/patterns/components-tooltip--keyboard-shortcut.tsx +1 -1
  126. package/docs/patterns/components-tooltip--placement.tsx +1 -1
  127. package/docs/patterns/foundations-scroll-fade--horizontal-rail.tsx +1 -1
  128. package/docs/patterns/foundations-scroll-fade--overflowing-list.tsx +1 -1
  129. package/docs/patterns/guides-chart-explorations--comparison-gallery.tsx +1 -1
  130. package/docs/patterns/guides-overlay-flows--notification-preferences.tsx +1 -1
  131. package/docs/patterns/guides-profile-typography--editorial-profile.tsx +1 -1
  132. package/docs/patterns/index.json +9 -161
  133. package/package.json +1 -1
  134. package/docs/patterns/components-promptbar--pattern-marketing-composer.tsx +0 -37
  135. package/docs/patterns/sites-pitchkit-account-settings--account-settings-owner.tsx +0 -265
  136. package/docs/patterns/sites-pitchkit-creator-identity--creator-identity-owner-settings.tsx +0 -154
  137. package/docs/patterns/sites-pitchkit-creator-identity--creator-identity-public.tsx +0 -96
  138. package/docs/patterns/sites-pitchkit-insights-and-kit--creator-insights-loading.tsx +0 -1006
  139. package/docs/patterns/sites-pitchkit-insights-and-kit--creator-insights.tsx +0 -1031
  140. package/docs/patterns/sites-pitchkit-insights-and-kit--insufficient-audience-data.tsx +0 -1015
  141. package/docs/patterns/sites-pitchkit-insights-and-kit--insufficient-reach-and-audience-data.tsx +0 -1017
  142. package/docs/patterns/sites-pitchkit-insights-and-kit--insufficient-reach-data.tsx +0 -1033
  143. package/docs/patterns/sites-pitchkit-insights-and-kit--owner-pitch-kit.tsx +0 -838
  144. package/docs/patterns/sites-pitchkit-insights-and-kit--shareable-pitch-kit.tsx +0 -608
  145. package/docs/patterns/sites-pitchkit-intro--intro-owner.tsx +0 -161
  146. package/docs/patterns/sites-pitchkit-intro--intro-public.tsx +0 -111
  147. package/docs/patterns/sites-pitchkit-past-brands--past-brands-owner.tsx +0 -611
  148. package/docs/patterns/sites-pitchkit-past-brands--past-brands-public.tsx +0 -299
  149. package/docs/patterns/sites-pitchkit-theme-picker--theme-picker-owner.tsx +0 -832
  150. package/docs/patterns/sites-whatmatters-intake--start-a-project-pattern.tsx +0 -234
  151. package/docs/patterns/sites-whatmatters-marketing-landing--marketing-landing.tsx +0 -87
  152. package/docs/patterns/sites-whatmatters-prompt-chat--landing-to-chat.tsx +0 -899
  153. package/docs/patterns/sites-whatmatters-rfp-submitted--rfp-submitted.tsx +0 -302
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@thewhatmatters/wmds",
3
3
  "description": "WhatMatters Design System — React components, Tailwind v4 theme, and Storybook patterns",
4
- "version": "0.2.0",
4
+ "version": "0.4.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -1,37 +0,0 @@
1
- // @thewhatmatters/wmds@0.2.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 ask page: route to /ask?q=<prompt>, where the ask page passes
11
- * `q` to AskWhatMatters as `initialPrompt`.
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
- }
@@ -1,265 +0,0 @@
1
- // @thewhatmatters/wmds@0.2.0 · Pattern — account settings (owner)
2
- // Storybook: Sites/PitchKit/Account settings → Pattern — account settings (owner) (?path=/story/sites-pitchkit-account-settings--account-settings-owner)
3
- // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
-
5
- import { useState } from "react";
6
- import {
7
- AlertDialog,
8
- Avatar,
9
- Badge,
10
- Button,
11
- Card,
12
- Chip,
13
- Dialog,
14
- Dropdown,
15
- TextLink,
16
- Toaster,
17
- cardTitleClasses,
18
- toast,
19
- } from "@thewhatmatters/wmds";
20
-
21
- const compactNumber = new Intl.NumberFormat("en", {
22
- notation: "compact",
23
- maximumFractionDigits: 1,
24
- });
25
-
26
-
27
- export interface PitchKitCreatorIdentity {
28
- displayName?: string;
29
- /** Without the @ — shown as @handle, shared as /k/[handle]. */
30
- handle: string;
31
- profilePictureUrl?: string;
32
- followersCount?: number;
33
- professionalAccount?: "Business" | "Creator";
34
- connected?: boolean;
35
- lastSyncedLabel?: string;
36
- }
37
-
38
- function CreatorIdentityStrip({
39
- identity,
40
- nameAs = "h1",
41
- showProfessionalChip = false,
42
- }: {
43
- identity: PitchKitCreatorIdentity;
44
- nameAs?: "h1" | "p";
45
- showProfessionalChip?: boolean;
46
- }) {
47
- const NameTag = nameAs;
48
- const avatarName = identity.displayName ?? identity.handle;
49
- const handleLabel = `@${identity.handle}`;
50
- const followerLabel =
51
- identity.followersCount == null
52
- ? null
53
- : `${compactNumber.format(identity.followersCount)} followers`;
54
- const meta = [handleLabel, followerLabel].filter(Boolean).join(" · ");
55
- const showTitleRow =
56
- identity.displayName != null ||
57
- (showProfessionalChip && identity.professionalAccount != null);
58
-
59
- return (
60
- <div className="flex flex-wrap items-center gap-4">
61
- <Avatar
62
- name={avatarName}
63
- src={identity.profilePictureUrl}
64
- size="lg"
65
- />
66
- <div className="flex min-w-0 flex-col gap-1">
67
- {showTitleRow ? (
68
- <div className="flex flex-wrap items-center gap-2">
69
- {identity.displayName != null ? (
70
- <NameTag className="type-heading-2 text-fg">
71
- {identity.displayName}
72
- </NameTag>
73
- ) : null}
74
- {showProfessionalChip && identity.professionalAccount != null ? (
75
- <Chip readOnly size="sm">
76
- {identity.professionalAccount}
77
- </Chip>
78
- ) : null}
79
- </div>
80
- ) : null}
81
- <p className="type-body text-fg text-muted">{meta}</p>
82
- </div>
83
- </div>
84
- );
85
- }
86
-
87
-
88
- function copyShareKitUrl(handle: string) {
89
- const path = `/k/${handle}`;
90
- void navigator.clipboard.writeText(path);
91
- toast.add({
92
- title: "Kit URL copied",
93
- description: path,
94
- tone: "success",
95
- });
96
- }
97
-
98
- function AccountSettingsDialog({
99
- identity,
100
- open,
101
- onOpenChange,
102
- }: {
103
- identity: PitchKitCreatorIdentity;
104
- open: boolean;
105
- onOpenChange: (open: boolean) => void;
106
- }) {
107
- return (
108
- <Dialog open={open} onOpenChange={onOpenChange}>
109
- <Dialog.Content size="md" title="Account settings">
110
- <div className="flex w-full min-w-0 flex-col gap-4">
111
- <Card variant="outlined" shape="rounded" bodyTerminal className="col-span-full">
112
- <Card.Header
113
- start={<h2 className={cardTitleClasses}>Connected Instagram</h2>}
114
- end={
115
- identity.connected ? (
116
- <Badge variant="success" emphasis="muted" size="sm">
117
- Connected
118
- </Badge>
119
- ) : null
120
- }
121
- />
122
- <Card.Body>
123
- <div className="flex min-w-0 flex-col gap-4 px-3.5 py-[16px]">
124
- <CreatorIdentityStrip
125
- identity={identity}
126
- nameAs="p"
127
- showProfessionalChip
128
- />
129
- {identity.lastSyncedLabel != null ? (
130
- <p className="type-supporting text-muted text-muted">
131
- Last synced {identity.lastSyncedLabel}
132
- </p>
133
- ) : null}
134
- </div>
135
- </Card.Body>
136
- </Card>
137
- </div>
138
- </Dialog.Content>
139
- </Dialog>
140
- );
141
- }
142
-
143
- function OwnerAccountMenu({ identity }: { identity: PitchKitCreatorIdentity }) {
144
- const [menuOpen, setMenuOpen] = useState(false);
145
- const [settingsOpen, setSettingsOpen] = useState(false);
146
- const [deleteOpen, setDeleteOpen] = useState(false);
147
-
148
- function handleAction(actionId: string) {
149
- setMenuOpen(false);
150
- if (actionId === "settings") {
151
- setSettingsOpen(true);
152
- return;
153
- }
154
- if (actionId === "share") {
155
- copyShareKitUrl(identity.handle);
156
- return;
157
- }
158
- if (actionId === "delete") {
159
- setDeleteOpen(true);
160
- }
161
- }
162
-
163
- return (
164
- <>
165
- <div className="relative">
166
- <Button
167
- type="button"
168
- role="ghost"
169
- size="sm"
170
- aria-label="My account"
171
- aria-haspopup="menu"
172
- aria-expanded={menuOpen}
173
- className="size-9 min-h-9 gap-0 px-0 py-0 focus-visible:ring-offset-0"
174
- onClick={() => setMenuOpen((open) => !open)}
175
- >
176
- <Avatar
177
- name={identity.displayName ?? identity.handle}
178
- src={identity.profilePictureUrl}
179
- size="md"
180
- />
181
- </Button>
182
- {menuOpen ? (
183
- <Dropdown.Menu
184
- role="menu"
185
- aria-label="My account"
186
- className="absolute end-0 top-full mt-1 min-w-56"
187
- >
188
- <li role="presentation">
189
- <p className="type-supporting font-medium uppercase tracking-wider text-muted px-3.5 py-2">My account</p>
190
- </li>
191
- <li role="presentation">
192
- <Dropdown.Item role="menuitem" truncate={false} onClick={() => handleAction("settings")}>
193
- Account settings
194
- </Dropdown.Item>
195
- </li>
196
- <li role="presentation">
197
- <Dropdown.Item role="menuitem" truncate={false} onClick={() => handleAction("share")}>
198
- Share kit
199
- </Dropdown.Item>
200
- </li>
201
- <li role="separator" className="mx-1.5 my-0.5 border-0 border-t border-border" />
202
- <li role="presentation">
203
- <Dropdown.Item role="menuitem" truncate={false} onClick={() => handleAction("signout")}>
204
- Sign out
205
- </Dropdown.Item>
206
- </li>
207
- <li role="presentation">
208
- <Dropdown.Item role="menuitem" truncate={false} onClick={() => handleAction("disconnect")}>
209
- Disconnect
210
- </Dropdown.Item>
211
- </li>
212
- <li role="presentation">
213
- <Dropdown.Item role="menuitem" truncate={false} onClick={() => handleAction("delete")}>Delete</Dropdown.Item>
214
- </li>
215
- </Dropdown.Menu>
216
- ) : null}
217
- </div>
218
- <AccountSettingsDialog
219
- identity={identity}
220
- open={settingsOpen}
221
- onOpenChange={setSettingsOpen}
222
- />
223
- <AlertDialog
224
- open={deleteOpen}
225
- onOpenChange={setDeleteOpen}
226
- title="Delete your Pitchkit account?"
227
- description="This permanently deletes your kit, stored media copies, and connection. Your Instagram account is not deleted. This cannot be undone."
228
- cancelLabel="Cancel"
229
- confirmLabel="Delete account"
230
- confirmRole="destructive"
231
- onConfirm={() => setDeleteOpen(false)}
232
- />
233
- </>
234
- );
235
- }
236
-
237
- function PitchKitPageFooter() {
238
- return (
239
- <div className="band pb-6 pt-10">
240
- <footer className="col-span-full flex items-center justify-center gap-4">
241
- <TextLink href="/privacy">Privacy</TextLink>
242
- <TextLink href="mailto:hello@whatmatters.com">Support</TextLink>
243
- </footer>
244
- </div>
245
- );
246
- }
247
-
248
-
249
- export function AccountSettingsOwnerPage({ identity }: { identity: PitchKitCreatorIdentity }) {
250
- return (
251
- <main className="grid-page min-h-screen bg-body [--grid-column-gap:8px] [--grid-max:1140px] [padding-bottom:44px]">
252
- <div className="band pb-4">
253
- <header className="col-span-full grid grid-cols-[1fr_auto_1fr] items-center gap-3">
254
- <span className="type-heading-4 text-fg text-fg">PitchKit</span>
255
- <span />
256
- <span className="justify-self-end">
257
- <OwnerAccountMenu identity={identity} />
258
- </span>
259
- </header>
260
- </div>
261
- <PitchKitPageFooter />
262
- <Toaster position="bottom-right" />
263
- </main>
264
- );
265
- }
@@ -1,154 +0,0 @@
1
- // @thewhatmatters/wmds@0.2.0 · Pattern — creator identity (owner settings)
2
- // Storybook: Sites/PitchKit/Creator identity → Pattern — creator identity (owner settings) (?path=/story/sites-pitchkit-creator-identity--creator-identity-owner-settings)
3
- // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
-
5
- import { Avatar, Badge, Button, Card, Chip, PageHeader, TextLink, Toaster, cardTitleClasses, toast } from "@thewhatmatters/wmds";
6
- import { Copy } from "lucide-react";
7
-
8
- const compactNumber = new Intl.NumberFormat("en", {
9
- notation: "compact",
10
- maximumFractionDigits: 1,
11
- });
12
-
13
-
14
- export interface PitchKitCreatorIdentity {
15
- displayName?: string;
16
- /** Without the @ — shown as @handle, shared as /k/[handle]. */
17
- handle: string;
18
- profilePictureUrl?: string;
19
- followersCount?: number;
20
- professionalAccount?: "Business" | "Creator";
21
- connected?: boolean;
22
- lastSyncedLabel?: string;
23
- }
24
-
25
- function CreatorIdentityStrip({
26
- identity,
27
- nameAs = "h1",
28
- showProfessionalChip = false,
29
- }: {
30
- identity: PitchKitCreatorIdentity;
31
- nameAs?: "h1" | "p";
32
- showProfessionalChip?: boolean;
33
- }) {
34
- const NameTag = nameAs;
35
- const avatarName = identity.displayName ?? identity.handle;
36
- const handleLabel = `@${identity.handle}`;
37
- const followerLabel =
38
- identity.followersCount == null
39
- ? null
40
- : `${compactNumber.format(identity.followersCount)} followers`;
41
- const meta = [handleLabel, followerLabel].filter(Boolean).join(" · ");
42
- const showTitleRow =
43
- identity.displayName != null ||
44
- (showProfessionalChip && identity.professionalAccount != null);
45
-
46
- return (
47
- <div className="flex flex-wrap items-center gap-4">
48
- <Avatar
49
- name={avatarName}
50
- src={identity.profilePictureUrl}
51
- size="lg"
52
- />
53
- <div className="flex min-w-0 flex-col gap-1">
54
- {showTitleRow ? (
55
- <div className="flex flex-wrap items-center gap-2">
56
- {identity.displayName != null ? (
57
- <NameTag className="type-heading-2 text-fg">
58
- {identity.displayName}
59
- </NameTag>
60
- ) : null}
61
- {showProfessionalChip && identity.professionalAccount != null ? (
62
- <Chip readOnly size="sm">
63
- {identity.professionalAccount}
64
- </Chip>
65
- ) : null}
66
- </div>
67
- ) : null}
68
- <p className="type-body text-fg text-muted">{meta}</p>
69
- </div>
70
- </div>
71
- );
72
- }
73
-
74
-
75
- export function CreatorIdentityOwnerSettingsPage({ identity }: { identity: PitchKitCreatorIdentity }) {
76
- const sharePath = `/k/${identity.handle}`;
77
-
78
- function copyShareKitUrl() {
79
- void navigator.clipboard.writeText(sharePath);
80
- toast.add({
81
- title: "Kit URL copied",
82
- description: sharePath,
83
- tone: "success",
84
- });
85
- }
86
-
87
- return (
88
- <main className="grid-page min-h-screen bg-body [--grid-column-gap:8px] [--grid-max:1140px] [padding-bottom:44px]">
89
- <div className="band pb-4">
90
- <header className="col-span-full grid grid-cols-[1fr_auto_1fr] items-center gap-3">
91
- <span className="type-heading-4 text-fg text-fg">PitchKit</span>
92
- <span />
93
- <span className="justify-self-end">
94
- <Avatar
95
- name={identity.displayName ?? identity.handle}
96
- src={identity.profilePictureUrl}
97
- size="md"
98
- />
99
- </span>
100
- </header>
101
- </div>
102
-
103
- <div className="band pt-6 sm:pt-8">
104
- <div className="band min-w-0 gap-y-6 sm:gap-y-8">
105
- <section className="col-span-full">
106
- <PageHeader variant="page" title="Settings" />
107
- <div className="flex max-w-2xl flex-col gap-1">
108
- <p className="type-body text-fg text-muted">
109
- Instagram connection for this PitchKit.
110
- </p>
111
- </div>
112
- </section>
113
-
114
- <Card variant="outlined" shape="rounded" bodyTerminal className="col-span-full">
115
- <Card.Header
116
- start={<h2 className={cardTitleClasses}>Connected Instagram</h2>}
117
- end={
118
- identity.connected ? (
119
- <Badge variant="success" emphasis="muted" size="sm">
120
- Connected
121
- </Badge>
122
- ) : null
123
- }
124
- />
125
- <Card.Body>
126
- <div className="flex min-w-0 flex-col gap-4 px-3.5 py-[16px]">
127
- <CreatorIdentityStrip
128
- identity={identity}
129
- nameAs="p"
130
- showProfessionalChip
131
- />
132
- <div className="flex min-w-0 flex-col gap-2">
133
- <span className="type-supporting font-medium uppercase tracking-wider text-muted text-muted">Share kit</span>
134
- <div className="flex min-w-0 flex-wrap items-center gap-3">
135
- <TextLink href={sharePath}>{sharePath}</TextLink>
136
- <Button role="secondary" size="sm" icon={<Copy />} onClick={copyShareKitUrl}>
137
- Copy
138
- </Button>
139
- </div>
140
- </div>
141
- {identity.lastSyncedLabel != null ? (
142
- <p className="type-supporting text-muted text-muted">
143
- Last synced {identity.lastSyncedLabel}
144
- </p>
145
- ) : null}
146
- </div>
147
- </Card.Body>
148
- </Card>
149
- </div>
150
- </div>
151
- <Toaster position="bottom-right" />
152
- </main>
153
- );
154
- }
@@ -1,96 +0,0 @@
1
- // @thewhatmatters/wmds@0.2.0 · Pattern — creator identity (public)
2
- // Storybook: Sites/PitchKit/Creator identity → Pattern — creator identity (public) (?path=/story/sites-pitchkit-creator-identity--creator-identity-public)
3
- // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
-
5
- import { Avatar, Chip } from "@thewhatmatters/wmds";
6
-
7
- const compactNumber = new Intl.NumberFormat("en", {
8
- notation: "compact",
9
- maximumFractionDigits: 1,
10
- });
11
-
12
-
13
- export interface PitchKitCreatorIdentity {
14
- displayName?: string;
15
- /** Without the @ — shown as @handle, shared as /k/[handle]. */
16
- handle: string;
17
- profilePictureUrl?: string;
18
- followersCount?: number;
19
- professionalAccount?: "Business" | "Creator";
20
- connected?: boolean;
21
- lastSyncedLabel?: string;
22
- }
23
-
24
- function CreatorIdentityStrip({
25
- identity,
26
- nameAs = "h1",
27
- showProfessionalChip = false,
28
- }: {
29
- identity: PitchKitCreatorIdentity;
30
- nameAs?: "h1" | "p";
31
- showProfessionalChip?: boolean;
32
- }) {
33
- const NameTag = nameAs;
34
- const avatarName = identity.displayName ?? identity.handle;
35
- const handleLabel = `@${identity.handle}`;
36
- const followerLabel =
37
- identity.followersCount == null
38
- ? null
39
- : `${compactNumber.format(identity.followersCount)} followers`;
40
- const meta = [handleLabel, followerLabel].filter(Boolean).join(" · ");
41
- const showTitleRow =
42
- identity.displayName != null ||
43
- (showProfessionalChip && identity.professionalAccount != null);
44
-
45
- return (
46
- <div className="flex flex-wrap items-center gap-4">
47
- <Avatar
48
- name={avatarName}
49
- src={identity.profilePictureUrl}
50
- size="lg"
51
- />
52
- <div className="flex min-w-0 flex-col gap-1">
53
- {showTitleRow ? (
54
- <div className="flex flex-wrap items-center gap-2">
55
- {identity.displayName != null ? (
56
- <NameTag className="type-heading-2 text-fg">
57
- {identity.displayName}
58
- </NameTag>
59
- ) : null}
60
- {showProfessionalChip && identity.professionalAccount != null ? (
61
- <Chip readOnly size="sm">
62
- {identity.professionalAccount}
63
- </Chip>
64
- ) : null}
65
- </div>
66
- ) : null}
67
- <p className="type-body text-fg text-muted">{meta}</p>
68
- </div>
69
- </div>
70
- );
71
- }
72
-
73
-
74
- export function CreatorIdentityPublicPage({ identity }: { identity: PitchKitCreatorIdentity }) {
75
- return (
76
- <main className="grid-page min-h-screen bg-body [--grid-column-gap:8px] [--grid-max:1140px] [padding-bottom:44px]">
77
- <div className="band pb-4">
78
- <header className="col-span-full grid grid-cols-[1fr_auto_1fr] items-center gap-3">
79
- <span className="type-heading-4 text-fg text-fg">PitchKit</span>
80
- </header>
81
- </div>
82
-
83
- <div className="band pt-6 sm:pt-8">
84
- <div className="band min-w-0 gap-y-6 sm:gap-y-8">
85
- <section className="col-span-full border-b border-border pb-6">
86
- <CreatorIdentityStrip
87
- identity={identity}
88
- nameAs="h1"
89
- showProfessionalChip
90
- />
91
- </section>
92
- </div>
93
- </div>
94
- </main>
95
- );
96
- }