@xenide-io/the-old-ui-theme 0.2.5 → 0.2.9

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 (112) hide show
  1. package/dist/chunk-FWCSY2DS.mjs +37 -0
  2. package/dist/chunk-SHF57J7U.mjs +2910 -0
  3. package/dist/index-CmS6hcUk.d.mts +753 -0
  4. package/dist/index-CmS6hcUk.d.ts +753 -0
  5. package/dist/index.d.mts +5 -755
  6. package/dist/index.d.ts +5 -755
  7. package/dist/index.js +655 -378
  8. package/dist/index.mjs +348 -2695
  9. package/dist/tailwind-preset.mjs +2 -0
  10. package/dist/ui.d.mts +3 -0
  11. package/dist/ui.d.ts +3 -0
  12. package/dist/ui.js +2946 -0
  13. package/dist/ui.mjs +139 -0
  14. package/package.json +13 -5
  15. package/src/components/charts/index.ts +8 -0
  16. package/src/components/charts/ph-insight-charts.tsx +162 -0
  17. package/src/components/dashboard/DashboardFiltersBar.tsx +19 -0
  18. package/src/components/dashboard/DashboardGrid.tsx +23 -0
  19. package/src/components/dashboard/DashboardInsightPlaceholder.tsx +37 -0
  20. package/src/components/dashboard/DashboardKpiCard.tsx +25 -0
  21. package/src/components/dashboard/DashboardToolbar.tsx +23 -0
  22. package/src/components/dashboard/DashboardWell.tsx +10 -0
  23. package/src/components/dashboard/InsightMiniCard.tsx +26 -0
  24. package/src/components/dashboard/InsightShell.tsx +37 -0
  25. package/src/components/dashboard/InsightShellHeader.tsx +22 -0
  26. package/src/components/dashboard/MiniTrendBars.tsx +51 -0
  27. package/src/components/dashboard/index.ts +31 -0
  28. package/src/components/dashboard/types.ts +9 -0
  29. package/src/components/icons/IconBase.tsx +39 -0
  30. package/src/components/icons/createIconBase.tsx +27 -0
  31. package/src/components/icons/icons.tsx +367 -0
  32. package/src/components/icons/index.ts +3 -0
  33. package/src/components/sections/AccordionShowcase.tsx +45 -0
  34. package/src/components/sections/AlertShowcase.tsx +39 -0
  35. package/src/components/sections/AvatarShowcase.tsx +80 -0
  36. package/src/components/sections/BadgeShowcase.tsx +65 -0
  37. package/src/components/sections/ButtonShowcase.tsx +312 -0
  38. package/src/components/sections/CalendarShowcase.tsx +35 -0
  39. package/src/components/sections/CardShowcase.tsx +143 -0
  40. package/src/components/sections/ChartShowcase.tsx +190 -0
  41. package/src/components/sections/CodeMockupShowcase.tsx +56 -0
  42. package/src/components/sections/ColorPalette.tsx +117 -0
  43. package/src/components/sections/CommandPaletteShowcase.tsx +48 -0
  44. package/src/components/sections/CountdownShowcase.tsx +43 -0
  45. package/src/components/sections/DashboardShowcase.tsx +191 -0
  46. package/src/components/sections/DiffShowcase.tsx +70 -0
  47. package/src/components/sections/DrawerShowcase.tsx +97 -0
  48. package/src/components/sections/DropdownShowcase.tsx +100 -0
  49. package/src/components/sections/EmptyStateShowcase.tsx +50 -0
  50. package/src/components/sections/FilterChipsShowcase.tsx +50 -0
  51. package/src/components/sections/FormShowcase.tsx +126 -0
  52. package/src/components/sections/HoverCardShowcase.tsx +50 -0
  53. package/src/components/sections/IconShowcase.tsx +247 -0
  54. package/src/components/sections/IndicatorShowcase.tsx +52 -0
  55. package/src/components/sections/KbdShowcase.tsx +31 -0
  56. package/src/components/sections/ModalShowcase.tsx +210 -0
  57. package/src/components/sections/NavigationShowcase.tsx +199 -0
  58. package/src/components/sections/ProgressShowcase.tsx +85 -0
  59. package/src/components/sections/SegmentedControlShowcase.tsx +49 -0
  60. package/src/components/sections/SetupThemeShowcase.tsx +262 -0
  61. package/src/components/sections/StackShowcase.tsx +33 -0
  62. package/src/components/sections/StatShowcase.tsx +129 -0
  63. package/src/components/sections/StepperShowcase.tsx +37 -0
  64. package/src/components/sections/SwapShowcase.tsx +91 -0
  65. package/src/components/sections/TabShowcase.tsx +84 -0
  66. package/src/components/sections/TableShowcase.tsx +140 -0
  67. package/src/components/sections/TimelineShowcase.tsx +83 -0
  68. package/src/components/sections/ToastShowcase.tsx +108 -0
  69. package/src/components/sections/TooltipShowcase.tsx +44 -0
  70. package/src/components/sections/UtilityShowcase.tsx +81 -0
  71. package/src/components/ui/Accordion.tsx +77 -0
  72. package/src/components/ui/Alert.tsx +68 -0
  73. package/src/components/ui/Avatar.tsx +97 -0
  74. package/src/components/ui/Badge.tsx +55 -0
  75. package/src/components/ui/Button.tsx +110 -0
  76. package/src/components/ui/ButtonChrome.tsx +20 -0
  77. package/src/components/ui/Calendar.tsx +116 -0
  78. package/src/components/ui/Card.tsx +60 -0
  79. package/src/components/ui/ChatBubble.tsx +71 -0
  80. package/src/components/ui/CodeBlock.tsx +48 -0
  81. package/src/components/ui/CollapsibleSection.tsx +49 -0
  82. package/src/components/ui/CommandPalette.tsx +137 -0
  83. package/src/components/ui/ComponentDocs.tsx +52 -0
  84. package/src/components/ui/Drawer.tsx +71 -0
  85. package/src/components/ui/DropdownMenu.tsx +138 -0
  86. package/src/components/ui/EmptyState.tsx +33 -0
  87. package/src/components/ui/FilterChips.tsx +50 -0
  88. package/src/components/ui/HoverCard.tsx +36 -0
  89. package/src/components/ui/Indicator.tsx +61 -0
  90. package/src/components/ui/Input.tsx +359 -0
  91. package/src/components/ui/Kbd.tsx +38 -0
  92. package/src/components/ui/Modal.tsx +75 -0
  93. package/src/components/ui/Navigation.tsx +94 -0
  94. package/src/components/ui/Panel.tsx +18 -0
  95. package/src/components/ui/Progress.tsx +59 -0
  96. package/src/components/ui/Rating.tsx +65 -0
  97. package/src/components/ui/SearchInput.tsx +106 -0
  98. package/src/components/ui/SegmentedControl.tsx +44 -0
  99. package/src/components/ui/ShowcaseWrapper.tsx +136 -0
  100. package/src/components/ui/Stat.tsx +39 -0
  101. package/src/components/ui/Stepper.tsx +75 -0
  102. package/src/components/ui/Table.tsx +55 -0
  103. package/src/components/ui/Tabs.tsx +53 -0
  104. package/src/components/ui/Terminal.tsx +54 -0
  105. package/src/components/ui/ThemeDomSync.tsx +17 -0
  106. package/src/components/ui/ThemeManager.tsx +18 -0
  107. package/src/components/ui/ThemeSwitcher.tsx +46 -0
  108. package/src/components/ui/Timeline.tsx +60 -0
  109. package/src/components/ui/Toast.tsx +70 -0
  110. package/src/components/ui/Typography.tsx +129 -0
  111. package/src/components/ui/index.ts +92 -0
  112. package/src/styles/themes.css +118 -0
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Bespoke Lemon glyphs from PostHog open source — filled Material / product paths,
3
+ * not Lucide stroke icons.
4
+ */
5
+ import {
6
+ IconActivity,
7
+ IconAreaChart,
8
+ IconArrowDown,
9
+ IconArrowUp,
10
+ IconBell,
11
+ IconBellOff,
12
+ IconBolt,
13
+ IconBox,
14
+ IconCancel,
15
+ IconCheck,
16
+ IconCheckCircle,
17
+ IconChevronDown,
18
+ IconChevronLeft,
19
+ IconChevronRight,
20
+ IconClipboardEdit,
21
+ IconClose,
22
+ IconCohort,
23
+ IconCopy,
24
+ IconCumulativeChart,
25
+ IconDatabase,
26
+ IconDownload,
27
+ IconEdit,
28
+ IconErrorOutline,
29
+ IconExclamation,
30
+ IconFlag,
31
+ IconFlare,
32
+ IconFlask,
33
+ IconGift,
34
+ IconGridView,
35
+ IconHandClick,
36
+ IconHome,
37
+ IconLayers,
38
+ IconListView,
39
+ IconLogout,
40
+ IconMail,
41
+ IconMoon,
42
+ IconPanelRight,
43
+ IconPerson,
44
+ IconPlayCircle,
45
+ IconPlus,
46
+ IconPremium,
47
+ IconQueryEditor,
48
+ IconRadar,
49
+ IconRecording,
50
+ IconRobot,
51
+ IconRocket,
52
+ IconSave,
53
+ IconSearch,
54
+ IconSelectEvents,
55
+ IconStar,
56
+ IconSubArrowRight,
57
+ IconSun,
58
+ IconSurveys,
59
+ IconSync,
60
+ IconTableChart,
61
+ IconTerminal,
62
+ IconToggle,
63
+ IconTrash,
64
+ IconTuning,
65
+ IconUpload,
66
+ IconVolume,
67
+ IconVolumeOff,
68
+ PH_ICONS,
69
+ type IconName,
70
+ } from "@/components/icons";
71
+ import { ShowcaseWrapper } from "@/components/ui";
72
+
73
+ const iconCells: { name: IconName; Icon: (typeof PH_ICONS)[IconName] }[] = [
74
+ { name: "activity", Icon: IconActivity },
75
+ { name: "areaChart", Icon: IconAreaChart },
76
+ { name: "arrowUp", Icon: IconArrowUp },
77
+ { name: "arrowDown", Icon: IconArrowDown },
78
+ { name: "bell", Icon: IconBell },
79
+ { name: "bellOff", Icon: IconBellOff },
80
+ { name: "bolt", Icon: IconBolt },
81
+ { name: "box", Icon: IconBox },
82
+ { name: "cancel", Icon: IconCancel },
83
+ { name: "check", Icon: IconCheck },
84
+ { name: "checkCircle", Icon: IconCheckCircle },
85
+ { name: "chevronDown", Icon: IconChevronDown },
86
+ { name: "chevronLeft", Icon: IconChevronLeft },
87
+ { name: "chevronRight", Icon: IconChevronRight },
88
+ { name: "clipboard", Icon: IconClipboardEdit },
89
+ { name: "close", Icon: IconClose },
90
+ { name: "cohort", Icon: IconCohort },
91
+ { name: "copy", Icon: IconCopy },
92
+ { name: "cumulativeChart", Icon: IconCumulativeChart },
93
+ { name: "database", Icon: IconDatabase },
94
+ { name: "download", Icon: IconDownload },
95
+ { name: "edit", Icon: IconEdit },
96
+ { name: "errorOutline", Icon: IconErrorOutline },
97
+ { name: "exclamation", Icon: IconExclamation },
98
+ { name: "flag", Icon: IconFlag },
99
+ { name: "flare", Icon: IconFlare },
100
+ { name: "flask", Icon: IconFlask },
101
+ { name: "gift", Icon: IconGift },
102
+ { name: "grid", Icon: IconGridView },
103
+ { name: "handClick", Icon: IconHandClick },
104
+ { name: "home", Icon: IconHome },
105
+ { name: "layers", Icon: IconLayers },
106
+ { name: "list", Icon: IconListView },
107
+ { name: "logout", Icon: IconLogout },
108
+ { name: "mail", Icon: IconMail },
109
+ { name: "moon", Icon: IconMoon },
110
+ { name: "panelRight", Icon: IconPanelRight },
111
+ { name: "person", Icon: IconPerson },
112
+ { name: "play", Icon: IconPlayCircle },
113
+ { name: "plus", Icon: IconPlus },
114
+ { name: "premium", Icon: IconPremium },
115
+ { name: "queryEditor", Icon: IconQueryEditor },
116
+ { name: "radar", Icon: IconRadar },
117
+ { name: "recording", Icon: IconRecording },
118
+ { name: "robot", Icon: IconRobot },
119
+ { name: "rocket", Icon: IconRocket },
120
+ { name: "save", Icon: IconSave },
121
+ { name: "search", Icon: IconSearch },
122
+ { name: "selectEvents", Icon: IconSelectEvents },
123
+ { name: "settings", Icon: IconTuning },
124
+ { name: "star", Icon: IconStar },
125
+ { name: "subArrowRight", Icon: IconSubArrowRight },
126
+ { name: "sun", Icon: IconSun },
127
+ { name: "surveys", Icon: IconSurveys },
128
+ { name: "sync", Icon: IconSync },
129
+ { name: "tableChart", Icon: IconTableChart },
130
+ { name: "terminal", Icon: IconTerminal },
131
+ { name: "toggle", Icon: IconToggle },
132
+ { name: "trash", Icon: IconTrash },
133
+ { name: "upload", Icon: IconUpload },
134
+ { name: "volume", Icon: IconVolume },
135
+ { name: "volumeOff", Icon: IconVolumeOff },
136
+ ];
137
+
138
+ const colourTiles = [
139
+ { label: "Session replay", Icon: IconRecording, fg: "--ph-product-session-replay" as const },
140
+ { label: "Product analytics", Icon: IconAreaChart, fg: "--ph-product-product-analytics" as const },
141
+ { label: "Data pipeline", Icon: IconGridView, fg: "--ph-product-data-pipeline" as const },
142
+ { label: "Feature flags", Icon: IconFlag, fg: "--ph-product-feature-flags" as const },
143
+ { label: "Experiments", Icon: IconFlask, fg: "--ph-product-experiments" as const },
144
+ { label: "Data warehouse", Icon: IconDatabase, fg: "--ph-product-data-warehouse" as const },
145
+ { label: "Surveys", Icon: IconSurveys, fg: "--ph-product-surveys" as const },
146
+ ];
147
+
148
+ export default function IconShowcase() {
149
+ const code = `import { IconActivity, IconAreaChart, IconArrowDown, IconArrowUp, IconBell, IconBellOff, IconBolt, IconBox, IconCancel, IconCheck, IconCheckCircle, IconChevronDown, IconChevronLeft, IconChevronRight, IconClipboardEdit, IconClose, IconCohort, IconCopy, IconCumulativeChart, IconDatabase, IconDownload, IconEdit, IconErrorOutline, IconExclamation, IconFlag, IconFlare, IconFlask, IconGift, IconGridView, IconHandClick, IconHome, IconLayers, IconListView, IconLogout, IconMail, IconMoon, IconPanelRight, IconPerson, IconPlayCircle, IconPlus, IconPremium, IconQueryEditor, IconRadar, IconRecording, IconRobot, IconRocket, IconSave, IconSearch, IconSelectEvents, IconStar, IconSubArrowRight, IconSun, IconSurveys, IconSync, IconTableChart, IconTerminal, IconToggle, IconTrash, IconTuning, IconUpload, IconVolume, IconVolumeOff, PH_ICONS, type IconName } from "the-old-ui";
150
+
151
+ <div className="space-y-8">
152
+ <div className="ph-panel space-y-4">
153
+ <h3 className="text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Bespoke Lemon glyphs</h3>
154
+ <p className="text-sm leading-relaxed text-ph-subtle">
155
+ Paths mirror PostHog&apos;s Lemon UI — filled{" "}
156
+ <code className="ph-kbd">currentColor</code> SVGs at <code className="ph-kbd">1em</code>, vendored in{" "}
157
+ <code className="ph-kbd">the-old-ui</code> (no Lucide).
158
+ </p>
159
+
160
+ <div className="grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8">
161
+ {iconCells.map(({ name, Icon }) => (
162
+ <div
163
+ key={name}
164
+ className="flex flex-col items-center gap-2 rounded-[var(--ph-radius-app)] border border-ph-border bg-ph-surface p-4 text-center"
165
+ style={{ boxShadow: "var(--ph-shadow-elevation-3000)" }}
166
+ >
167
+ <Icon className="h-6 w-6 text-ph-ink" />
168
+ <span className="text-[10px] font-medium uppercase tracking-wide text-ph-mutedtext">{name}</span>
169
+ </div>
170
+ ))}
171
+ </div>
172
+ </div>
173
+
174
+ <div className="ph-panel space-y-4">
175
+ <h3 className="text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Product rail hues</h3>
176
+ <p className="text-sm leading-relaxed text-ph-subtle">
177
+ In-app nav tiles use saturated backgrounds with light glyphs — tokens map to{" "}
178
+ <code className="ph-kbd">--ph-product-*</code> in <code className="ph-kbd">globals.css</code>.
179
+ </p>
180
+ <div className="grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-7">
181
+ {colourTiles.map(({ label, Icon, fg }) => (
182
+ <div
183
+ key={label}
184
+ className="ph-icon-tile border-white/15 text-white"
185
+ style={{ backgroundColor: \`var(\${fg})\` }}
186
+ >
187
+ <Icon className="mb-1 h-7 w-7 drop-shadow-sm" />
188
+ <span className="max-w-full truncate px-1 text-center normal-case tracking-normal">{label}</span>
189
+ </div>
190
+ ))}
191
+ </div>
192
+ </div>
193
+ </div>`;
194
+
195
+ return (
196
+ <ShowcaseWrapper
197
+ title="Icons"
198
+ description="Bespoke Lemon glyphs from PostHog open source — filled Material / product paths, not Lucide stroke icons."
199
+ code={code}
200
+ filename="IconExample.tsx"
201
+ >
202
+ <div className="space-y-8">
203
+ <div className="ph-panel space-y-4">
204
+ <h3 className="text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Bespoke Lemon glyphs</h3>
205
+ <p className="text-sm leading-relaxed text-ph-subtle">
206
+ Paths mirror PostHog&apos;s Lemon UI — filled{" "}
207
+ <code className="ph-kbd">currentColor</code> SVGs at <code className="ph-kbd">1em</code>, vendored in{" "}
208
+ <code className="ph-kbd">the-old-ui</code> (no Lucide).
209
+ </p>
210
+
211
+ <div className="grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8">
212
+ {iconCells.map(({ name, Icon }) => (
213
+ <div
214
+ key={name}
215
+ className="flex flex-col items-center gap-2 rounded-[var(--ph-radius-app)] border border-ph-border bg-ph-surface p-4 text-center"
216
+ style={{ boxShadow: "var(--ph-shadow-elevation-3000)" }}
217
+ >
218
+ <Icon className="h-6 w-6 text-ph-ink" />
219
+ <span className="text-[10px] font-medium uppercase tracking-wide text-ph-mutedtext">{name}</span>
220
+ </div>
221
+ ))}
222
+ </div>
223
+ </div>
224
+
225
+ <div className="ph-panel space-y-4">
226
+ <h3 className="text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Product rail hues</h3>
227
+ <p className="text-sm leading-relaxed text-ph-subtle">
228
+ In-app nav tiles use saturated backgrounds with light glyphs — tokens map to{" "}
229
+ <code className="ph-kbd">--ph-product-*</code> in <code className="ph-kbd">globals.css</code>.
230
+ </p>
231
+ <div className="grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-7">
232
+ {colourTiles.map(({ label, Icon, fg }) => (
233
+ <div
234
+ key={label}
235
+ className="ph-icon-tile border-white/15 text-white"
236
+ style={{ backgroundColor: `var(${fg})` }}
237
+ >
238
+ <Icon className="mb-1 h-7 w-7 drop-shadow-sm" />
239
+ <span className="max-w-full truncate px-1 text-center normal-case tracking-normal">{label}</span>
240
+ </div>
241
+ ))}
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </ShowcaseWrapper>
246
+ );
247
+ }
@@ -0,0 +1,52 @@
1
+ import { IconBell, IconMail, IconShoppingCart, IconSurveys } from "@/components/icons";
2
+ import { ComponentDocs, Indicator, ShowcaseWrapper } from "@/components/ui";
3
+
4
+ const indicators = [
5
+ { icon: IconBell, label: "Notifications", count: "8", hue: "bg-ph-brand" },
6
+ { icon: IconMail, label: "Messages", count: "99+", hue: "bg-ph-blue" },
7
+ { icon: IconSurveys, label: "Comments", count: "3", hue: "bg-emerald-600" },
8
+ { icon: IconShoppingCart, label: "Cart", count: "!", hue: "bg-ph-danger" },
9
+ ] as const;
10
+
11
+ export default function IndicatorShowcase() {
12
+ const code = `import { Indicator } from "the-old-ui";
13
+
14
+ <Indicator badge="8" color="bg-ph-brand">
15
+ <Button variant="ghost" shape="circle">
16
+ <IconBell className="h-6 w-6" />
17
+ </Button>
18
+ </Indicator>
19
+
20
+ <Indicator dot color="bg-ph-brand">
21
+ <Avatar label="JD" />
22
+ </Indicator>`;
23
+
24
+ return (
25
+ <ShowcaseWrapper
26
+ title="Badge hotspots"
27
+ description="Indicator badges and dots for notifications, status, and counts."
28
+ code={code}
29
+ filename="IndicatorExample.tsx"
30
+ docs={
31
+ <ComponentDocs
32
+ rows={[
33
+ { name: "badge", type: "ReactNode", description: "Badge content (number, text, !)." },
34
+ { name: "color", type: "string", defaultValue: "bg-ph-brand", description: "Tailwind colour class." },
35
+ { name: "position", type: "top-right | top-left | bottom-right | bottom-left", defaultValue: "top-right", description: "Indicator position." },
36
+ { name: "dot", type: "boolean", defaultValue: "false", description: "Show a simple dot instead of badge." },
37
+ ]}
38
+ />
39
+ }
40
+ >
41
+ <div className="flex flex-wrap gap-10 rounded-xl border border-ph-border bg-ph-muted px-10 py-8">
42
+ {indicators.map(({ icon: Icon, label, count, hue }) => (
43
+ <Indicator key={label} badge={count} color={hue}>
44
+ <div className="flex h-10 w-10 items-center justify-center rounded-full bg-ph-surface shadow-ph">
45
+ <Icon className="h-6 w-6 text-ph-mutedtext" />
46
+ </div>
47
+ </Indicator>
48
+ ))}
49
+ </div>
50
+ </ShowcaseWrapper>
51
+ );
52
+ }
@@ -0,0 +1,31 @@
1
+ import { Kbd, Panel, ShowcaseWrapper } from "@/components/ui";
2
+
3
+ export default function KbdShowcase() {
4
+ const code = `import { Kbd, Panel } from "the-old-ui";
5
+
6
+ <Panel className="flex flex-wrap items-center gap-3 text-ph-subtle">
7
+ <Kbd keys={["⌘", "K"]} />
8
+ <span className="text-xs font-semibold text-ph-mutedtext">/</span>
9
+ <Kbd keys={["⌥", "⇧", "E"]} />
10
+ <span className="text-xs font-semibold text-ph-mutedtext">/</span>
11
+ <Kbd variant="token">HogQL</Kbd>
12
+ <p className="w-full pt-5 text-xs text-ph-mutedtext">
13
+ Keyboard hints and code tokens are rendered through the same reusable component.
14
+ </p>
15
+ </Panel>`;
16
+
17
+ return (
18
+ <ShowcaseWrapper title="Keyboard glyphs" code={code} filename="KbdExample.tsx">
19
+ <Panel className="flex flex-wrap items-center gap-3 text-ph-subtle">
20
+ <Kbd keys={["⌘", "K"]} />
21
+ <span className="text-xs font-semibold text-ph-mutedtext">/</span>
22
+ <Kbd keys={["⌥", "⇧", "E"]} />
23
+ <span className="text-xs font-semibold text-ph-mutedtext">/</span>
24
+ <Kbd variant="token">HogQL</Kbd>
25
+ <p className="w-full pt-5 text-xs text-ph-mutedtext">
26
+ Keyboard hints and code tokens are rendered through the same reusable component.
27
+ </p>
28
+ </Panel>
29
+ </ShowcaseWrapper>
30
+ );
31
+ }
@@ -0,0 +1,210 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { IconCheck, IconClose, IconPlus } from "@/components/icons";
5
+ import { Button, ComponentDocs, Input, Modal, Select, ShowcaseWrapper, Textarea } from "@/components/ui";
6
+
7
+ export default function ModalShowcase() {
8
+ const [openModal, setOpenModal] = useState<string | null>(null);
9
+
10
+ const close = () => setOpenModal(null);
11
+
12
+ const code = `import { IconCheck, IconClose, IconPlus } from "the-old-ui";
13
+ import { Button, Input, Modal, Select, Textarea } from "the-old-ui";
14
+
15
+ <div className="ph-panel space-y-4">
16
+ <h3 className="text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Patterns</h3>
17
+
18
+ <div className="flex flex-wrap gap-3">
19
+ <Button variant="secondary" onClick={() => setOpenModal("info")}>
20
+ Info
21
+ </Button>
22
+ <Button variant="success" onClick={() => setOpenModal("success")}>
23
+ Success
24
+ </Button>
25
+ <Button variant="danger" onClick={() => setOpenModal("error")}>
26
+ Error
27
+ </Button>
28
+ <Button variant="primary" icon={<IconPlus className="h-4 w-4" aria-hidden />} onClick={() => setOpenModal("form")}>
29
+ Form modal
30
+ </Button>
31
+ </div>
32
+
33
+ <Modal
34
+ open={openModal === "info"}
35
+ onClose={close}
36
+ title="Configure capture"
37
+ description="Lightweight overlay + white sheet — Lemon modals skew toward tight copy and decisive buttons."
38
+ footer={<Button variant="secondary" onClick={close}>Close</Button>}
39
+ />
40
+
41
+ <Modal
42
+ open={openModal === "success"}
43
+ onClose={close}
44
+ showCloseButton={false}
45
+ footer={<Button variant="success" onClick={close}>Continue</Button>}
46
+ >
47
+ <div className="flex items-start gap-3">
48
+ <div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-ph-success">
49
+ <IconCheck className="h-5 w-5" />
50
+ </div>
51
+ <div>
52
+ <h3 className="text-lg font-bold text-ph-success">Saved</h3>
53
+ <p className="mt-1 text-sm text-ph-subtle">Your dashboard layout synced to the team.</p>
54
+ </div>
55
+ </div>
56
+ </Modal>
57
+
58
+ <Modal
59
+ open={openModal === "error"}
60
+ onClose={close}
61
+ showCloseButton={false}
62
+ footer={
63
+ <>
64
+ <Button variant="ghost" onClick={close}>Cancel</Button>
65
+ <Button variant="danger" onClick={close}>View logs</Button>
66
+ </>
67
+ }
68
+ >
69
+ <div className="flex items-start gap-3">
70
+ <div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-red-100 text-ph-danger">
71
+ <IconClose className="h-5 w-5" />
72
+ </div>
73
+ <div>
74
+ <h3 className="text-lg font-bold text-ph-danger">Query failed</h3>
75
+ <p className="mt-1 text-sm text-ph-subtle">ClickHouse returned a timeout — retry or narrow the date range.</p>
76
+ </div>
77
+ </div>
78
+ </Modal>
79
+
80
+ <Modal
81
+ open={openModal === "form"}
82
+ onClose={close}
83
+ size="lg"
84
+ title="Create feature flag"
85
+ footer={
86
+ <>
87
+ <Button variant="ghost" onClick={close}>Cancel</Button>
88
+ <Button variant="primary" onClick={close}>Create</Button>
89
+ </>
90
+ }
91
+ >
92
+ <div className="space-y-4">
93
+ <Input label="Key" placeholder="billing-ui-v3" />
94
+ <Textarea label="Description" placeholder="Expose the rewritten billing funnel" className="h-28" />
95
+ <Select label="Rollout">
96
+ <option>10% staged</option>
97
+ <option>Everyone</option>
98
+ </Select>
99
+ </div>
100
+ </Modal>
101
+ </div>`;
102
+
103
+ return (
104
+ <ShowcaseWrapper
105
+ title="Modals"
106
+ description="Accessible modal shell with open state, title, description, size, close button, and footer props."
107
+ code={code}
108
+ filename="ModalExample.tsx"
109
+ docs={
110
+ <ComponentDocs
111
+ rows={[
112
+ { name: "open", type: "boolean", defaultValue: "false", description: "Controls modal visibility." },
113
+ { name: "onClose", type: "() => void", description: "Called by overlay and close button." },
114
+ { name: "size", type: "sm | md | lg | xl | full", defaultValue: "md", description: "Controls panel max width." },
115
+ { name: "title", type: "string", description: "Accessible dialog heading." },
116
+ { name: "footer", type: "ReactNode", description: "Renders action row with consistent spacing." },
117
+ ]}
118
+ />
119
+ }
120
+ >
121
+ <div className="ph-panel space-y-4">
122
+ <h3 className="text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Patterns</h3>
123
+
124
+ <div className="flex flex-wrap gap-3">
125
+ <Button variant="secondary" onClick={() => setOpenModal("info")}>
126
+ Info
127
+ </Button>
128
+ <Button variant="success" onClick={() => setOpenModal("success")}>
129
+ Success
130
+ </Button>
131
+ <Button variant="danger" onClick={() => setOpenModal("error")}>
132
+ Error
133
+ </Button>
134
+ <Button variant="primary" icon={<IconPlus className="h-4 w-4" aria-hidden />} onClick={() => setOpenModal("form")}>
135
+ Form modal
136
+ </Button>
137
+ </div>
138
+
139
+ <Modal
140
+ open={openModal === "info"}
141
+ onClose={close}
142
+ title="Configure capture"
143
+ description="Lightweight overlay + white sheet — Lemon modals skew toward tight copy and decisive buttons."
144
+ footer={<Button variant="secondary" onClick={close}>Close</Button>}
145
+ />
146
+
147
+ <Modal
148
+ open={openModal === "success"}
149
+ onClose={close}
150
+ showCloseButton={false}
151
+ footer={<Button variant="success" onClick={close}>Continue</Button>}
152
+ >
153
+ <div className="flex items-start gap-3">
154
+ <div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-ph-success">
155
+ <IconCheck className="h-5 w-5" />
156
+ </div>
157
+ <div>
158
+ <h3 className="text-lg font-bold text-ph-success">Saved</h3>
159
+ <p className="mt-1 text-sm text-ph-subtle">Your dashboard layout synced to the team.</p>
160
+ </div>
161
+ </div>
162
+ </Modal>
163
+
164
+ <Modal
165
+ open={openModal === "error"}
166
+ onClose={close}
167
+ showCloseButton={false}
168
+ footer={
169
+ <>
170
+ <Button variant="ghost" onClick={close}>Cancel</Button>
171
+ <Button variant="danger" onClick={close}>View logs</Button>
172
+ </>
173
+ }
174
+ >
175
+ <div className="flex items-start gap-3">
176
+ <div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-red-100 text-ph-danger">
177
+ <IconClose className="h-5 w-5" />
178
+ </div>
179
+ <div>
180
+ <h3 className="text-lg font-bold text-ph-danger">Query failed</h3>
181
+ <p className="mt-1 text-sm text-ph-subtle">ClickHouse returned a timeout — retry or narrow the date range.</p>
182
+ </div>
183
+ </div>
184
+ </Modal>
185
+
186
+ <Modal
187
+ open={openModal === "form"}
188
+ onClose={close}
189
+ size="lg"
190
+ title="Create feature flag"
191
+ footer={
192
+ <>
193
+ <Button variant="ghost" onClick={close}>Cancel</Button>
194
+ <Button variant="primary" onClick={close}>Create</Button>
195
+ </>
196
+ }
197
+ >
198
+ <div className="space-y-4">
199
+ <Input label="Key" placeholder="billing-ui-v3" />
200
+ <Textarea label="Description" placeholder="Expose the rewritten billing funnel" className="h-28" />
201
+ <Select label="Rollout">
202
+ <option>10% staged</option>
203
+ <option>Everyone</option>
204
+ </Select>
205
+ </div>
206
+ </Modal>
207
+ </div>
208
+ </ShowcaseWrapper>
209
+ );
210
+ }