@xenide-io/the-old-ui-theme 0.2.6 → 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 (110) hide show
  1. package/dist/chunk-SHF57J7U.mjs +2910 -0
  2. package/dist/index-CmS6hcUk.d.mts +753 -0
  3. package/dist/index-CmS6hcUk.d.ts +753 -0
  4. package/dist/index.d.mts +5 -755
  5. package/dist/index.d.ts +5 -755
  6. package/dist/index.js +43 -23
  7. package/dist/index.mjs +252 -2846
  8. package/dist/ui.d.mts +3 -0
  9. package/dist/ui.d.ts +3 -0
  10. package/dist/ui.js +2946 -0
  11. package/dist/ui.mjs +139 -0
  12. package/package.json +11 -3
  13. package/src/components/charts/index.ts +8 -0
  14. package/src/components/charts/ph-insight-charts.tsx +162 -0
  15. package/src/components/dashboard/DashboardFiltersBar.tsx +19 -0
  16. package/src/components/dashboard/DashboardGrid.tsx +23 -0
  17. package/src/components/dashboard/DashboardInsightPlaceholder.tsx +37 -0
  18. package/src/components/dashboard/DashboardKpiCard.tsx +25 -0
  19. package/src/components/dashboard/DashboardToolbar.tsx +23 -0
  20. package/src/components/dashboard/DashboardWell.tsx +10 -0
  21. package/src/components/dashboard/InsightMiniCard.tsx +26 -0
  22. package/src/components/dashboard/InsightShell.tsx +37 -0
  23. package/src/components/dashboard/InsightShellHeader.tsx +22 -0
  24. package/src/components/dashboard/MiniTrendBars.tsx +51 -0
  25. package/src/components/dashboard/index.ts +31 -0
  26. package/src/components/dashboard/types.ts +9 -0
  27. package/src/components/icons/IconBase.tsx +39 -0
  28. package/src/components/icons/createIconBase.tsx +27 -0
  29. package/src/components/icons/icons.tsx +367 -0
  30. package/src/components/icons/index.ts +3 -0
  31. package/src/components/sections/AccordionShowcase.tsx +45 -0
  32. package/src/components/sections/AlertShowcase.tsx +39 -0
  33. package/src/components/sections/AvatarShowcase.tsx +80 -0
  34. package/src/components/sections/BadgeShowcase.tsx +65 -0
  35. package/src/components/sections/ButtonShowcase.tsx +312 -0
  36. package/src/components/sections/CalendarShowcase.tsx +35 -0
  37. package/src/components/sections/CardShowcase.tsx +143 -0
  38. package/src/components/sections/ChartShowcase.tsx +190 -0
  39. package/src/components/sections/CodeMockupShowcase.tsx +56 -0
  40. package/src/components/sections/ColorPalette.tsx +117 -0
  41. package/src/components/sections/CommandPaletteShowcase.tsx +48 -0
  42. package/src/components/sections/CountdownShowcase.tsx +43 -0
  43. package/src/components/sections/DashboardShowcase.tsx +191 -0
  44. package/src/components/sections/DiffShowcase.tsx +70 -0
  45. package/src/components/sections/DrawerShowcase.tsx +97 -0
  46. package/src/components/sections/DropdownShowcase.tsx +100 -0
  47. package/src/components/sections/EmptyStateShowcase.tsx +50 -0
  48. package/src/components/sections/FilterChipsShowcase.tsx +50 -0
  49. package/src/components/sections/FormShowcase.tsx +126 -0
  50. package/src/components/sections/HoverCardShowcase.tsx +50 -0
  51. package/src/components/sections/IconShowcase.tsx +247 -0
  52. package/src/components/sections/IndicatorShowcase.tsx +52 -0
  53. package/src/components/sections/KbdShowcase.tsx +31 -0
  54. package/src/components/sections/ModalShowcase.tsx +210 -0
  55. package/src/components/sections/NavigationShowcase.tsx +199 -0
  56. package/src/components/sections/ProgressShowcase.tsx +85 -0
  57. package/src/components/sections/SegmentedControlShowcase.tsx +49 -0
  58. package/src/components/sections/SetupThemeShowcase.tsx +262 -0
  59. package/src/components/sections/StackShowcase.tsx +33 -0
  60. package/src/components/sections/StatShowcase.tsx +129 -0
  61. package/src/components/sections/StepperShowcase.tsx +37 -0
  62. package/src/components/sections/SwapShowcase.tsx +91 -0
  63. package/src/components/sections/TabShowcase.tsx +84 -0
  64. package/src/components/sections/TableShowcase.tsx +140 -0
  65. package/src/components/sections/TimelineShowcase.tsx +83 -0
  66. package/src/components/sections/ToastShowcase.tsx +108 -0
  67. package/src/components/sections/TooltipShowcase.tsx +44 -0
  68. package/src/components/sections/UtilityShowcase.tsx +81 -0
  69. package/src/components/ui/Accordion.tsx +77 -0
  70. package/src/components/ui/Alert.tsx +68 -0
  71. package/src/components/ui/Avatar.tsx +97 -0
  72. package/src/components/ui/Badge.tsx +55 -0
  73. package/src/components/ui/Button.tsx +110 -0
  74. package/src/components/ui/ButtonChrome.tsx +20 -0
  75. package/src/components/ui/Calendar.tsx +116 -0
  76. package/src/components/ui/Card.tsx +60 -0
  77. package/src/components/ui/ChatBubble.tsx +71 -0
  78. package/src/components/ui/CodeBlock.tsx +48 -0
  79. package/src/components/ui/CollapsibleSection.tsx +49 -0
  80. package/src/components/ui/CommandPalette.tsx +137 -0
  81. package/src/components/ui/ComponentDocs.tsx +52 -0
  82. package/src/components/ui/Drawer.tsx +71 -0
  83. package/src/components/ui/DropdownMenu.tsx +138 -0
  84. package/src/components/ui/EmptyState.tsx +33 -0
  85. package/src/components/ui/FilterChips.tsx +50 -0
  86. package/src/components/ui/HoverCard.tsx +36 -0
  87. package/src/components/ui/Indicator.tsx +61 -0
  88. package/src/components/ui/Input.tsx +359 -0
  89. package/src/components/ui/Kbd.tsx +38 -0
  90. package/src/components/ui/Modal.tsx +75 -0
  91. package/src/components/ui/Navigation.tsx +94 -0
  92. package/src/components/ui/Panel.tsx +18 -0
  93. package/src/components/ui/Progress.tsx +59 -0
  94. package/src/components/ui/Rating.tsx +65 -0
  95. package/src/components/ui/SearchInput.tsx +106 -0
  96. package/src/components/ui/SegmentedControl.tsx +44 -0
  97. package/src/components/ui/ShowcaseWrapper.tsx +136 -0
  98. package/src/components/ui/Stat.tsx +39 -0
  99. package/src/components/ui/Stepper.tsx +75 -0
  100. package/src/components/ui/Table.tsx +55 -0
  101. package/src/components/ui/Tabs.tsx +53 -0
  102. package/src/components/ui/Terminal.tsx +54 -0
  103. package/src/components/ui/ThemeDomSync.tsx +17 -0
  104. package/src/components/ui/ThemeManager.tsx +18 -0
  105. package/src/components/ui/ThemeSwitcher.tsx +46 -0
  106. package/src/components/ui/Timeline.tsx +60 -0
  107. package/src/components/ui/Toast.tsx +70 -0
  108. package/src/components/ui/Typography.tsx +129 -0
  109. package/src/components/ui/index.ts +92 -0
  110. package/src/styles/themes.css +118 -0
