@flamingo-stack/openframe-frontend-core 0.0.267 → 0.0.268-snapshot.20260615081103

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 (63) hide show
  1. package/dist/{chunk-YV55JZAD.cjs → chunk-5P22US65.cjs} +25 -25
  2. package/dist/{chunk-YV55JZAD.cjs.map → chunk-5P22US65.cjs.map} +1 -1
  3. package/dist/{chunk-O6UA475M.cjs → chunk-6HOVFLRN.cjs} +845 -700
  4. package/dist/chunk-6HOVFLRN.cjs.map +1 -0
  5. package/dist/{chunk-TPZI7NBN.cjs → chunk-O3QFZPGQ.cjs} +11 -11
  6. package/dist/{chunk-TPZI7NBN.cjs.map → chunk-O3QFZPGQ.cjs.map} +1 -1
  7. package/dist/{chunk-XSK72QRR.js → chunk-O3WINEZN.js} +2 -2
  8. package/dist/{chunk-CI5XE4LB.cjs → chunk-PKUIGYQF.cjs} +30 -30
  9. package/dist/{chunk-CI5XE4LB.cjs.map → chunk-PKUIGYQF.cjs.map} +1 -1
  10. package/dist/{chunk-GJVSLS2R.js → chunk-QVQ4YA46.js} +2 -2
  11. package/dist/{chunk-J6O57C7S.js → chunk-Z4475TMT.js} +3140 -2995
  12. package/dist/chunk-Z4475TMT.js.map +1 -0
  13. package/dist/{chunk-Z6MKG53Z.js → chunk-ZXNJLY4E.js} +2 -2
  14. package/dist/components/chat/index.cjs +2 -2
  15. package/dist/components/chat/index.js +1 -1
  16. package/dist/components/contact/index.cjs +3 -3
  17. package/dist/components/contact/index.js +2 -2
  18. package/dist/components/features/index.cjs +2 -2
  19. package/dist/components/features/index.js +1 -1
  20. package/dist/components/index.cjs +61 -47
  21. package/dist/components/index.cjs.map +1 -1
  22. package/dist/components/index.js +17 -3
  23. package/dist/components/index.js.map +1 -1
  24. package/dist/components/navigation/index.cjs +2 -2
  25. package/dist/components/navigation/index.js +1 -1
  26. package/dist/components/related-content/index.cjs +3 -3
  27. package/dist/components/related-content/index.js +2 -2
  28. package/dist/components/tickets/index.cjs +53 -53
  29. package/dist/components/tickets/index.js +3 -3
  30. package/dist/components/ui/index.cjs +16 -2
  31. package/dist/components/ui/index.cjs.map +1 -1
  32. package/dist/components/ui/index.d.ts +1 -0
  33. package/dist/components/ui/index.d.ts.map +1 -1
  34. package/dist/components/ui/index.js +15 -1
  35. package/dist/components/ui/no-data/index.d.ts +5 -0
  36. package/dist/components/ui/no-data/index.d.ts.map +1 -0
  37. package/dist/components/ui/no-data/no-data-actions.d.ts +34 -0
  38. package/dist/components/ui/no-data/no-data-actions.d.ts.map +1 -0
  39. package/dist/components/ui/no-data/no-data-message.d.ts +17 -0
  40. package/dist/components/ui/no-data/no-data-message.d.ts.map +1 -0
  41. package/dist/components/ui/no-data/no-data-styles.d.ts +8 -0
  42. package/dist/components/ui/no-data/no-data-styles.d.ts.map +1 -0
  43. package/dist/components/ui/no-data/no-data.d.ts +33 -0
  44. package/dist/components/ui/no-data/no-data.d.ts.map +1 -0
  45. package/dist/index.cjs +16 -2
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.js +15 -1
  48. package/dist/types/platform.d.ts +2 -0
  49. package/dist/types/platform.d.ts.map +1 -1
  50. package/package.json +1 -1
  51. package/src/components/ui/index.ts +1 -0
  52. package/src/components/ui/no-data/index.ts +4 -0
  53. package/src/components/ui/no-data/no-data-actions.tsx +102 -0
  54. package/src/components/ui/no-data/no-data-message.tsx +43 -0
  55. package/src/components/ui/no-data/no-data-styles.ts +36 -0
  56. package/src/components/ui/no-data/no-data.tsx +84 -0
  57. package/src/stories/EmptyState.stories.tsx +207 -0
  58. package/src/types/platform.ts +6 -0
  59. package/dist/chunk-J6O57C7S.js.map +0 -1
  60. package/dist/chunk-O6UA475M.cjs.map +0 -1
  61. /package/dist/{chunk-XSK72QRR.js.map → chunk-O3WINEZN.js.map} +0 -0
  62. /package/dist/{chunk-GJVSLS2R.js.map → chunk-QVQ4YA46.js.map} +0 -0
  63. /package/dist/{chunk-Z6MKG53Z.js.map → chunk-ZXNJLY4E.js.map} +0 -0
