@flamingo-stack/openframe-frontend-core 0.0.222 → 0.0.223

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 (183) hide show
  1. package/dist/{chunk-AIKPR6BE.js → chunk-4VHWSAQR.js} +6069 -5235
  2. package/dist/chunk-4VHWSAQR.js.map +1 -0
  3. package/dist/{chunk-GMNE7P7V.cjs → chunk-4WBVMIKQ.cjs} +26 -26
  4. package/dist/{chunk-GMNE7P7V.cjs.map → chunk-4WBVMIKQ.cjs.map} +1 -1
  5. package/dist/{chunk-QYRV6MKX.js → chunk-53EA4QPZ.js} +13 -7
  6. package/dist/chunk-53EA4QPZ.js.map +1 -0
  7. package/dist/{chunk-4JOWZLEL.cjs → chunk-7TKYFZ3L.cjs} +7 -7
  8. package/dist/{chunk-4JOWZLEL.cjs.map → chunk-7TKYFZ3L.cjs.map} +1 -1
  9. package/dist/{chunk-IZA5WF44.cjs → chunk-ABBU7QOM.cjs} +12 -12
  10. package/dist/{chunk-IZA5WF44.cjs.map → chunk-ABBU7QOM.cjs.map} +1 -1
  11. package/dist/{chunk-KM4KK2A6.cjs → chunk-ENDUMC7Z.cjs} +2558 -1724
  12. package/dist/chunk-ENDUMC7Z.cjs.map +1 -0
  13. package/dist/{chunk-CCSEXVI4.js → chunk-GYYGA24C.js} +2 -2
  14. package/dist/{chunk-RMOHKAHA.js → chunk-ISWWP2BH.js} +3 -3
  15. package/dist/{chunk-QNYH3WUU.cjs → chunk-JUWPBMQM.cjs} +13 -7
  16. package/dist/chunk-JUWPBMQM.cjs.map +1 -0
  17. package/dist/{chunk-A2SFHYVF.cjs → chunk-KXLTWANQ.cjs} +10 -10
  18. package/dist/{chunk-A2SFHYVF.cjs.map → chunk-KXLTWANQ.cjs.map} +1 -1
  19. package/dist/{chunk-ND24XSVT.js → chunk-TA6Z2AKD.js} +3 -3
  20. package/dist/chunk-TA6Z2AKD.js.map +1 -0
  21. package/dist/{chunk-HRIAZQ5D.js → chunk-WOKB6RJ7.js} +3 -3
  22. package/dist/components/chat/chat-archive-page.d.ts.map +1 -1
  23. package/dist/components/chat/chat-composer.d.ts.map +1 -1
  24. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  25. package/dist/components/chat/chat-message-skeleton.d.ts +19 -4
  26. package/dist/components/chat/chat-message-skeleton.d.ts.map +1 -1
  27. package/dist/components/chat/chat-panel-header-mobile.d.ts +24 -0
  28. package/dist/components/chat/chat-panel-header-mobile.d.ts.map +1 -0
  29. package/dist/components/chat/chat-panel-header.d.ts +6 -0
  30. package/dist/components/chat/chat-panel-header.d.ts.map +1 -1
  31. package/dist/components/chat/chat-quick-action-row.d.ts +31 -0
  32. package/dist/components/chat/chat-quick-action-row.d.ts.map +1 -0
  33. package/dist/components/chat/embeddable-chat.d.ts +27 -0
  34. package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
  35. package/dist/components/chat/entity-cards/dispatch.d.ts +14 -0
  36. package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
  37. package/dist/components/chat/entity-cards/github-activity-card.d.ts +10 -1
  38. package/dist/components/chat/entity-cards/github-activity-card.d.ts.map +1 -1
  39. package/dist/components/chat/guide-welcome.d.ts.map +1 -1
  40. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +9 -0
  41. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  42. package/dist/components/chat/hooks/use-slash-commands.d.ts +26 -0
  43. package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -1
  44. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +12 -1
  45. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  46. package/dist/components/chat/hooks/use-unified-chat.d.ts +12 -0
  47. package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -1
  48. package/dist/components/chat/index.cjs +9 -3
  49. package/dist/components/chat/index.cjs.map +1 -1
  50. package/dist/components/chat/index.js +8 -2
  51. package/dist/components/chat/mingo-chat-history.d.ts +10 -0
  52. package/dist/components/chat/mingo-chat-history.d.ts.map +1 -1
  53. package/dist/components/chat/mingo-info-card.d.ts +63 -0
  54. package/dist/components/chat/mingo-info-card.d.ts.map +1 -0
  55. package/dist/components/chat/mingo-welcome.d.ts +14 -1
  56. package/dist/components/chat/mingo-welcome.d.ts.map +1 -1
  57. package/dist/components/chat/types/chat.types.d.ts +6 -0
  58. package/dist/components/chat/types/chat.types.d.ts.map +1 -1
  59. package/dist/components/chat/types/unified-chat-state.types.d.ts +30 -0
  60. package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
  61. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  62. package/dist/components/contact/index.cjs +4 -4
  63. package/dist/components/contact/index.js +3 -3
  64. package/dist/components/features/index.cjs +3 -3
  65. package/dist/components/features/index.js +2 -2
  66. package/dist/components/index.cjs +110 -104
  67. package/dist/components/index.cjs.map +1 -1
  68. package/dist/components/index.js +36 -30
  69. package/dist/components/index.js.map +1 -1
  70. package/dist/components/navigation/app-layout-drawer.d.ts +7 -0
  71. package/dist/components/navigation/app-layout-drawer.d.ts.map +1 -1
  72. package/dist/components/navigation/index.cjs +3 -3
  73. package/dist/components/navigation/index.js +2 -2
  74. package/dist/components/onboarding-guides/index.cjs +26 -26
  75. package/dist/components/onboarding-guides/index.js +4 -4
  76. package/dist/components/tickets/index.cjs +67 -67
  77. package/dist/components/tickets/index.js +5 -5
  78. package/dist/components/ui/actions-menu.d.ts +9 -0
  79. package/dist/components/ui/actions-menu.d.ts.map +1 -1
  80. package/dist/components/ui/dropdown-button.d.ts +2 -2
  81. package/dist/components/ui/dropdown-button.d.ts.map +1 -1
  82. package/dist/components/ui/index.cjs +9 -3
  83. package/dist/components/ui/index.cjs.map +1 -1
  84. package/dist/components/ui/index.js +8 -2
  85. package/dist/components/ui/modal-v2.d.ts.map +1 -1
  86. package/dist/components/ui/more-actions-menu.d.ts +13 -0
  87. package/dist/components/ui/more-actions-menu.d.ts.map +1 -1
  88. package/dist/components/ui/square-avatar.d.ts +4 -0
  89. package/dist/components/ui/square-avatar.d.ts.map +1 -1
  90. package/dist/components/ui/textarea.d.ts.map +1 -1
  91. package/dist/hooks/index.cjs +2 -2
  92. package/dist/hooks/index.js +1 -1
  93. package/dist/hooks/ui/use-auto-limit-tags.d.ts +7 -1
  94. package/dist/hooks/ui/use-auto-limit-tags.d.ts.map +1 -1
  95. package/dist/index.cjs +9 -3
  96. package/dist/index.cjs.map +1 -1
  97. package/dist/index.js +8 -2
  98. package/package.json +1 -1
  99. package/src/components/chat/chat-archive-page.tsx +32 -7
  100. package/src/components/chat/chat-composer.tsx +6 -2
  101. package/src/components/chat/chat-message-enhanced.tsx +24 -7
  102. package/src/components/chat/chat-message-list.tsx +1 -1
  103. package/src/components/chat/chat-message-skeleton.tsx +60 -60
  104. package/src/components/chat/chat-panel-header-mobile.tsx +94 -0
  105. package/src/components/chat/chat-panel-header.tsx +78 -50
  106. package/src/components/chat/chat-quick-action-row.tsx +146 -0
  107. package/src/components/chat/embeddable-chat.tsx +140 -45
  108. package/src/components/chat/entity-cards/dispatch.tsx +770 -232
  109. package/src/components/chat/entity-cards/github-activity-card.tsx +9 -3
  110. package/src/components/chat/guide-welcome.tsx +11 -8
  111. package/src/components/chat/hooks/use-nats-chat-adapter.ts +80 -7
  112. package/src/components/chat/hooks/use-slash-commands.ts +39 -0
  113. package/src/components/chat/hooks/use-sse-chat-adapter.ts +49 -45
  114. package/src/components/chat/hooks/use-unified-chat.ts +31 -8
  115. package/src/components/chat/mingo-chat-history.tsx +118 -36
  116. package/src/components/chat/mingo-info-card.tsx +214 -0
  117. package/src/components/chat/mingo-welcome.tsx +89 -36
  118. package/src/components/chat/types/chat.types.ts +4 -0
  119. package/src/components/chat/types/unified-chat-state.types.ts +35 -0
  120. package/src/components/chat/utils/process-historical-messages.ts +8 -0
  121. package/src/components/content-loading-container.tsx +1 -1
  122. package/src/components/empty-state.tsx +3 -3
  123. package/src/components/faq-accordion.tsx +2 -2
  124. package/src/components/features/changelog-manager.tsx +2 -2
  125. package/src/components/features/highlight-config-section.tsx +2 -2
  126. package/src/components/features/og-editor-preview.tsx +3 -3
  127. package/src/components/features/release-media-manager.tsx +2 -2
  128. package/src/components/loading/card-skeleton.tsx +3 -3
  129. package/src/components/loading/device-card-skeleton.tsx +1 -1
  130. package/src/components/loading/margin-report-skeleton.tsx +2 -2
  131. package/src/components/loading/organization-card-skeleton.tsx +1 -1
  132. package/src/components/loading/organization-icon-skeleton.tsx +1 -1
  133. package/src/components/loading/page-layout-skeleton.tsx +9 -9
  134. package/src/components/loading/users-grid-skeleton.tsx +2 -2
  135. package/src/components/logs-list.tsx +1 -1
  136. package/src/components/media-carousel.tsx +1 -1
  137. package/src/components/navigation/app-layout-drawer.tsx +70 -6
  138. package/src/components/open-source-features.tsx +2 -2
  139. package/src/components/ui/actions-menu.tsx +36 -13
  140. package/src/components/ui/allowed-domains-input.tsx +3 -3
  141. package/src/components/ui/cursor-pagination.tsx +1 -1
  142. package/src/components/ui/dropdown-button.tsx +6 -6
  143. package/src/components/ui/info-row.tsx +2 -2
  144. package/src/components/ui/modal-v2.tsx +8 -1
  145. package/src/components/ui/more-actions-menu.tsx +13 -0
  146. package/src/components/ui/square-avatar.tsx +6 -1
  147. package/src/components/ui/tags-input.tsx +1 -1
  148. package/src/components/ui/textarea.tsx +18 -4
  149. package/src/components/vendor-icon.tsx +1 -1
  150. package/src/components/vendor-tag.tsx +1 -1
  151. package/src/components/why-it-matters.tsx +1 -1
  152. package/src/hooks/ui/use-auto-limit-tags.ts +22 -8
  153. package/src/stories/ActionsMenu.stories.tsx +256 -0
  154. package/src/stories/AppLayoutSidebar.stories.tsx +6 -0
  155. package/src/stories/Board.stories.tsx +1 -1
  156. package/src/stories/ChatMingoInfoCards.stories.tsx +748 -0
  157. package/src/stories/ChatTicketList.stories.tsx +1 -1
  158. package/src/stories/DataTable.stories.tsx +17 -13
  159. package/src/stories/EmbeddableChat.stories.tsx +233 -1
  160. package/src/stories/MingoInfoCard.stories.tsx +193 -0
  161. package/src/stories/MingoOnboardingCard.stories.tsx +1 -1
  162. package/src/stories/Modal.stories.tsx +1 -0
  163. package/src/stories/NotificationDrawer.stories.tsx +14 -3
  164. package/src/stories/PageActions.stories.tsx +4 -4
  165. package/src/stories/PageContainer.stories.tsx +5 -5
  166. package/src/stories/PageLayout.stories.tsx +1 -1
  167. package/src/stories/TabSelector.stories.tsx +2 -2
  168. package/src/stories/Tag.stories.tsx +10 -5
  169. package/src/stories/TicketInfoSection.stories.tsx +23 -11
  170. package/src/stories/Toaster.stories.tsx +5 -5
  171. package/src/stories/__fixtures__/chat-card-decorator.tsx +44 -0
  172. package/dist/chunk-AIKPR6BE.js.map +0 -1
  173. package/dist/chunk-KM4KK2A6.cjs.map +0 -1
  174. package/dist/chunk-ND24XSVT.js.map +0 -1
  175. package/dist/chunk-QNYH3WUU.cjs.map +0 -1
  176. package/dist/chunk-QYRV6MKX.js.map +0 -1
  177. package/src/stories/.TicketDescriptionViewer.stories.md +0 -39
  178. package/src/stories/.TicketKnowledgeBaseList.stories.md +0 -36
  179. package/src/stories/TicketDescriptionViewer.stories.tsx +0 -70
  180. package/src/stories/TicketKnowledgeBaseList.stories.tsx +0 -51
  181. /package/dist/{chunk-CCSEXVI4.js.map → chunk-GYYGA24C.js.map} +0 -0
  182. /package/dist/{chunk-RMOHKAHA.js.map → chunk-ISWWP2BH.js.map} +0 -0
  183. /package/dist/{chunk-HRIAZQ5D.js.map → chunk-WOKB6RJ7.js.map} +0 -0