@@ -0,0 +1,199 @@
1
+ "use client";
2
+
3
+ import { IconBell, IconPerson } from "@/components/icons";
4
+ import { Button, DropdownItem, DropdownMenu, SearchInput, ShowcaseWrapper } from "@/components/ui";
5
+
6
+ export default function NavigationShowcase() {
7
+ const code = `import { IconBell, IconPerson } from "the-old-ui";
8
+ import { Button, DropdownItem, DropdownMenu, SearchInput } from "the-old-ui";
9
+
10
+ <div className="space-y-8">
11
+ <div className="ph-panel">
12
+ <h3 className="mb-4 text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Top bar density</h3>
13
+ <div className="ph-navbar-demo justify-between gap-4">
14
+ <span className="text-lg font-bold text-ph-brand">posthog</span>
15
+ <div className="flex flex-1 flex-wrap items-center justify-end gap-2">
16
+ <SearchInput
17
+ label="Jump to"
18
+ hideLabel
19
+ shortcut="Cmd K"
20
+ placeholder="Jump to…"
21
+ density="compact"
22
+ />
23
+ <Button type="button" variant="ghost" shape="circle" className="relative" aria-label="Notifications">
24
+ <IconBell className="h-5 w-5 text-ph-mutedtext" />
25
+ <span className="absolute right-2 top-2 h-2 w-2 rounded-full bg-ph-brand ring-2 ring-ph-surface" />
26
+ </Button>
27
+ <DropdownMenu
28
+ align="end"
29
+ aria-label="Account menu"
30
+ trigger={
31
+ <span className="flex h-9 w-9 cursor-pointer items-center justify-center rounded-full bg-ph-muted text-ph-ink">
32
+ <IconPerson className="h-5 w-5" aria-hidden />
33
+ </span>
34
+ }
35
+ >
36
+ <DropdownItem>Personal API keys</DropdownItem>
37
+ <DropdownItem>Organisation settings</DropdownItem>
38
+ </DropdownMenu>
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ <div className="ph-panel flex gap-10">
44
+ <div>
45
+ <h3 className="mb-4 text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Side navigation</h3>
46
+ <ul className="w-52 space-y-1 text-sm font-medium">
47
+ <li>
48
+ <a href="#" className="block rounded-md bg-ph-muted px-3 py-2 text-ph-ink">
49
+ Home
50
+ </a>
51
+ </li>
52
+ <li>
53
+ <a href="#" className="block rounded-md px-3 py-2 text-ph-subtle hover:bg-ph-muted/70">
54
+ Data pipeline
55
+ </a>
56
+ </li>
57
+ <li>
58
+ <details open className="ph-details [&>summary::-webkit-details-marker]:hidden">
59
+ <summary className="cursor-pointer list-none px-3 py-2 text-ph-mutedtext">Warehouse</summary>
60
+ <ul className="mt-1 space-y-1 border-l border-ph-border pl-5">
61
+ <li>
62
+ <a href="#" className="block py-1 text-ph-subtle hover:text-ph-ink">
63
+ Sources
64
+ </a>
65
+ </li>
66
+ <li>
67
+ <a href="#" className="block py-1 text-ph-subtle hover:text-ph-ink">
68
+ Views
69
+ </a>
70
+ </li>
71
+ </ul>
72
+ </details>
73
+ </li>
74
+ </ul>
75
+ </div>
76
+
77
+ <div className="flex-1">
78
+ <h3 className="mb-4 text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Timeline steps</h3>
79
+ <ol className="ph-steps">
80
+ <li className="flex flex-col items-center gap-2">
81
+ <span className="flex h-8 w-8 items-center justify-center rounded-full bg-ph-brand text-xs font-bold text-white">
82
+ 1
83
+ </span>
84
+ <span>Install snippet</span>
85
+ </li>
86
+ <li className="flex flex-col items-center gap-2 opacity-60">
87
+ <span className="flex h-8 w-8 items-center justify-center rounded-full border border-dashed border-ph-border text-xs">
88
+ 2
89
+ </span>
90
+ <span>Send test event</span>
91
+ </li>
92
+ <li className="flex flex-col items-center gap-2 opacity-60">
93
+ <span className="flex h-8 w-8 items-center justify-center rounded-full border border-dashed border-ph-border text-xs">
94
+ 3
95
+ </span>
96
+ <span>Invite team</span>
97
+ </li>
98
+ </ol>
99
+ </div>
100
+ </div>
101
+ </div>`;
102
+
103
+ return (
104
+ <ShowcaseWrapper title="Navigation chrome" code={code} filename="NavigationExample.tsx">
105
+ <div className="space-y-8">
106
+ <div className="ph-panel">
107
+ <h3 className="mb-4 text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Top bar density</h3>
108
+ <div className="ph-navbar-demo justify-between gap-4">
109
+ <span className="text-lg font-bold text-ph-brand">posthog</span>
110
+ <div className="flex flex-1 flex-wrap items-center justify-end gap-2">
111
+ <SearchInput
112
+ label="Jump to"
113
+ hideLabel
114
+ shortcut="Cmd K"
115
+ placeholder="Jump to…"
116
+ density="compact"
117
+ />
118
+ <Button type="button" variant="ghost" shape="circle" className="relative" aria-label="Notifications">
119
+ <IconBell className="h-5 w-5 text-ph-mutedtext" />
120
+ <span className="absolute right-2 top-2 h-2 w-2 rounded-full bg-ph-brand ring-2 ring-ph-surface" />
121
+ </Button>
122
+ <DropdownMenu
123
+ align="end"
124
+ aria-label="Account menu"
125
+ trigger={
126
+ <span className="flex h-9 w-9 cursor-pointer items-center justify-center rounded-full bg-ph-muted text-ph-ink">
127
+ <IconPerson className="h-5 w-5" aria-hidden />
128
+ </span>
129
+ }
130
+ >
131
+ <DropdownItem>Personal API keys</DropdownItem>
132
+ <DropdownItem>Organisation settings</DropdownItem>
133
+ </DropdownMenu>
134
+ </div>
135
+ </div>
136
+ </div>
137
+
138
+ <div className="ph-panel flex gap-10">
139
+ <div>
140
+ <h3 className="mb-4 text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Side navigation</h3>
141
+ <ul className="w-52 space-y-1 text-sm font-medium">
142
+ <li>
143
+ <a href="#" className="block rounded-md bg-ph-muted px-3 py-2 text-ph-ink">
144
+ Home
145
+ </a>
146
+ </li>
147
+ <li>
148
+ <a href="#" className="block rounded-md px-3 py-2 text-ph-subtle hover:bg-ph-muted/70">
149
+ Data pipeline
150
+ </a>
151
+ </li>
152
+ <li>
153
+ <details open className="ph-details [&>summary::-webkit-details-marker]:hidden">
154
+ <summary className="cursor-pointer list-none px-3 py-2 text-ph-mutedtext">Warehouse</summary>
155
+ <ul className="mt-1 space-y-1 border-l border-ph-border pl-5">
156
+ <li>
157
+ <a href="#" className="block py-1 text-ph-subtle hover:text-ph-ink">
158
+ Sources
159
+ </a>
160
+ </li>
161
+ <li>
162
+ <a href="#" className="block py-1 text-ph-subtle hover:text-ph-ink">
163
+ Views
164
+ </a>
165
+ </li>
166
+ </ul>
167
+ </details>
168
+ </li>
169
+ </ul>
170
+ </div>
171
+
172
+ <div className="flex-1">
173
+ <h3 className="mb-4 text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Timeline steps</h3>
174
+ <ol className="ph-steps">
175
+ <li className="flex flex-col items-center gap-2">
176
+ <span className="flex h-8 w-8 items-center justify-center rounded-full bg-ph-brand text-xs font-bold text-white">
177
+ 1
178
+ </span>
179
+ <span>Install snippet</span>
180
+ </li>
181
+ <li className="flex flex-col items-center gap-2 opacity-60">
182
+ <span className="flex h-8 w-8 items-center justify-center rounded-full border border-dashed border-ph-border text-xs">
183
+ 2
184
+ </span>
185
+ <span>Send test event</span>
186
+ </li>
187
+ <li className="flex flex-col items-center gap-2 opacity-60">
188
+ <span className="flex h-8 w-8 items-center justify-center rounded-full border border-dashed border-ph-border text-xs">
189
+ 3
190
+ </span>
191
+ <span>Invite team</span>
192
+ </li>
193
+ </ol>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </ShowcaseWrapper>
198
+ );
199
+ }
@@ -0,0 +1,85 @@
1
+ import { IconSpinner } from "@/components/icons";
2
+ import { ComponentDocs, Progress, ShowcaseWrapper } from "@/components/ui";
3
+
4
+ export default function ProgressShowcase() {
5
+ const code = `import { Progress } from "the-old-ui";
6
+
7
+ <div className="space-y-8">
8
+ <div className="ph-panel space-y-6">
9
+ <Progress label="Ingest backlog" value={72} color="bg-ph-brand" showPercentage />
10
+ <Progress label="Exports" value={45} color="bg-ph-blue" showPercentage />
11
+ <Progress label="LLM evaluations" value={28} color="bg-ph-purple" showPercentage />
12
+ </div>
13
+
14
+ <div className="ph-panel flex flex-wrap items-center gap-10">
15
+ <Progress value={72} color="bg-ph-brand" size="lg" className="w-48" />
16
+ <Progress value={45} color="bg-ph-blue" size="lg" className="w-48" />
17
+ </div>
18
+
19
+ <div className="ph-panel flex flex-wrap items-center gap-8">
20
+ <span className="ph-loading" role="status" aria-label="Loading" />
21
+ <IconSpinner className="h-6 w-6 text-ph-brand" role="status" aria-label="Loading" />
22
+ <div className="ph-loading-dots" role="status" aria-label="Loading">
23
+ <span />
24
+ <span />
25
+ <span />
26
+ </div>
27
+ </div>
28
+ </div>`;
29
+
30
+ return (
31
+ <ShowcaseWrapper
32
+ title="Progress & loading"
33
+ description="Linear progress bars, spinners, and skeleton placeholders with semantic colour support."
34
+ code={code}
35
+ filename="ProgressExample.tsx"
36
+ docs={
37
+ <ComponentDocs
38
+ rows={[
39
+ { name: "value", type: "number", description: "Current value." },
40
+ { name: "max", type: "number", defaultValue: "100", description: "Maximum value." },
41
+ { name: "color", type: "string", defaultValue: "bg-ph-brand", description: "Tailwind colour class for the bar." },
42
+ { name: "label", type: "string", description: "Label shown above the bar." },
43
+ { name: "showPercentage", type: "boolean", defaultValue: "false", description: "Show percentage text." },
44
+ { name: "size", type: "sm | md | lg", defaultValue: "md", description: "Bar height." },
45
+ ]}
46
+ />
47
+ }
48
+ >
49
+ <div className="space-y-8">
50
+ <div className="ph-panel space-y-6">
51
+ <h3 className="text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Linear bars</h3>
52
+ <Progress label="Ingest backlog" value={72} color="bg-ph-brand" showPercentage />
53
+ <Progress label="Exports" value={45} color="bg-ph-blue" showPercentage />
54
+ <Progress label="LLM evaluations" value={28} color="bg-ph-purple" showPercentage />
55
+ </div>
56
+
57
+ <div className="ph-panel flex flex-wrap items-center gap-10">
58
+ <div className="w-full">
59
+ <h3 className="mb-4 text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Large bars</h3>
60
+ <div className="flex gap-10">
61
+ <Progress value={72} color="bg-ph-brand" size="lg" className="w-48" />
62
+ <Progress value={45} color="bg-ph-blue" size="lg" className="w-48" />
63
+ </div>
64
+ </div>
65
+ </div>
66
+
67
+ <div className="ph-panel flex flex-wrap items-center gap-8">
68
+ <div className="flex items-center gap-3 text-ph-subtle">
69
+ <span className="ph-loading" role="status" aria-label="Loading" />
70
+ <code className="ph-kbd">ph-loading</code> — CSS spinner
71
+ </div>
72
+ <div className="flex items-center gap-3 text-ph-subtle">
73
+ <IconSpinner className="h-6 w-6 text-ph-brand" role="status" aria-label="Loading" />
74
+ <code className="ph-kbd">IconSpinner</code> — Animated icon
75
+ </div>
76
+ <div className="ph-loading-dots" role="status" aria-label="Loading">
77
+ <span />
78
+ <span />
79
+ <span />
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </ShowcaseWrapper>
84
+ );
85
+ }
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { ComponentDocs, SegmentedControl, ShowcaseWrapper } from "@/components/ui";
5
+ import { IconGridView, IconListView } from "@/components/icons";
6
+
7
+ export default function SegmentedControlShowcase() {
8
+ const [view, setView] = useState("grid");
9
+
10
+ const options = [
11
+ { value: "grid", label: "Grid", icon: <IconGridView className="h-4 w-4" /> },
12
+ { value: "list", label: "List", icon: <IconListView className="h-4 w-4" /> },
13
+ ];
14
+
15
+ const code = `import { SegmentedControl } from "the-old-ui";
16
+ import { IconGridView, IconListView } from "the-old-ui";
17
+
18
+ <div className="ph-panel">
19
+ <SegmentedControl options={options} value={view} onChange={setView} />
20
+ <div className="mt-4 rounded-lg bg-ph-muted p-4 text-sm text-ph-subtle">
21
+ Selected: <span className="font-semibold text-ph-ink">{view}</span>
22
+ </div>
23
+ </div>`;
24
+
25
+ return (
26
+ <ShowcaseWrapper
27
+ title="Segmented Control"
28
+ description="Compact controlled switch for mutually exclusive display modes."
29
+ code={code}
30
+ filename="SegmentedControlExample.tsx"
31
+ docs={
32
+ <ComponentDocs
33
+ rows={[
34
+ { name: "options", type: "{ value; label; icon? }[]", description: "Segments to render." },
35
+ { name: "value", type: "string", description: "Currently selected value." },
36
+ { name: "onChange", type: "(value: string) => void", description: "Called when a segment is selected." },
37
+ ]}
38
+ />
39
+ }
40
+ >
41
+ <div className="ph-panel">
42
+ <SegmentedControl options={options} value={view} onChange={setView} />
43
+ <div className="mt-4 rounded-lg bg-ph-muted p-4 text-sm text-ph-subtle">
44
+ Selected: <span className="font-semibold text-ph-ink">{view}</span>
45
+ </div>
46
+ </div>
47
+ </ShowcaseWrapper>
48
+ );
49
+ }
@@ -0,0 +1,262 @@
1
+ "use client";
2
+
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { CodeBlock, H3, P, Panel, ThemeSwitcher } from "@/components/ui";
5
+ import { THEMES } from "@/themes";
6
+
7
+ const themePairs = [
8
+ { name: "HedgeHog", light: "hedgehog-light", dark: "hedgehog-dark" },
9
+ { name: "Sheets", light: "sheets", dark: "sheets-dark" },
10
+ { name: "Note", light: "note", dark: "note-dark" },
11
+ { name: "Presentation", light: "presentation", dark: "presentation-dark" },
12
+ { name: "Socials", light: "socials", dark: "socials-dark" },
13
+ { name: "Chats", light: "chats-light", dark: "chats-dark" },
14
+ { name: "Catppuccin", light: "catppuccin-light", dark: "catppuccin-dark" },
15
+ { name: "Xenide", light: "xenide-light", dark: "xenide-dark" },
16
+ { name: "GitHub", light: "github-light", dark: "github-dark" },
17
+ { name: "Rose Pine", light: "rosepine-light", dark: "rosepine-dark" },
18
+ { name: "TurtleTime", light: "turtletime", dark: "turtletime-dark" },
19
+ { name: "Bikini Bottom", light: "bikini-bottom", dark: "bikini-bottom-dark" },
20
+ { name: "Notion", light: "notion", dark: "notion-dark" },
21
+ ] as const;
22
+
23
+ const guideTokens = [
24
+ { label: "canvas", token: "--ph-canvas", text: "text-ph-ink" },
25
+ { label: "surface", token: "--ph-surface", text: "text-ph-ink" },
26
+ { label: "muted", token: "--ph-muted", text: "text-ph-ink" },
27
+ { label: "toolbar", token: "--ph-toolbar", text: "text-ph-ink" },
28
+ { label: "border", token: "--ph-border", text: "text-ph-ink" },
29
+ { label: "accent", token: "--ph-accent", text: "text-white" },
30
+ { label: "blue", token: "--ph-blue", text: "text-white" },
31
+ { label: "purple", token: "--ph-purple", text: "text-white" },
32
+ { label: "success", token: "--ph-success", text: "text-white" },
33
+ { label: "warning", token: "--ph-warning", text: "text-white" },
34
+ { label: "danger", token: "--ph-danger", text: "text-white" },
35
+ { label: "info", token: "--ph-info", text: "text-white" },
36
+ ] as const;
37
+
38
+ const dataTokens = [1, 2, 3, 4, 5, 6, 7].map((item) => ({
39
+ label: `data ${item}`,
40
+ token: `--ph-data-${item}`,
41
+ text: "text-white",
42
+ }));
43
+
44
+ const installCode = `bun add the-old-ui
45
+ # or
46
+ npm install the-old-ui`;
47
+
48
+ const layoutCode = `// app/layout.tsx
49
+ import "the-old-ui/styles.css";
50
+ import { THEME_INIT_SCRIPT, ThemeManager } from "the-old-ui";
51
+
52
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
53
+ return (
54
+ <html lang="en" data-theme="hedgehog-light" suppressHydrationWarning>
55
+ <head>
56
+ <script dangerouslySetInnerHTML={{ __html: THEME_INIT_SCRIPT }} />
57
+ </head>
58
+ <body>
59
+ <ThemeManager>{children}</ThemeManager>
60
+ </body>
61
+ </html>
62
+ );
63
+ }`;
64
+
65
+ const tailwindCode = `// tailwind.config.ts
66
+ import theOldUiPreset from "the-old-ui/tailwind-preset";
67
+
68
+ export default {
69
+ presets: [theOldUiPreset],
70
+ content: [
71
+ "./src/**/*.{ts,tsx}",
72
+ "./app/**/*.{ts,tsx}",
73
+ "./node_modules/the-old-ui/dist/**/*.{js,mjs}",
74
+ ],
75
+ };`;
76
+
77
+ const switchCode = `import { ThemeSwitcher, persistTheme } from "the-old-ui";
78
+
79
+ <ThemeSwitcher />
80
+
81
+ // Or switch manually
82
+ persistTheme("sheets-dark");`;
83
+
84
+ const customThemeCode = `/* app/globals.css */
85
+ @import "the-old-ui/styles.css";
86
+
87
+ [data-theme="my-theme-light"] {
88
+ color-scheme: light;
89
+
90
+ --ph-canvas: #f8f5ef;
91
+ --ph-surface: #ffffff;
92
+ --ph-muted: #eee8dd;
93
+ --ph-toolbar: #e5dccd;
94
+ --ph-border: #d7cbb8;
95
+ --ph-border-strong: #a99b87;
96
+
97
+ --ph-text-primary: #15110c;
98
+ --ph-text-secondary: #4d4337;
99
+ --ph-text-tertiary: #796f63;
100
+
101
+ --ph-accent: #f97316;
102
+ --ph-accent-hover: #ea580c;
103
+ --ph-blue: #2563eb;
104
+ --ph-purple: #7c3aed;
105
+ --ph-success: #15803d;
106
+ --ph-warning: #b45309;
107
+ --ph-danger: #dc2626;
108
+ --ph-info: #2563eb;
109
+ }
110
+
111
+ [data-theme="my-theme-dark"] {
112
+ color-scheme: dark;
113
+
114
+ --ph-canvas: #11100e;
115
+ --ph-surface: #191713;
116
+ --ph-muted: #242018;
117
+ --ph-toolbar: #2e281f;
118
+ --ph-border: #443a2b;
119
+ --ph-border-strong: #7a6a54;
120
+
121
+ --ph-text-primary: #fff7ed;
122
+ --ph-text-secondary: #d8c8b6;
123
+ --ph-text-tertiary: #a89985;
124
+
125
+ --ph-accent: #fb923c;
126
+ --ph-accent-hover: #fdba74;
127
+ --ph-blue: #60a5fa;
128
+ --ph-purple: #a78bfa;
129
+ --ph-success: #4ade80;
130
+ --ph-warning: #facc15;
131
+ --ph-danger: #f87171;
132
+ --ph-info: #60a5fa;
133
+ }`;
134
+
135
+ const registryCode = `// Add to src/themes/registry.ts if this repo should show it in ThemeSwitcher
136
+ {
137
+ id: "my-theme-light",
138
+ name: "My Theme Light",
139
+ description: "Custom light palette.",
140
+ colorScheme: "light",
141
+ group: "Custom",
142
+ },
143
+ {
144
+ id: "my-theme-dark",
145
+ name: "My Theme Dark",
146
+ description: "Custom dark palette.",
147
+ colorScheme: "dark",
148
+ group: "Custom",
149
+ }`;
150
+
151
+ export default function SetupThemeShowcase() {
152
+ const [activeTheme, setActiveTheme] = useState("hedgehog-light");
153
+
154
+ useEffect(() => {
155
+ const root = document.documentElement;
156
+ const update = () => setActiveTheme(root.getAttribute("data-theme") || "hedgehog-light");
157
+ update();
158
+
159
+ const observer = new MutationObserver(update);
160
+ observer.observe(root, { attributes: true, attributeFilter: ["data-theme"] });
161
+ return () => observer.disconnect();
162
+ }, []);
163
+
164
+ const activeThemeCode = useMemo(() => {
165
+ const theme = THEMES.find((item) => item.id === activeTheme);
166
+ return `// Current selected theme in this demo\n${JSON.stringify({
167
+ id: activeTheme,
168
+ name: theme?.name ?? activeTheme,
169
+ colorScheme: theme?.colorScheme ?? "light",
170
+ group: theme?.group ?? "Custom",
171
+ }, null, 2)}`;
172
+ }, [activeTheme]);
173
+
174
+ const themeListCode = useMemo(() => {
175
+ return `export const themePairs = ${JSON.stringify(themePairs, null, 2)} as const;`;
176
+ }, []);
177
+
178
+ return (
179
+ <div className="space-y-8">
180
+ <Panel className="space-y-4">
181
+ <H3>Setup</H3>
182
+ <P tone="subtle">
183
+ This demo is also the docs. A consuming app imports the package CSS once, adds the Tailwind preset, then switches palettes through <code className="ph-kbd">html[data-theme]</code>.
184
+ </P>
185
+ <div className="grid gap-4 lg:grid-cols-2">
186
+ <CodeBlock code={installCode} filename="install.sh" language="bash" />
187
+ <CodeBlock code={tailwindCode} filename="tailwind.config.ts" />
188
+ </div>
189
+ <CodeBlock code={layoutCode} filename="app/layout.tsx" />
190
+ </Panel>
191
+
192
+ <Panel className="space-y-4">
193
+ <div className="flex flex-wrap items-center justify-between gap-4">
194
+ <div>
195
+ <H3>Theme Switching</H3>
196
+ <P tone="subtle">Each default palette is a light/dark pair. Pick one below and copy the active theme ID.</P>
197
+ </div>
198
+ <ThemeSwitcher />
199
+ </div>
200
+ <div className="grid gap-4 lg:grid-cols-2">
201
+ <CodeBlock code={activeThemeCode} filename="current-theme.ts" />
202
+ <CodeBlock code={switchCode} filename="ThemeSwitch.tsx" />
203
+ </div>
204
+ </Panel>
205
+
206
+ <Panel className="space-y-4">
207
+ <H3>Default Theme Pairs</H3>
208
+ <P tone="subtle">Use these IDs with <code className="ph-kbd">data-theme</code> or <code className="ph-kbd">persistTheme()</code>.</P>
209
+ <CodeBlock code={themeListCode} filename="theme-pairs.ts" />
210
+ </Panel>
211
+
212
+ <Panel className="space-y-5">
213
+ <div>
214
+ <H3>Theme Color Guide</H3>
215
+ <P tone="subtle">
216
+ Every built-in theme is rendered below with its own <code className="ph-kbd">data-theme</code> attribute. These swatches are the guide for what each token becomes in that theme.
217
+ </P>
218
+ </div>
219
+ <div className="grid gap-4 lg:grid-cols-2">
220
+ {THEMES.map((theme) => (
221
+ <div
222
+ key={theme.id}
223
+ data-theme={theme.id}
224
+ className="rounded-xl border border-ph-border bg-ph-canvas p-4 shadow-ph"
225
+ >
226
+ <div className="mb-3 flex items-baseline justify-between gap-3">
227
+ <div>
228
+ <h4 className="font-semibold text-ph-ink">{theme.name}</h4>
229
+ <p className="text-xs text-ph-mutedtext">{theme.id}</p>
230
+ </div>
231
+ <span className="rounded-full border border-ph-border bg-ph-surface px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-ph-mutedtext">
232
+ {theme.colorScheme}
233
+ </span>
234
+ </div>
235
+ <div className="grid grid-cols-3 gap-2 sm:grid-cols-4">
236
+ {[...guideTokens, ...dataTokens].map((item) => (
237
+ <div
238
+ key={item.token}
239
+ className={`rounded-lg border border-ph-border p-2 ${item.text}`}
240
+ style={{ background: `var(${item.token})` }}
241
+ >
242
+ <div className="text-[10px] font-bold uppercase tracking-wide">{item.label}</div>
243
+ <div className="mt-1 truncate font-mono text-[9px] opacity-80">{item.token}</div>
244
+ </div>
245
+ ))}
246
+ </div>
247
+ </div>
248
+ ))}
249
+ </div>
250
+ </Panel>
251
+
252
+ <Panel className="space-y-4">
253
+ <H3>Custom Light & Dark Theme</H3>
254
+ <P tone="subtle">Custom themes are DaisyUI-style: define one light token block and one dark token block. Components read semantic tokens, not hardcoded colours.</P>
255
+ <div className="grid gap-4 lg:grid-cols-2">
256
+ <CodeBlock code={customThemeCode} filename="custom-theme.css" language="css" />
257
+ <CodeBlock code={registryCode} filename="registry.ts" />
258
+ </div>
259
+ </Panel>
260
+ </div>
261
+ );
262
+ }
@@ -0,0 +1,33 @@
1
+ import { ShowcaseWrapper } from "@/components/ui";
2
+
3
+ export default function StackShowcase() {
4
+ const code = `
5
+
6
+ <div className="rounded-xl border border-ph-border bg-ph-muted p-10">
7
+ <div className="relative mx-auto h-44 w-48">
8
+ <div className="absolute inset-3 translate-x-4 translate-y-4 rounded-xl border border-ph-border bg-ph-toolbar shadow-ph ring-8 ring-ph-muted" />
9
+ <div className="absolute inset-y-7 left-8 right-[-1rem] translate-x-1 rounded-xl border border-ph-border bg-ph-blue text-center text-xs font-semibold uppercase leading-[4.75rem] text-white shadow-ph ring-8 ring-ph-muted">
10
+ Replay
11
+ </div>
12
+ <div className="absolute inset-x-5 top-0 flex h-[5.75rem] items-center justify-center rounded-xl border border-ph-border bg-ph-surface shadow-ph-md ring-8 ring-ph-muted">
13
+ <span className="text-sm font-bold text-ph-brand">Trends insight</span>
14
+ </div>
15
+ </div>
16
+ </div>`;
17
+
18
+ return (
19
+ <ShowcaseWrapper title="Stacked surfaces" code={code} filename="StackExample.tsx">
20
+ <div className="rounded-xl border border-ph-border bg-ph-muted p-10">
21
+ <div className="relative mx-auto h-44 w-48">
22
+ <div className="absolute inset-3 translate-x-4 translate-y-4 rounded-xl border border-ph-border bg-ph-toolbar shadow-ph ring-8 ring-ph-muted" />
23
+ <div className="absolute inset-y-7 left-8 right-[-1rem] translate-x-1 rounded-xl border border-ph-border bg-ph-blue text-center text-xs font-semibold uppercase leading-[4.75rem] text-white shadow-ph ring-8 ring-ph-muted">
24
+ Replay
25
+ </div>
26
+ <div className="absolute inset-x-5 top-0 flex h-[5.75rem] items-center justify-center rounded-xl border border-ph-border bg-ph-surface shadow-ph-md ring-8 ring-ph-muted">
27
+ <span className="text-sm font-bold text-ph-brand">Trends insight</span>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </ShowcaseWrapper>
32
+ );
33
+ }