@@ -0,0 +1,43 @@
1
+ import React from "react"
2
+
3
+ import { cn } from "../../../utils/cn"
4
+ import { noDataIconClasses } from "./no-data-styles"
5
+
6
+ interface NoDataMessageProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
7
+ /** Leading glyph, sized to 16px (mobile) / 24px (md+). Optional. */
8
+ icon?: React.ReactNode
9
+ /** Primary line (body size). */
10
+ title?: React.ReactNode
11
+ /** Secondary line (caption size). */
12
+ description?: React.ReactNode
13
+ }
14
+
15
+ /**
16
+ * A transparent, centered stack of an icon, a title and a description, in muted
17
+ * gray. Any piece is optional, so it also covers "icon + title", "title only",
18
+ * and similar reduced forms.
19
+ */
20
+ const NoDataMessage = React.forwardRef<HTMLDivElement, NoDataMessageProps>(
21
+ function NoDataMessage({ icon, title, description, className, ...props }, ref) {
22
+ return (
23
+ <div
24
+ ref={ref}
25
+ className={cn(
26
+ "flex flex-col items-center gap-[var(--spacing-system-l)] text-center text-ods-text-secondary",
27
+ className,
28
+ )}
29
+ {...props}
30
+ >
31
+ {icon && <span className={noDataIconClasses}>{icon}</span>}
32
+ {(title || description) && (
33
+ <div className="flex flex-col">
34
+ {title && <p className="text-h4 break-words">{title}</p>}
35
+ {description && <p className="text-h6 break-words">{description}</p>}
36
+ </div>
37
+ )}
38
+ </div>
39
+ )
40
+ },
41
+ )
42
+
43
+ export { NoDataMessage, type NoDataMessageProps }
@@ -0,0 +1,36 @@
1
+ // Shared style atoms for the NoData (empty-state) family. Mirrors the approach
2
+ // used by `button-styles.ts`: a single source of truth for the icon scale, the
3
+ // block-group surface and the interactive/disabled treatment, expressed as
4
+ // reusable class atoms so new looks can be added without touching the markup.
5
+
6
+ import { cva, type VariantProps } from "class-variance-authority"
7
+
8
+ // Leading-icon glyph scale: 16px on mobile, 24px on md+. Color is intentionally
9
+ // omitted so the glyph inherits the current text color (and dims with it when
10
+ // the block is disabled).
11
+ export const noDataIconClasses =
12
+ "inline-flex shrink-0 items-center justify-center [&_svg]:h-4 [&_svg]:w-4 md:[&_svg]:h-6 md:[&_svg]:w-6"
13
+
14
+ // Surface for the action-block group container: a card-colored panel with a
15
+ // border and rounded corners. `overflow-hidden` keeps only the outer blocks
16
+ // round — inner blocks stay square.
17
+ export const noDataActionsVariants = cva("overflow-hidden rounded-md", {
18
+ variants: {
19
+ variant: {
20
+ outline: "bg-ods-card border border-ods-border",
21
+ },
22
+ },
23
+ defaultVariants: { variant: "outline" },
24
+ })
25
+
26
+ export type NoDataActionsVariant = NonNullable<
27
+ VariantProps<typeof noDataActionsVariants>["variant"]
28
+ >
29
+
30
+ // Interactive treatment for a clickable block: hover/active surface tints, a
31
+ // keyboard focus ring, and a disabled state that grays the text and stops
32
+ // pointer interaction — matching the disabled outline button.
33
+ export const noDataActionInteractiveClasses =
34
+ "cursor-pointer transition-colors hover:bg-ods-bg-hover active:bg-ods-bg-active " +
35
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ods-focus focus-visible:ring-inset " +
36
+ "disabled:cursor-default disabled:pointer-events-none disabled:text-ods-text-disabled"
@@ -0,0 +1,84 @@
1
+ import React from "react"
2
+
3
+ import { cn } from "../../../utils/cn"
4
+ import { Button, type ButtonProps } from "../button"
5
+ import { NoDataMessage } from "./no-data-message"
6
+ import { NoDataActions, type NoDataActionProps } from "./no-data-actions"
7
+
8
+ interface NoDataProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
9
+ // --- Message ---
10
+ /** Leading glyph, sized to 16px (mobile) / 24px (md+). */
11
+ icon?: React.ReactNode
12
+ /** Primary line. */
13
+ title?: React.ReactNode
14
+ /** Secondary line. */
15
+ description?: React.ReactNode
16
+
17
+ // --- Clickable blocks ---
18
+ /** Clickable blocks. Dynamic count. Hidden when empty/omitted. */
19
+ actions?: NoDataActionProps[]
20
+
21
+ // --- Footer button ---
22
+ /** Footer button label. When set (and `button` is not), renders the button. */
23
+ buttonLabel?: React.ReactNode
24
+ /** Leading icon for the footer button. */
25
+ buttonIcon?: React.ReactNode
26
+ /** Click handler for the footer button. */
27
+ onButtonClick?: ButtonProps["onClick"]
28
+ /** Extra props forwarded to the footer button (variant, href, loading, …). */
29
+ buttonProps?: Partial<ButtonProps>
30
+ /** Fully custom footer node; overrides the `buttonLabel`/`buttonIcon` path. */
31
+ button?: React.ReactNode
32
+ }
33
+
34
+ /**
35
+ * A centered empty-state panel: a muted icon/title/description message, an
36
+ * optional group of clickable blocks, and an optional footer button, stacked
37
+ * vertically with breakpoint-aware spacing. Each region renders only when its
38
+ * inputs are present, so the same component covers a bare message, a message
39
+ * with a button, the full layout, and everything in between.
40
+ */
41
+ const NoData = React.forwardRef<HTMLDivElement, NoDataProps>(function NoData(
42
+ {
43
+ icon,
44
+ title,
45
+ description,
46
+ actions,
47
+ buttonLabel,
48
+ buttonIcon,
49
+ onButtonClick,
50
+ buttonProps,
51
+ button,
52
+ className,
53
+ ...props
54
+ },
55
+ ref,
56
+ ) {
57
+ const hasMessage = !!(icon || title || description)
58
+ const hasActions = !!actions?.length
59
+
60
+ const footerButton =
61
+ button ??
62
+ (buttonLabel != null ? (
63
+ <Button variant="outline" leftIcon={buttonIcon} onClick={onButtonClick} {...buttonProps}>
64
+ {buttonLabel}
65
+ </Button>
66
+ ) : null)
67
+
68
+ return (
69
+ <div
70
+ ref={ref}
71
+ className={cn(
72
+ "flex w-full flex-col items-center justify-center gap-[var(--spacing-system-l)] p-[var(--spacing-system-l)]",
73
+ className,
74
+ )}
75
+ {...props}
76
+ >
77
+ {hasMessage && <NoDataMessage icon={icon} title={title} description={description} />}
78
+ {hasActions && <NoDataActions actions={actions} />}
79
+ {footerButton}
80
+ </div>
81
+ )
82
+ })
83
+
84
+ export { NoData, type NoDataProps }
@@ -0,0 +1,207 @@
1
+ import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2
+ import { Database, FileText, Inbox, Plus, Search, Settings, Sparkles, Upload, Zap } from 'lucide-react';
3
+ import React from 'react';
4
+ import { Button } from '../components/ui/button';
5
+ import { NoData, NoDataAction, NoDataActions, NoDataMessage } from '../components/ui/no-data';
6
+
7
+ const meta = {
8
+ title: 'UI/EmptyState',
9
+ component: NoData,
10
+ argTypes: {
11
+ icon: { control: false },
12
+ actions: { control: false },
13
+ button: { control: false },
14
+ buttonIcon: { control: false },
15
+ onButtonClick: { control: false },
16
+ buttonProps: { control: false },
17
+ title: { control: 'text' },
18
+ description: { control: 'text' },
19
+ buttonLabel: { control: 'text' },
20
+ },
21
+ } satisfies Meta<typeof NoData>;
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof meta>;
25
+
26
+ const noop = () => {};
27
+
28
+ const defaultActions = [
29
+ { icon: <Zap />, label: 'Feature Description', onClick: noop },
30
+ { icon: <Sparkles />, label: 'Feature Description', onClick: noop },
31
+ { icon: <Database />, label: 'Feature Description', onClick: noop },
32
+ ];
33
+
34
+ // === Full composition ===
35
+
36
+ export const Default: Story = {
37
+ args: {
38
+ icon: <Inbox />,
39
+ title: 'No data available',
40
+ description: 'Start by adding an item',
41
+ actions: defaultActions,
42
+ buttonLabel: 'Ask Mingo about Item',
43
+ buttonIcon: <Sparkles />,
44
+ onButtonClick: noop,
45
+ },
46
+ };
47
+
48
+ // === Reduced message ===
49
+
50
+ export const MessageTitleOnly: Story = {
51
+ args: {
52
+ icon: <Search />,
53
+ title: 'No results found',
54
+ },
55
+ };
56
+
57
+ // === Without one region ===
58
+
59
+ export const WithoutActions: Story = {
60
+ args: {
61
+ icon: <Inbox />,
62
+ title: 'No data available',
63
+ description: 'Start by adding an item',
64
+ buttonLabel: 'Add item',
65
+ buttonIcon: <Plus />,
66
+ onButtonClick: noop,
67
+ },
68
+ };
69
+
70
+ export const WithoutButton: Story = {
71
+ args: {
72
+ icon: <Inbox />,
73
+ title: 'No data available',
74
+ description: 'Start by adding an item',
75
+ actions: defaultActions,
76
+ },
77
+ };
78
+
79
+ // === Dynamic block count ===
80
+
81
+ export const TwoActions: Story = {
82
+ args: {
83
+ icon: <Database />,
84
+ title: 'No data available',
85
+ description: 'Start by adding an item',
86
+ actions: [
87
+ { icon: <Zap />, label: 'Feature Description', onClick: noop },
88
+ { icon: <Sparkles />, label: 'Feature Description', onClick: noop },
89
+ ],
90
+ buttonLabel: 'Ask Mingo about Item',
91
+ buttonIcon: <Sparkles />,
92
+ onButtonClick: noop,
93
+ },
94
+ };
95
+
96
+ export const FourActions: Story = {
97
+ args: {
98
+ icon: <Database />,
99
+ title: 'No data available',
100
+ description: 'Start by adding an item',
101
+ actions: [
102
+ { icon: <Zap />, label: 'Real-time sync', onClick: noop },
103
+ { icon: <Sparkles />, label: 'Smart suggestions', onClick: noop },
104
+ { icon: <Database />, label: 'Unlimited storage', onClick: noop },
105
+ { icon: <FileText />, label: 'Export anywhere', onClick: noop },
106
+ ],
107
+ buttonLabel: 'Ask Mingo about Item',
108
+ buttonIcon: <Sparkles />,
109
+ onButtonClick: noop,
110
+ },
111
+ };
112
+
113
+ // === Disabled blocks ===
114
+
115
+ export const DisabledActions: Story = {
116
+ args: {
117
+ icon: <Inbox />,
118
+ title: 'No data available',
119
+ description: 'Some actions are unavailable',
120
+ actions: [
121
+ { icon: <Zap />, label: 'Available', onClick: noop },
122
+ { icon: <Sparkles />, label: 'Disabled', onClick: noop, disabled: true },
123
+ { icon: <Database />, label: 'Disabled', onClick: noop, disabled: true },
124
+ ],
125
+ buttonLabel: 'Ask Mingo about Item',
126
+ buttonIcon: <Sparkles />,
127
+ onButtonClick: noop,
128
+ },
129
+ };
130
+
131
+ // === Footer button variations ===
132
+
133
+ export const ButtonAsLink: Story = {
134
+ args: {
135
+ icon: <Upload />,
136
+ title: 'No data available',
137
+ description: 'Import your first dataset',
138
+ buttonLabel: 'View docs',
139
+ buttonIcon: <FileText />,
140
+ buttonProps: { href: '/docs' },
141
+ },
142
+ };
143
+
144
+ export const CustomButton: Story = {
145
+ args: {
146
+ icon: <Settings />,
147
+ title: 'No data available',
148
+ description: 'Configure a source to get started',
149
+ // `button` is the escape hatch — pass any node.
150
+ button: (
151
+ <div className="flex gap-2">
152
+ <Button variant="outline" leftIcon={<Plus />}>Connect source</Button>
153
+ <Button variant="transparent" leftIcon={<FileText />}>View docs</Button>
154
+ </div>
155
+ ),
156
+ },
157
+ };
158
+
159
+ // === Standalone parts ===
160
+
161
+ export const StandaloneActions: Story = {
162
+ args: { title: '' },
163
+ render: () => (
164
+ <NoDataActions>
165
+ <NoDataAction icon={<Zap />} label="Clickable block" onClick={noop} />
166
+ <NoDataAction icon={<Sparkles />} label="Clickable block" onClick={noop} />
167
+ <NoDataAction icon={<Database />} label="Disabled block" onClick={noop} disabled />
168
+ </NoDataActions>
169
+ ),
170
+ };
171
+
172
+ export const StandaloneMessage: Story = {
173
+ args: { title: '' },
174
+ render: () => (
175
+ <NoDataMessage
176
+ icon={<Search />}
177
+ title="No results found"
178
+ description="Try adjusting your filters"
179
+ />
180
+ ),
181
+ };
182
+
183
+ // === Showcase ===
184
+
185
+ export const Showcase: Story = {
186
+ args: { title: '' },
187
+ render: () => (
188
+ <div className="flex flex-col items-stretch gap-12">
189
+ <NoData
190
+ icon={<Inbox />}
191
+ title="No data available"
192
+ description="Start by adding an item"
193
+ actions={defaultActions}
194
+ buttonLabel="Ask Mingo about Item"
195
+ buttonIcon={<Sparkles />}
196
+ onButtonClick={noop}
197
+ />
198
+ <NoData icon={<Search />} title="No results found" description="Try a different search" />
199
+ <NoData
200
+ icon={<Database />}
201
+ title="No data available"
202
+ description="Start by adding an item"
203
+ actions={defaultActions}
204
+ />
205
+ </div>
206
+ ),
207
+ };
@@ -11,6 +11,12 @@ export interface PlatformRecord {
11
11
  description?: string;
12
12
  is_active: boolean;
13
13
  is_internal: boolean; // Whether this is an internal admin platform vs public-facing
14
+ // Universal-viewer: when true, content DALs return ALL platforms' rows (applyFilter=false),
15
+ // decoupled from is_internal. Read by getPlatformContentScopeMode (hub lib/platform-utils.ts).
16
+ serves_all_content: boolean;
17
+ // When false, skip activity-tracking + HubSpot sync for this platform's principals
18
+ // (formerly keyed on is_internal). Read by platformTracksActivity (hub lib/platform-utils.ts).
19
+ tracks_activity: boolean;
14
20
  // Chat (Ask AI) wiring — populated only for platforms that host a chat surface.
15
21
  // `chat_source_id` is the doc-source binding (`chat_admin_personas.chat_source_id`).
16
22
  // `chat_source_rag_tables_version` is the per-platform RAG-table override version