@@ -0,0 +1,748 @@
1
+ import type { Meta, StoryObj } from '@storybook/nextjs-vite'
2
+ import type { ReactNode } from 'react'
3
+ import { MingoInfoCard } from '../components/chat/mingo-info-card'
4
+ import { ChatColumnDecorator, makeAnchorProps } from './__fixtures__/chat-card-decorator'
5
+ import { MingoIcon } from '../components/icons'
6
+ import { EyeIcon } from '../components/icons-v2-generated/interface/eye-icon'
7
+ import { ArrowRightUpIcon } from '../components/icons-v2-generated/arrows/arrow-right-up-icon'
8
+ import { TagIcon } from '../components/icons-v2-generated/shopping/tag-icon'
9
+ import { CodingCommitIcon } from '../components/icons-v2-generated/coding/coding-commit-icon'
10
+ import { CodingPullRequestIcon } from '../components/icons-v2-generated/coding/coding-pull-request-icon'
11
+ import { CodeIcon } from '../components/icons-v2-generated/coding/code-icon'
12
+ import { SlackLogoGreyIcon } from '../components/icons-v2-generated/brand-logos/slack-logo-grey-icon'
13
+ import { FileContentIcon } from '../components/icons-v2-generated/documents/file-content-icon'
14
+ import { ChartBar01VerIcon } from '../components/icons-v2-generated/charts/chart-bar-01-ver-icon'
15
+ import { ChartPieIcon } from '../components/icons-v2-generated/charts/chart-pie-icon'
16
+ import { MoneyBillDollarIcon } from '../components/icons-v2-generated/finance/money-bill-dollar-icon'
17
+ import { BankIcon } from '../components/icons-v2-generated/finance/bank-icon'
18
+ import { CoinsExchangeCurrencyIcon } from '../components/icons-v2-generated/finance/coins-exchange-currency-icon'
19
+ import { NewspaperIcon } from '../components/icons-v2-generated/documents/newspaper-icon'
20
+ import { TrophyIcon } from '../components/icons-v2-generated/sport/trophy-icon'
21
+ import { MicrophoneIcon } from '../components/icons-v2-generated/household/microphone-icon'
22
+ import { Rocket02Icon } from '../components/icons-v2-generated/vehicles-and-delivery/rocket-02-icon'
23
+ import { TruckFastIcon } from '../components/icons-v2-generated/vehicles-and-delivery/truck-fast-icon'
24
+ import { PresentationBarIcon } from '../components/icons-v2-generated/charts/presentation-bar-icon'
25
+ import { PresentationLineIcon } from '../components/icons-v2-generated/charts/presentation-line-icon'
26
+ import { CalendarIcon } from '../components/icons-v2-generated/date-and-time/calendar-icon'
27
+ import { CompassIcon } from '../components/icons-v2-generated/map-and-travel/compass-icon'
28
+ import { MapIcon } from '../components/icons-v2-generated/map-and-travel/map-icon'
29
+ import { CheckSquareIcon } from '../components/icons-v2-generated/signs-and-symbols/check-square-icon'
30
+ import { Megaphone01Icon } from '../components/icons-v2-generated/shopping/megaphone-01-icon'
31
+
32
+ /**
33
+ * Chat entity-cards re-skinned with `MingoInfoCard`.
34
+ *
35
+ * As each `[card://type:id]` registry entry in `entity-cards/dispatch.tsx` is
36
+ * migrated to render a `MingoInfoCard`, its variants are mirrored here so the
37
+ * compact in-chat appearance can be reviewed in isolation — same column width
38
+ * and background the dispatch renders into, without booting the chat runtime.
39
+ *
40
+ * Each `render` reproduces the registry's field mapping for that card type
41
+ * (icon, status pill, description, "⋯" menu). Anchor clicks are neutralized via
42
+ * `makeAnchorProps` so the Storybook iframe doesn't navigate away.
43
+ */
44
+ const meta: Meta<typeof MingoInfoCard> = {
45
+ title: 'Chat/ChatMingoInfoCards',
46
+ component: MingoInfoCard,
47
+ parameters: {
48
+ layout: 'fullscreen',
49
+ docs: {
50
+ description: {
51
+ component:
52
+ 'In-chat entity cards rendered through `MingoInfoCard`. One section per migrated `CHAT_CARD_REGISTRY` type — mirrors the icon / status / description / menu mapping from `entity-cards/dispatch.tsx`.',
53
+ },
54
+ },
55
+ },
56
+ decorators: [
57
+ (Story) => (
58
+ <ChatColumnDecorator>
59
+ <Story />
60
+ </ChatColumnDecorator>
61
+ ),
62
+ ],
63
+ }
64
+
65
+ export default meta
66
+ type Story = StoryObj<typeof meta>
67
+
68
+ /** Shared "⋯" overflow menu (Figma `7740:55075`): "Ask Mingo" (Mingo logo)
69
+ * followed by "Open Details" (eye) with a trailing ↗ open-in-new-tab side
70
+ * button. */
71
+ const openMenu = (
72
+ href: string,
73
+ openDetails?: { label: string; icon: ReactNode },
74
+ ) => [
75
+ {
76
+ items: [
77
+ {
78
+ id: 'discuss',
79
+ label: 'Ask Mingo',
80
+ icon: (
81
+ <MingoIcon
82
+ className="size-5"
83
+ color="white"
84
+ eyesColor="var(--ods-flamingo-cyan-base)"
85
+ cornerColor="var(--ods-flamingo-cyan-base)"
86
+ />
87
+ ),
88
+ onClick: () => {
89
+ // eslint-disable-next-line no-console
90
+ console.log('[story] ask mingo', href)
91
+ },
92
+ },
93
+ {
94
+ id: 'open-details',
95
+ label: openDetails?.label ?? 'Open Details',
96
+ icon: openDetails?.icon ?? <EyeIcon size={20} />,
97
+ onClick: () => {
98
+ // eslint-disable-next-line no-console
99
+ console.log('[story] open details', href)
100
+ },
101
+ iconAction: {
102
+ icon: <ArrowRightUpIcon size={20} />,
103
+ 'aria-label': 'Open in new tab',
104
+ onClick: () => {
105
+ // eslint-disable-next-line no-console
106
+ console.log('[story] open in new tab', href)
107
+ },
108
+ },
109
+ },
110
+ ],
111
+ },
112
+ ]
113
+
114
+ // =============================================================================
115
+ // HubSpot ticket — icon: HubSpot grey logo · status: ticket state · desc: preview
116
+ // =============================================================================
117
+
118
+ export const HubspotTicket: Story = {
119
+ parameters: {
120
+ docs: {
121
+ description: {
122
+ story:
123
+ 'Registry types `hubspot_ticket` / `_anon` / `_self`. Status pill maps the ticket state (Closed → green, Open → amber, other → grey); description is the ticket preview.',
124
+ },
125
+ },
126
+ },
127
+ render: () => {
128
+ const HREF = 'https://app.hubspot.com/contacts/0/ticket/123'
129
+ return (
130
+ <div className="flex flex-col gap-3">
131
+ <MingoInfoCard
132
+ title="Login page returns 500 after SSO redirect"
133
+ description="Customer cannot sign in via Google SSO since this morning…"
134
+ icon={<TagIcon size={24} />}
135
+ status={{ label: 'Open', variant: 'warning' }}
136
+ anchorProps={makeAnchorProps(HREF)}
137
+ menuGroups={openMenu(HREF, {
138
+ label: 'Open Ticket Details',
139
+ icon: <TagIcon size={20} />,
140
+ })}
141
+ menuAriaLabel="Ticket actions"
142
+ />
143
+ <MingoInfoCard
144
+ title="Export to CSV missing last column"
145
+ description="Resolved — shipped in 2.14.1, customer confirmed the fix."
146
+ icon={<TagIcon size={24} />}
147
+ status={{ label: 'Closed', variant: 'success' }}
148
+ anchorProps={makeAnchorProps(HREF)}
149
+ menuGroups={openMenu(HREF, {
150
+ label: 'Open Ticket Details',
151
+ icon: <TagIcon size={20} />,
152
+ })}
153
+ menuAriaLabel="Ticket actions"
154
+ />
155
+ <MingoInfoCard
156
+ title="Waiting on customer logs for the sync failure"
157
+ description="Pending — asked for the agent log bundle from the affected host."
158
+ icon={<TagIcon size={24} />}
159
+ status={{ label: 'Waiting on us', variant: 'grey' }}
160
+ anchorProps={makeAnchorProps(HREF)}
161
+ menuGroups={openMenu(HREF, {
162
+ label: 'Open Ticket Details',
163
+ icon: <TagIcon size={20} />,
164
+ })}
165
+ menuAriaLabel="Ticket actions"
166
+ />
167
+ <MingoInfoCard
168
+ title="Ticket with no preview text and no status set at all"
169
+ icon={<TagIcon size={24} />}
170
+ anchorProps={makeAnchorProps(HREF)}
171
+ menuGroups={openMenu(HREF, {
172
+ label: 'Open Ticket Details',
173
+ icon: <TagIcon size={20} />,
174
+ })}
175
+ menuAriaLabel="Ticket actions"
176
+ />
177
+ </div>
178
+ )
179
+ },
180
+ }
181
+
182
+ // =============================================================================
183
+ // GitHub activity — icon per kind · status: review state or activity type ·
184
+ // description: "<id> · <date>"
185
+ // =============================================================================
186
+
187
+ export const GithubActivity: Story = {
188
+ parameters: {
189
+ docs: {
190
+ description: {
191
+ story:
192
+ 'Registry types `github_commit` / `github_pull_request` / `github_pr_review` (+ `_public`). Icon differs per kind (commit / pull-request / code); the pill shows the PR review state (Approved → green, Changes → red, Comment → grey) or, for commits/PRs, the neutral activity type.',
193
+ },
194
+ },
195
+ },
196
+ render: () => {
197
+ const HREF = 'https://github.com/flamingo/openframe/commit/a1b2c3d'
198
+ return (
199
+ <div className="flex flex-col gap-3">
200
+ <MingoInfoCard
201
+ title="fix(auth): guard SSO redirect against null session"
202
+ description="a1b2c3d · May 28, 2026"
203
+ icon={<CodingCommitIcon size={24} />}
204
+ status={{ label: 'Commit', variant: 'grey' }}
205
+ anchorProps={makeAnchorProps(HREF)}
206
+ menuGroups={openMenu(HREF)}
207
+ menuAriaLabel="Activity actions"
208
+ />
209
+ <MingoInfoCard
210
+ title="Add device bulk-actions to the fleet table"
211
+ description="#482 · May 27, 2026"
212
+ icon={<CodingPullRequestIcon size={24} />}
213
+ status={{ label: 'PR', variant: 'grey' }}
214
+ anchorProps={makeAnchorProps(HREF)}
215
+ menuGroups={openMenu(HREF)}
216
+ menuAriaLabel="Activity actions"
217
+ />
218
+ <MingoInfoCard
219
+ title="Pavlo Shylo"
220
+ description="#482 · May 27, 2026"
221
+ icon={<CodeIcon size={24} />}
222
+ status={{ label: 'Approved', variant: 'success' }}
223
+ anchorProps={makeAnchorProps(HREF)}
224
+ menuGroups={openMenu(HREF)}
225
+ menuAriaLabel="Activity actions"
226
+ />
227
+ <MingoInfoCard
228
+ title="Alex Rivera"
229
+ description="#479 · May 26, 2026"
230
+ icon={<CodeIcon size={24} />}
231
+ status={{ label: 'Changes', variant: 'error' }}
232
+ anchorProps={makeAnchorProps(HREF)}
233
+ menuGroups={openMenu(HREF)}
234
+ menuAriaLabel="Activity actions"
235
+ />
236
+ <MingoInfoCard
237
+ title="Sam Lee"
238
+ description="#477 · May 25, 2026"
239
+ icon={<CodeIcon size={24} />}
240
+ status={{ label: 'Comment', variant: 'grey' }}
241
+ anchorProps={makeAnchorProps(HREF)}
242
+ menuGroups={openMenu(HREF)}
243
+ menuAriaLabel="Activity actions"
244
+ />
245
+ </div>
246
+ )
247
+ },
248
+ }
249
+
250
+ // =============================================================================
251
+ // Slack message — icon: Slack grey logo · no pill · description: message text
252
+ // =============================================================================
253
+
254
+ export const SlackMessage: Story = {
255
+ parameters: {
256
+ docs: {
257
+ description: {
258
+ story:
259
+ 'Registry type `slack_message`. No status pill (Slack has no status); the channel is appended to the author title ("Author · #channel"), and the description is the message preview text.',
260
+ },
261
+ },
262
+ },
263
+ render: () => {
264
+ const HREF = 'https://flamingo.slack.com/archives/C12345/p1700000000'
265
+ return (
266
+ <div className="flex flex-col gap-3">
267
+ <MingoInfoCard
268
+ title="Pavlo Shylo · #deploys"
269
+ description="Heads up — the staging deploy is going out in 10 minutes, hold any merges to main."
270
+ icon={<SlackLogoGreyIcon size={24} />}
271
+ anchorProps={makeAnchorProps(HREF)}
272
+ menuGroups={openMenu(HREF)}
273
+ menuAriaLabel="Message actions"
274
+ />
275
+ <MingoInfoCard
276
+ title="Alex Rivera · #incidents"
277
+ description="Found the root cause of the sync failure — it's the token refresh race. PR incoming."
278
+ icon={<SlackLogoGreyIcon size={24} />}
279
+ anchorProps={makeAnchorProps(HREF)}
280
+ menuGroups={openMenu(HREF)}
281
+ menuAriaLabel="Message actions"
282
+ />
283
+ <MingoInfoCard
284
+ title="Sam Lee · #general"
285
+ icon={<SlackLogoGreyIcon size={24} />}
286
+ anchorProps={makeAnchorProps(HREF)}
287
+ menuGroups={openMenu(HREF)}
288
+ menuAriaLabel="Message actions"
289
+ />
290
+ </div>
291
+ )
292
+ },
293
+ }
294
+
295
+ // =============================================================================
296
+ // Data-room doc / markdown — icon: FileContent · status: source badge ·
297
+ // description: preview
298
+ // =============================================================================
299
+
300
+ export const DataRoomDoc: Story = {
301
+ parameters: {
302
+ docs: {
303
+ description: {
304
+ story:
305
+ 'Registry types `data_room_doc` / `markdown`. Status pill is the provenance label (the source-repo label, or a neutral "Document" when unknown); the description is the content preview.',
306
+ },
307
+ },
308
+ },
309
+ render: () => {
310
+ const HREF = 'https://hub.flamingo.cx/docs/openframe/getting-started'
311
+ return (
312
+ <div className="flex flex-col gap-3">
313
+ <MingoInfoCard
314
+ title="Getting started with OpenFrame"
315
+ description="Install the agent, connect your first device, and open the fleet view."
316
+ icon={<FileContentIcon size={24} />}
317
+ status={{ label: 'OpenFrame Docs', variant: 'grey' }}
318
+ anchorProps={makeAnchorProps(HREF)}
319
+ menuGroups={openMenu(HREF)}
320
+ menuAriaLabel="Document actions"
321
+ />
322
+ <MingoInfoCard
323
+ title="Series A — financial model (Q1 2026)"
324
+ description="Revenue, burn, and runway projections for the upcoming raise."
325
+ icon={<FileContentIcon size={24} />}
326
+ status={{ label: 'Data room', variant: 'grey' }}
327
+ anchorProps={makeAnchorProps(HREF)}
328
+ menuGroups={openMenu(HREF)}
329
+ menuAriaLabel="Document actions"
330
+ />
331
+ <MingoInfoCard
332
+ title="Unlabeled doc — source repo unknown, falls back to Document"
333
+ description="Neutral provenance so unknown content can't be mislabeled."
334
+ icon={<FileContentIcon size={24} />}
335
+ status={{ label: 'Document', variant: 'grey' }}
336
+ anchorProps={makeAnchorProps(HREF)}
337
+ menuGroups={openMenu(HREF)}
338
+ menuAriaLabel="Document actions"
339
+ />
340
+ </div>
341
+ )
342
+ },
343
+ }
344
+
345
+ // =============================================================================
346
+ // Financial — distinct icon per type · no pill · description: subtitle
347
+ // =============================================================================
348
+
349
+ export const Financial: Story = {
350
+ parameters: {
351
+ docs: {
352
+ description: {
353
+ story:
354
+ 'Registry types `financial_kpi` / `cap_table` / `profit_loss` / `balance_sheet` / `cash_flow`. No status pill — the per-type icon carries the type signal (chart / pie / money / bank / exchange); the description is the subtitle.',
355
+ },
356
+ },
357
+ },
358
+ render: () => {
359
+ const HREF = 'https://hub.flamingo.cx/data-room/financials'
360
+ return (
361
+ <div className="flex flex-col gap-3">
362
+ <MingoInfoCard
363
+ title="Net revenue retention"
364
+ description="TTM · 118%"
365
+ icon={<ChartBar01VerIcon size={24} />}
366
+ anchorProps={makeAnchorProps(HREF)}
367
+ menuGroups={openMenu(HREF)}
368
+ menuAriaLabel="Document actions"
369
+ />
370
+ <MingoInfoCard
371
+ title="Cap table — Series A"
372
+ description="Post-money · $42M"
373
+ icon={<ChartPieIcon size={24} />}
374
+ anchorProps={makeAnchorProps(HREF)}
375
+ menuGroups={openMenu(HREF)}
376
+ menuAriaLabel="Document actions"
377
+ />
378
+ <MingoInfoCard
379
+ title="Profit & loss"
380
+ description="Q1 2026"
381
+ icon={<MoneyBillDollarIcon size={24} />}
382
+ anchorProps={makeAnchorProps(HREF)}
383
+ menuGroups={openMenu(HREF)}
384
+ menuAriaLabel="Document actions"
385
+ />
386
+ <MingoInfoCard
387
+ title="Balance sheet"
388
+ description="As of Mar 31, 2026"
389
+ icon={<BankIcon size={24} />}
390
+ anchorProps={makeAnchorProps(HREF)}
391
+ menuGroups={openMenu(HREF)}
392
+ menuAriaLabel="Document actions"
393
+ />
394
+ <MingoInfoCard
395
+ title="Cash flow statement"
396
+ description="Q1 2026 · burn $1.1M/mo"
397
+ icon={<CoinsExchangeCurrencyIcon size={24} />}
398
+ anchorProps={makeAnchorProps(HREF)}
399
+ menuGroups={openMenu(HREF)}
400
+ menuAriaLabel="Document actions"
401
+ />
402
+ </div>
403
+ )
404
+ },
405
+ }
406
+
407
+ // =============================================================================
408
+ // Blog post — media: cover image (newspaper-icon fallback) · pill: category ·
409
+ // description: summary
410
+ // =============================================================================
411
+
412
+ export const BlogPost: Story = {
413
+ parameters: {
414
+ docs: {
415
+ description: {
416
+ story:
417
+ 'Registry type `blog_post` (fetch mode). Media is the cover `featured_image` (OG placeholder, then a newspaper glyph as fallbacks); the pill is the first category; the description is the post summary.',
418
+ },
419
+ },
420
+ },
421
+ render: () => {
422
+ const HREF = 'https://openmsp.com/blog/rmm-buyers-guide'
423
+ return (
424
+ <div className="flex flex-col gap-3">
425
+ <MingoInfoCard
426
+ title="The 2026 RMM buyer's guide"
427
+ description="What to look for when choosing a remote monitoring and management platform."
428
+ imageSrc="https://picsum.photos/seed/rmm/80"
429
+ imageAlt="The 2026 RMM buyer's guide"
430
+ icon={<NewspaperIcon size={24} />}
431
+ status={{ label: 'Guides', variant: 'grey' }}
432
+ anchorProps={makeAnchorProps(HREF)}
433
+ menuGroups={openMenu(HREF)}
434
+ menuAriaLabel="Article actions"
435
+ />
436
+ <MingoInfoCard
437
+ title="Post with no cover image — falls back to the newspaper icon"
438
+ description="When featured_image and the OG placeholder are both missing."
439
+ icon={<NewspaperIcon size={24} />}
440
+ status={{ label: 'News', variant: 'grey' }}
441
+ anchorProps={makeAnchorProps(HREF)}
442
+ menuGroups={openMenu(HREF)}
443
+ menuAriaLabel="Article actions"
444
+ />
445
+ <MingoInfoCard
446
+ title="How we built the Mingo chat: streaming, citations and inline cards"
447
+ description="A deep-dive into the unified chat runtime that powers Guide and Mingo modes…"
448
+ imageSrc="https://picsum.photos/seed/videopost/80"
449
+ imageAlt="How we built the Mingo chat"
450
+ icon={<NewspaperIcon size={24} />}
451
+ status={{ label: 'Video', variant: 'primary' }}
452
+ anchorProps={makeAnchorProps(HREF)}
453
+ menuGroups={openMenu(HREF)}
454
+ menuAriaLabel="Article actions"
455
+ />
456
+ </div>
457
+ )
458
+ },
459
+ }
460
+
461
+ // =============================================================================
462
+ // Case study — trophy fallback icon · "Case study" pill · cover image
463
+ // =============================================================================
464
+
465
+ export const CaseStudy: Story = {
466
+ render: () => {
467
+ const HREF = 'https://openmsp.com/case-studies/acme-it'
468
+ return (
469
+ <div className="flex flex-col gap-3">
470
+ <MingoInfoCard
471
+ title="How Acme IT cut ticket volume by 40%"
472
+ description="Acme IT · Jordan Blake"
473
+ imageSrc="https://picsum.photos/seed/acme/80"
474
+ imageAlt="How Acme IT cut ticket volume by 40%"
475
+ icon={<TrophyIcon size={24} />}
476
+ status={{ label: 'Case study', variant: 'grey' }}
477
+ anchorProps={makeAnchorProps(HREF)}
478
+ menuGroups={openMenu(HREF)}
479
+ menuAriaLabel="Case study actions"
480
+ />
481
+ <MingoInfoCard
482
+ title="Case study without a cover — trophy icon fallback"
483
+ description="NorthStar MSP"
484
+ icon={<TrophyIcon size={24} />}
485
+ status={{ label: 'Case study', variant: 'grey' }}
486
+ anchorProps={makeAnchorProps(HREF)}
487
+ menuGroups={openMenu(HREF)}
488
+ menuAriaLabel="Case study actions"
489
+ />
490
+ </div>
491
+ )
492
+ },
493
+ }
494
+
495
+ // =============================================================================
496
+ // Customer interview — microphone fallback · "Interview" pill
497
+ // =============================================================================
498
+
499
+ export const CustomerInterview: Story = {
500
+ render: () => {
501
+ const HREF = 'https://openmsp.com/interviews/jamie-fox'
502
+ return (
503
+ <div className="flex flex-col gap-3">
504
+ <MingoInfoCard
505
+ title="Scaling an MSP from 5 to 50 technicians"
506
+ description="Jamie Fox · BrightLayer"
507
+ imageSrc="https://picsum.photos/seed/interview/80"
508
+ imageAlt="Scaling an MSP from 5 to 50 technicians"
509
+ icon={<MicrophoneIcon size={24} />}
510
+ status={{ label: 'Interview', variant: 'grey' }}
511
+ anchorProps={makeAnchorProps(HREF)}
512
+ menuGroups={openMenu(HREF)}
513
+ menuAriaLabel="Interview actions"
514
+ />
515
+ </div>
516
+ )
517
+ },
518
+ }
519
+
520
+ // =============================================================================
521
+ // Product release — rocket fallback · version pill · description: summary/date
522
+ // =============================================================================
523
+
524
+ export const ProductRelease: Story = {
525
+ render: () => {
526
+ const HREF = 'https://openframe.org/releases/2-14-0'
527
+ return (
528
+ <div className="flex flex-col gap-3">
529
+ <MingoInfoCard
530
+ title="OpenFrame 2.14"
531
+ description="Bulk device actions, faster fleet table, SSO hardening."
532
+ imageSrc="https://picsum.photos/seed/release/80"
533
+ imageAlt="OpenFrame 2.14"
534
+ icon={<Rocket02Icon size={24} />}
535
+ status={{ label: 'v2.14', variant: 'grey' }}
536
+ anchorProps={makeAnchorProps(HREF)}
537
+ menuGroups={openMenu(HREF)}
538
+ menuAriaLabel="Release actions"
539
+ />
540
+ <MingoInfoCard
541
+ title="OpenFrame 2.13.2 — patch release"
542
+ description="May 12, 2026"
543
+ icon={<Rocket02Icon size={24} />}
544
+ status={{ label: 'v2.13.2', variant: 'grey' }}
545
+ anchorProps={makeAnchorProps(HREF)}
546
+ menuGroups={openMenu(HREF)}
547
+ menuAriaLabel="Release actions"
548
+ />
549
+ </div>
550
+ )
551
+ },
552
+ }
553
+
554
+ // =============================================================================
555
+ // Programs — podcast / webinar / event, distinct icon + type pill
556
+ // =============================================================================
557
+
558
+ export const Programs: Story = {
559
+ render: () => {
560
+ const HREF = 'https://openmsp.com/podcasts/ep-42'
561
+ return (
562
+ <div className="flex flex-col gap-3">
563
+ <MingoInfoCard
564
+ title="Ep. 42 — The economics of co-managed IT"
565
+ description="May 28, 2026 · 42 min"
566
+ imageSrc="https://picsum.photos/seed/podcast/80"
567
+ imageAlt="Ep. 42 — The economics of co-managed IT"
568
+ icon={<MicrophoneIcon size={24} />}
569
+ status={{ label: 'Podcast', variant: 'grey' }}
570
+ anchorProps={makeAnchorProps(HREF)}
571
+ menuGroups={openMenu(HREF)}
572
+ menuAriaLabel="Podcast actions"
573
+ />
574
+ <MingoInfoCard
575
+ title="Live: securing the MSP supply chain"
576
+ description="Jun 4, 2026 · 11:00 AM PT · 1h"
577
+ icon={<PresentationBarIcon size={24} />}
578
+ status={{ label: 'Webinar', variant: 'grey' }}
579
+ anchorProps={makeAnchorProps(HREF)}
580
+ menuGroups={openMenu(HREF)}
581
+ menuAriaLabel="Webinar actions"
582
+ />
583
+ <MingoInfoCard
584
+ title="OpenMSP meetup — Austin"
585
+ description="Jun 18, 2026 · Austin, TX"
586
+ icon={<CalendarIcon size={24} />}
587
+ status={{ label: 'Event', variant: 'grey' }}
588
+ anchorProps={makeAnchorProps(HREF)}
589
+ menuGroups={openMenu(HREF)}
590
+ menuAriaLabel="Event actions"
591
+ />
592
+ </div>
593
+ )
594
+ },
595
+ }
596
+
597
+ // =============================================================================
598
+ // Investor update — presentation fallback · "Investor update" pill
599
+ // =============================================================================
600
+
601
+ export const InvestorUpdate: Story = {
602
+ render: () => {
603
+ const HREF = 'https://hub.flamingo.cx/investor-updates/2026-q1'
604
+ return (
605
+ <div className="flex flex-col gap-3">
606
+ <MingoInfoCard
607
+ title="Q1 2026 investor update"
608
+ description="118% NRR, $42M post-money, 14 months runway."
609
+ imageSrc="https://picsum.photos/seed/investor/80"
610
+ imageAlt="Q1 2026 investor update"
611
+ icon={<PresentationLineIcon size={24} />}
612
+ status={{ label: 'Investor update', variant: 'grey' }}
613
+ anchorProps={makeAnchorProps(HREF)}
614
+ menuGroups={openMenu(HREF)}
615
+ menuAriaLabel="Update actions"
616
+ />
617
+ <MingoInfoCard
618
+ title="Update #7"
619
+ description="Title-less row falls back to the update number."
620
+ icon={<PresentationLineIcon size={24} />}
621
+ status={{ label: 'Investor update', variant: 'grey' }}
622
+ anchorProps={makeAnchorProps(HREF)}
623
+ menuGroups={openMenu(HREF)}
624
+ menuAriaLabel="Update actions"
625
+ />
626
+ </div>
627
+ )
628
+ },
629
+ }
630
+
631
+ // =============================================================================
632
+ // Onboarding guide — compass fallback · "Guide" pill
633
+ // =============================================================================
634
+
635
+ export const OnboardingGuide: Story = {
636
+ render: () => {
637
+ const HREF = 'https://hub.flamingo.cx/guides/first-device'
638
+ return (
639
+ <div className="flex flex-col gap-3">
640
+ <MingoInfoCard
641
+ title="Connect your first device"
642
+ description="A five-minute walkthrough from install to live telemetry."
643
+ imageSrc="https://picsum.photos/seed/guide/80"
644
+ imageAlt="Connect your first device"
645
+ icon={<CompassIcon size={24} />}
646
+ status={{ label: 'Guide', variant: 'grey' }}
647
+ anchorProps={makeAnchorProps(HREF)}
648
+ menuGroups={openMenu(HREF)}
649
+ menuAriaLabel="Guide actions"
650
+ />
651
+ </div>
652
+ )
653
+ },
654
+ }
655
+
656
+ // =============================================================================
657
+ // Roadmap / delivery / task — per-type icon · coloured status pill · no image
658
+ // =============================================================================
659
+
660
+ export const Roadmap: Story = {
661
+ parameters: {
662
+ docs: {
663
+ description: {
664
+ story:
665
+ 'Registry types `roadmap_item` / `delivery_item` / `internal_task`. Icon priority mirrors RoadmapCard: server integration logo (`item.icon`, shown contained) → task-type glyph → per-type default (map / truck / check-square). The status pill is coloured via the shared `getStatusColorScheme` mapping (done → green, in-progress → amber, blocked → red, other → grey).',
666
+ },
667
+ },
668
+ },
669
+ render: () => {
670
+ const HREF = 'https://hub.flamingo.cx/roadmap/RM-128'
671
+ return (
672
+ <div className="flex flex-col gap-3">
673
+ <MingoInfoCard
674
+ title="Per-tenant audit log export"
675
+ description="Server integration logo (e.g. ClickUp) shown contained in the box."
676
+ icon={
677
+ <img
678
+ src="https://picsum.photos/seed/clickuplogo/48"
679
+ alt=""
680
+ className="size-6 object-contain"
681
+ />
682
+ }
683
+ status={{ label: 'In Progress', variant: 'warning' }}
684
+ anchorProps={makeAnchorProps(HREF)}
685
+ menuGroups={openMenu(HREF)}
686
+ menuAriaLabel="Roadmap actions"
687
+ />
688
+ <MingoInfoCard
689
+ title="Roadmap item with no logo — per-type default glyph"
690
+ description="Falls back to the map glyph when there's no server icon."
691
+ icon={<MapIcon size={24} />}
692
+ status={{ label: 'Planned', variant: 'grey' }}
693
+ anchorProps={makeAnchorProps(HREF)}
694
+ menuGroups={openMenu(HREF)}
695
+ menuAriaLabel="Roadmap actions"
696
+ />
697
+ <MingoInfoCard
698
+ title="Ship bulk device tagging"
699
+ description="Tag and filter devices in bulk from the fleet table."
700
+ icon={<TruckFastIcon size={24} />}
701
+ status={{ label: 'Done', variant: 'success' }}
702
+ anchorProps={makeAnchorProps(HREF)}
703
+ menuGroups={openMenu(HREF)}
704
+ menuAriaLabel="Roadmap actions"
705
+ />
706
+ <MingoInfoCard
707
+ title="Investigate flaky NATS reconnect"
708
+ description="Reconnect storm under network partition — needs a repro."
709
+ icon={<CheckSquareIcon size={24} />}
710
+ status={{ label: 'Blocked', variant: 'error' }}
711
+ anchorProps={makeAnchorProps(HREF)}
712
+ menuGroups={openMenu(HREF)}
713
+ menuAriaLabel="Roadmap actions"
714
+ />
715
+ </div>
716
+ )
717
+ },
718
+ }
719
+
720
+ // =============================================================================
721
+ // Marketing campaign — megaphone icon · coloured status pill
722
+ // =============================================================================
723
+
724
+ export const MarketingCampaign: Story = {
725
+ render: () => {
726
+ const HREF = 'https://hub.flamingo.cx/admin/campaigns/c-91'
727
+ return (
728
+ <div className="flex flex-col gap-3">
729
+ <MingoInfoCard
730
+ title="Spring RMM migration push"
731
+ description="Apr 1, 2026 · 3 goals · Marketing campaign"
732
+ icon={<Megaphone01Icon size={24} />}
733
+ anchorProps={makeAnchorProps(HREF)}
734
+ menuGroups={openMenu(HREF)}
735
+ menuAriaLabel="Campaign actions"
736
+ />
737
+ <MingoInfoCard
738
+ title="Webinar promo — supply chain security"
739
+ description="May 20, 2026 · 1 goal · Marketing campaign"
740
+ icon={<Megaphone01Icon size={24} />}
741
+ anchorProps={makeAnchorProps(HREF)}
742
+ menuGroups={openMenu(HREF)}
743
+ menuAriaLabel="Campaign actions"
744
+ />
745
+ </div>
746
+ )
747
+ },
748
+ }