@xenide-io/the-old-ui-theme 0.2.6 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/chunk-FDMD3IIN.mjs +3831 -0
- package/dist/index-D1RTT2Ap.d.mts +1044 -0
- package/dist/index-D1RTT2Ap.d.ts +1044 -0
- package/dist/index.d.mts +11 -758
- package/dist/index.d.ts +11 -758
- package/dist/index.js +1749 -768
- package/dist/index.mjs +312 -2846
- package/dist/tailwind-preset.js +7 -0
- package/dist/tailwind-preset.mjs +7 -0
- package/dist/ui.d.mts +4 -0
- package/dist/ui.d.ts +4 -0
- package/dist/ui.js +3864 -0
- package/dist/ui.mjs +169 -0
- package/package.json +28 -6
- package/src/app/globals.css +1005 -227
- package/src/components/charts/index.ts +8 -0
- package/src/components/charts/ph-insight-charts.tsx +162 -0
- package/src/components/dashboard/DashboardFiltersBar.tsx +19 -0
- package/src/components/dashboard/DashboardGrid.tsx +23 -0
- package/src/components/dashboard/DashboardInsightPlaceholder.tsx +37 -0
- package/src/components/dashboard/DashboardKpiCard.tsx +25 -0
- package/src/components/dashboard/DashboardToolbar.tsx +23 -0
- package/src/components/dashboard/DashboardWell.tsx +10 -0
- package/src/components/dashboard/InsightMiniCard.tsx +26 -0
- package/src/components/dashboard/InsightShell.tsx +37 -0
- package/src/components/dashboard/InsightShellHeader.tsx +22 -0
- package/src/components/dashboard/MiniTrendBars.tsx +51 -0
- package/src/components/dashboard/index.ts +31 -0
- package/src/components/dashboard/types.ts +9 -0
- package/src/components/icons/IconBase.tsx +47 -0
- package/src/components/icons/createIconBase.tsx +32 -0
- package/src/components/icons/icons.tsx +557 -0
- package/src/components/icons/index.ts +3 -0
- package/src/components/sections/AccordionShowcase.tsx +45 -0
- package/src/components/sections/AlertShowcase.tsx +40 -0
- package/src/components/sections/AvatarShowcase.tsx +80 -0
- package/src/components/sections/BadgeShowcase.tsx +65 -0
- package/src/components/sections/ButtonShowcase.tsx +308 -0
- package/src/components/sections/CalendarShowcase.tsx +35 -0
- package/src/components/sections/CardShowcase.tsx +159 -0
- package/src/components/sections/ChartShowcase.tsx +190 -0
- package/src/components/sections/CodeMockupShowcase.tsx +56 -0
- package/src/components/sections/ColorPalette.tsx +117 -0
- package/src/components/sections/CommandPaletteShowcase.tsx +48 -0
- package/src/components/sections/CountdownShowcase.tsx +43 -0
- package/src/components/sections/DashboardShowcase.tsx +191 -0
- package/src/components/sections/DiffShowcase.tsx +70 -0
- package/src/components/sections/DrawerShowcase.tsx +97 -0
- package/src/components/sections/DropdownShowcase.tsx +98 -0
- package/src/components/sections/EmptyStateShowcase.tsx +50 -0
- package/src/components/sections/FilterChipsShowcase.tsx +98 -0
- package/src/components/sections/FormShowcase.tsx +127 -0
- package/src/components/sections/HoverCardShowcase.tsx +50 -0
- package/src/components/sections/IconShowcase.tsx +127 -0
- package/src/components/sections/IndicatorShowcase.tsx +52 -0
- package/src/components/sections/KbdShowcase.tsx +57 -0
- package/src/components/sections/ModalShowcase.tsx +211 -0
- package/src/components/sections/NavigationShowcase.tsx +199 -0
- package/src/components/sections/ProductLayoutsShowcase.tsx +138 -0
- package/src/components/sections/ProgressShowcase.tsx +82 -0
- package/src/components/sections/SegmentedControlShowcase.tsx +49 -0
- package/src/components/sections/SetupThemeShowcase.tsx +262 -0
- package/src/components/sections/StackShowcase.tsx +33 -0
- package/src/components/sections/StatShowcase.tsx +129 -0
- package/src/components/sections/StepperShowcase.tsx +37 -0
- package/src/components/sections/SwapShowcase.tsx +99 -0
- package/src/components/sections/TabShowcase.tsx +84 -0
- package/src/components/sections/TableShowcase.tsx +140 -0
- package/src/components/sections/TimelineShowcase.tsx +83 -0
- package/src/components/sections/ToastShowcase.tsx +108 -0
- package/src/components/sections/TooltipShowcase.tsx +44 -0
- package/src/components/sections/UtilityShowcase.tsx +81 -0
- package/src/components/ui/Accordion.tsx +77 -0
- package/src/components/ui/Alert.tsx +77 -0
- package/src/components/ui/AuthLayout.tsx +58 -0
- package/src/components/ui/Avatar.tsx +97 -0
- package/src/components/ui/Badge.tsx +60 -0
- package/src/components/ui/Button.tsx +120 -0
- package/src/components/ui/ButtonChrome.tsx +20 -0
- package/src/components/ui/Calendar.tsx +115 -0
- package/src/components/ui/Card.tsx +70 -0
- package/src/components/ui/ChatBubble.tsx +71 -0
- package/src/components/ui/CodeBlock.tsx +48 -0
- package/src/components/ui/CollapsibleSection.tsx +49 -0
- package/src/components/ui/CommandPalette.tsx +137 -0
- package/src/components/ui/ComponentDocs.tsx +52 -0
- package/src/components/ui/Drawer.tsx +71 -0
- package/src/components/ui/DropdownMenu.tsx +262 -0
- package/src/components/ui/EmptyState.tsx +33 -0
- package/src/components/ui/FilterBar.tsx +165 -0
- package/src/components/ui/FilterChips.tsx +80 -0
- package/src/components/ui/FilterControls.tsx +30 -0
- package/src/components/ui/FormField.tsx +69 -0
- package/src/components/ui/HoverCard.tsx +36 -0
- package/src/components/ui/Indicator.tsx +61 -0
- package/src/components/ui/Input.tsx +385 -0
- package/src/components/ui/Kbd.tsx +113 -0
- package/src/components/ui/Loader.tsx +96 -0
- package/src/components/ui/Modal.tsx +105 -0
- package/src/components/ui/Navigation.tsx +94 -0
- package/src/components/ui/Panel.tsx +18 -0
- package/src/components/ui/Progress.tsx +59 -0
- package/src/components/ui/Rating.tsx +65 -0
- package/src/components/ui/SearchInput.tsx +106 -0
- package/src/components/ui/SegmentedControl.tsx +44 -0
- package/src/components/ui/SettingsLayout.tsx +94 -0
- package/src/components/ui/ShowcaseWrapper.tsx +124 -0
- package/src/components/ui/Stat.tsx +39 -0
- package/src/components/ui/Stepper.tsx +74 -0
- package/src/components/ui/Table.tsx +55 -0
- package/src/components/ui/Tabs.tsx +53 -0
- package/src/components/ui/Terminal.tsx +54 -0
- package/src/components/ui/ThemeDomSync.tsx +17 -0
- package/src/components/ui/ThemeManager.tsx +18 -0
- package/src/components/ui/ThemeSwitcher.tsx +46 -0
- package/src/components/ui/Timeline.tsx +60 -0
- package/src/components/ui/Toast.tsx +70 -0
- package/src/components/ui/Typography.tsx +129 -0
- package/src/components/ui/first-slice.test.tsx +98 -0
- package/src/components/ui/index.ts +151 -0
- package/src/components/ui/interaction-primitives.test.tsx +77 -0
- package/src/components/ui/kbd-icons.test.tsx +90 -0
- package/src/components/ui/product-patterns.test.tsx +77 -0
- package/src/styles/themes.css +528 -0
- package/tailwind-preset.ts +7 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { ComponentType, CSSProperties } from "react";
|
|
2
|
+
import {
|
|
3
|
+
CANONICAL_ICONS,
|
|
4
|
+
OLD_UI_ICONS,
|
|
5
|
+
IconAreaChart,
|
|
6
|
+
IconDatabase,
|
|
7
|
+
IconFlag,
|
|
8
|
+
IconFlask,
|
|
9
|
+
IconGridView,
|
|
10
|
+
IconRecording,
|
|
11
|
+
IconSurveys,
|
|
12
|
+
type CanonicalIconName,
|
|
13
|
+
type IconProps,
|
|
14
|
+
} from "@/components/icons";
|
|
15
|
+
import { Kbd, ShowcaseWrapper } from "@/components/ui";
|
|
16
|
+
|
|
17
|
+
const iconCells = Object.entries(CANONICAL_ICONS) as Array<[
|
|
18
|
+
CanonicalIconName,
|
|
19
|
+
ComponentType<IconProps>,
|
|
20
|
+
]>;
|
|
21
|
+
|
|
22
|
+
const originalIcons = Object.entries(OLD_UI_ICONS) as Array<[
|
|
23
|
+
keyof typeof OLD_UI_ICONS,
|
|
24
|
+
ComponentType<IconProps>,
|
|
25
|
+
]>;
|
|
26
|
+
|
|
27
|
+
const productTiles = [
|
|
28
|
+
{ label: "Session replay", Icon: IconRecording, color: "--ph-product-session-replay" },
|
|
29
|
+
{ label: "Product analytics", Icon: IconAreaChart, color: "--ph-product-product-analytics" },
|
|
30
|
+
{ label: "Data pipeline", Icon: IconGridView, color: "--ph-product-data-pipeline" },
|
|
31
|
+
{ label: "Feature flags", Icon: IconFlag, color: "--ph-product-feature-flags" },
|
|
32
|
+
{ label: "Experiments", Icon: IconFlask, color: "--ph-product-experiments" },
|
|
33
|
+
{ label: "Data warehouse", Icon: IconDatabase, color: "--ph-product-data-warehouse" },
|
|
34
|
+
{ label: "Surveys", Icon: IconSurveys, color: "--ph-product-surveys" },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
export default function IconShowcase() {
|
|
38
|
+
const code = `import {
|
|
39
|
+
IconCommandCursor,
|
|
40
|
+
IconDataReel,
|
|
41
|
+
IconInsightBoard,
|
|
42
|
+
IconOldWindow,
|
|
43
|
+
} from "@xenide-io/the-old-ui-theme";
|
|
44
|
+
|
|
45
|
+
<div className="flex items-center gap-4 text-ph-ink">
|
|
46
|
+
<IconOldWindow size={16} />
|
|
47
|
+
<IconCommandCursor size={20} />
|
|
48
|
+
<IconDataReel size={24} />
|
|
49
|
+
<IconInsightBoard size={24} aria-label="Insights" />
|
|
50
|
+
</div>`;
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<ShowcaseWrapper
|
|
54
|
+
title="Icons"
|
|
55
|
+
description="A canonical filled SVG registry with PostHog/Material foundations and clearly identified Old UI originals."
|
|
56
|
+
code={code}
|
|
57
|
+
filename="IconExample.tsx"
|
|
58
|
+
>
|
|
59
|
+
<div className="space-y-8">
|
|
60
|
+
<section className="ph-panel space-y-4">
|
|
61
|
+
<div>
|
|
62
|
+
<h3 className="text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Old UI originals</h3>
|
|
63
|
+
<p className="mt-2 max-w-3xl text-sm leading-relaxed text-ph-subtle">
|
|
64
|
+
Authored 24px glyphs for retro interface and analytics concepts. Each uses <Kbd variant="token">currentColor</Kbd>, a filled silhouette, and enough negative space to survive at 16px.
|
|
65
|
+
</p>
|
|
66
|
+
</div>
|
|
67
|
+
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4 lg:grid-cols-6">
|
|
68
|
+
{originalIcons.map(([name, Icon]) => (
|
|
69
|
+
<div key={name} className="flex flex-col items-center gap-3 rounded-lg border border-ph-border-subtle bg-ph-raised p-4 text-center">
|
|
70
|
+
<div className="flex h-9 items-center gap-2 text-ph-ink">
|
|
71
|
+
<Icon size={16} />
|
|
72
|
+
<Icon size={24} />
|
|
73
|
+
</div>
|
|
74
|
+
<span className="max-w-full break-words text-xs font-medium text-ph-subtle">{formatName(name)}</span>
|
|
75
|
+
</div>
|
|
76
|
+
))}
|
|
77
|
+
</div>
|
|
78
|
+
</section>
|
|
79
|
+
|
|
80
|
+
<section className="ph-panel space-y-4">
|
|
81
|
+
<div>
|
|
82
|
+
<h3 className="text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Canonical registry</h3>
|
|
83
|
+
<p className="mt-2 max-w-3xl text-sm leading-relaxed text-ph-subtle">
|
|
84
|
+
Documentation is generated from <Kbd variant="token">CANONICAL_ICONS</Kbd>. Compatibility aliases remain available through <Kbd variant="token">PH_ICONS</Kbd> without duplicating this inventory.
|
|
85
|
+
</p>
|
|
86
|
+
</div>
|
|
87
|
+
<div className="grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8">
|
|
88
|
+
{iconCells.map(([name, Icon]) => (
|
|
89
|
+
<div key={name} className="flex min-w-0 flex-col items-center gap-2 rounded-lg border border-ph-border-subtle bg-ph-raised p-3 text-center">
|
|
90
|
+
<div className="flex h-8 items-center gap-2 text-ph-ink">
|
|
91
|
+
<Icon size={16} />
|
|
92
|
+
<Icon size={24} />
|
|
93
|
+
</div>
|
|
94
|
+
<span className="max-w-full break-words text-[10px] font-medium tracking-wide text-ph-mutedtext">{name}</span>
|
|
95
|
+
</div>
|
|
96
|
+
))}
|
|
97
|
+
</div>
|
|
98
|
+
</section>
|
|
99
|
+
|
|
100
|
+
<section className="ph-panel space-y-4">
|
|
101
|
+
<div>
|
|
102
|
+
<h3 className="text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Product hues</h3>
|
|
103
|
+
<p className="mt-2 max-w-3xl text-sm leading-relaxed text-ph-subtle">
|
|
104
|
+
Product color is used as a subtle tint and icon accent instead of assuming white foregrounds on every theme.
|
|
105
|
+
</p>
|
|
106
|
+
</div>
|
|
107
|
+
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-7">
|
|
108
|
+
{productTiles.map(({ label, Icon, color }) => (
|
|
109
|
+
<div
|
|
110
|
+
key={label}
|
|
111
|
+
className="ph-icon-tile ph-product-icon-tile"
|
|
112
|
+
style={{ "--ph-icon-tile-color": `var(${color})` } as CSSProperties}
|
|
113
|
+
>
|
|
114
|
+
<Icon className="mb-1" size={28} />
|
|
115
|
+
<span className="max-w-full px-1 text-center normal-case tracking-normal">{label}</span>
|
|
116
|
+
</div>
|
|
117
|
+
))}
|
|
118
|
+
</div>
|
|
119
|
+
</section>
|
|
120
|
+
</div>
|
|
121
|
+
</ShowcaseWrapper>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function formatName(name: string) {
|
|
126
|
+
return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (letter) => letter.toUpperCase());
|
|
127
|
+
}
|
|
@@ -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,57 @@
|
|
|
1
|
+
import { ComponentDocs, Kbd, Panel, ShowcaseWrapper } from "@/components/ui";
|
|
2
|
+
|
|
3
|
+
export default function KbdShowcase() {
|
|
4
|
+
const code = `import { Kbd, Panel } from "@xenide-io/the-old-ui-theme";
|
|
5
|
+
|
|
6
|
+
<Panel className="space-y-5">
|
|
7
|
+
<div className="flex flex-wrap items-center gap-4">
|
|
8
|
+
<Kbd keys={["Command", "K"]} platform="mac" />
|
|
9
|
+
<Kbd keys={["Control", "K"]} platform="windows" />
|
|
10
|
+
<Kbd keys={["Control", "K"]} />
|
|
11
|
+
</div>
|
|
12
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
13
|
+
<Kbd variant="key">Escape</Kbd>
|
|
14
|
+
<Kbd variant="key">↵</Kbd>
|
|
15
|
+
<Kbd variant="token">HogQL</Kbd>
|
|
16
|
+
</div>
|
|
17
|
+
</Panel>`;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<ShowcaseWrapper
|
|
21
|
+
title="Keyboard glyphs"
|
|
22
|
+
description="PostHog-style joined shortcut caps with crisp lower borders, monospace type, and separate inline code tokens."
|
|
23
|
+
code={code}
|
|
24
|
+
filename="KbdExample.tsx"
|
|
25
|
+
docs={
|
|
26
|
+
<ComponentDocs
|
|
27
|
+
rows={[
|
|
28
|
+
{ name: "variant", type: "shortcut | key | token", defaultValue: "shortcut", description: "Chooses a shortcut group, single physical key, or inline code token." },
|
|
29
|
+
{ name: "keys", type: "readonly ReactNode[]", description: "Joins a shortcut chord inside one compact cap without stringifying React nodes." },
|
|
30
|
+
{ name: "platform", type: "text | mac | windows", defaultValue: "text", description: "Converts named modifier keys only when explicitly requested." },
|
|
31
|
+
{ name: "separator", type: "ReactNode", description: "Optional visual separator inside the joined shortcut cap." },
|
|
32
|
+
{ name: "aria-label", type: "string", description: "Optional spoken shortcut override; textual keys generate one automatically." },
|
|
33
|
+
]}
|
|
34
|
+
/>
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
<Panel className="space-y-5">
|
|
38
|
+
<div>
|
|
39
|
+
<h3 className="mb-3 text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Platform shortcuts</h3>
|
|
40
|
+
<div className="flex flex-wrap items-center gap-4">
|
|
41
|
+
<Kbd keys={["Command", "K"]} platform="mac" />
|
|
42
|
+
<Kbd keys={["Control", "K"]} platform="windows" />
|
|
43
|
+
<Kbd keys={["Control", "K"]} />
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
<div>
|
|
47
|
+
<h3 className="mb-3 text-xs font-semibold uppercase tracking-wider text-ph-mutedtext">Keys and tokens</h3>
|
|
48
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
49
|
+
<Kbd variant="key">Escape</Kbd>
|
|
50
|
+
<Kbd variant="key">↵</Kbd>
|
|
51
|
+
<Kbd variant="token">HogQL</Kbd>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</Panel>
|
|
55
|
+
</ShowcaseWrapper>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
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 { Button, IconCheck, IconClose, IconPlus, Input, Modal, Select, Textarea } from "@xenide-io/the-old-ui-theme";
|
|
13
|
+
|
|
14
|
+
<div className="ph-panel space-y-4">
|
|
15
|
+
<h3 className="text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Patterns</h3>
|
|
16
|
+
|
|
17
|
+
<div className="flex flex-wrap gap-3">
|
|
18
|
+
<Button variant="secondary" onClick={() => setOpenModal("info")}>
|
|
19
|
+
Info
|
|
20
|
+
</Button>
|
|
21
|
+
<Button variant="success" onClick={() => setOpenModal("success")}>
|
|
22
|
+
Success
|
|
23
|
+
</Button>
|
|
24
|
+
<Button variant="danger" onClick={() => setOpenModal("error")}>
|
|
25
|
+
Error
|
|
26
|
+
</Button>
|
|
27
|
+
<Button variant="primary" icon={<IconPlus className="h-4 w-4" aria-hidden />} onClick={() => setOpenModal("form")}>
|
|
28
|
+
Form modal
|
|
29
|
+
</Button>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<Modal
|
|
33
|
+
open={openModal === "info"}
|
|
34
|
+
onClose={close}
|
|
35
|
+
title="Configure capture"
|
|
36
|
+
description="Lightweight overlay + white sheet — Lemon modals skew toward tight copy and decisive buttons."
|
|
37
|
+
footer={<Button variant="secondary" onClick={close}>Close</Button>}
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
<Modal
|
|
41
|
+
open={openModal === "success"}
|
|
42
|
+
onClose={close}
|
|
43
|
+
showCloseButton={false}
|
|
44
|
+
footer={<Button variant="success" onClick={close}>Continue</Button>}
|
|
45
|
+
>
|
|
46
|
+
<div className="flex items-start gap-3">
|
|
47
|
+
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-[var(--ph-success-bg)] text-[var(--ph-success-text)]">
|
|
48
|
+
<IconCheck className="h-5 w-5" />
|
|
49
|
+
</div>
|
|
50
|
+
<div>
|
|
51
|
+
<h3 className="text-lg font-bold text-ph-success">Saved</h3>
|
|
52
|
+
<p className="mt-1 text-sm text-ph-subtle">Your dashboard layout synced to the team.</p>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</Modal>
|
|
56
|
+
|
|
57
|
+
<Modal
|
|
58
|
+
open={openModal === "error"}
|
|
59
|
+
onClose={close}
|
|
60
|
+
showCloseButton={false}
|
|
61
|
+
footer={
|
|
62
|
+
<>
|
|
63
|
+
<Button variant="ghost" onClick={close}>Cancel</Button>
|
|
64
|
+
<Button variant="danger" onClick={close}>View logs</Button>
|
|
65
|
+
</>
|
|
66
|
+
}
|
|
67
|
+
>
|
|
68
|
+
<div className="flex items-start gap-3">
|
|
69
|
+
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-[var(--ph-danger-bg)] text-[var(--ph-danger-text)]">
|
|
70
|
+
<IconClose className="h-5 w-5" />
|
|
71
|
+
</div>
|
|
72
|
+
<div>
|
|
73
|
+
<h3 className="text-lg font-bold text-ph-danger">Query failed</h3>
|
|
74
|
+
<p className="mt-1 text-sm text-ph-subtle">ClickHouse returned a timeout — retry or narrow the date range.</p>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</Modal>
|
|
78
|
+
|
|
79
|
+
<Modal
|
|
80
|
+
open={openModal === "form"}
|
|
81
|
+
onClose={close}
|
|
82
|
+
size="lg"
|
|
83
|
+
title="Create feature flag"
|
|
84
|
+
footer={
|
|
85
|
+
<>
|
|
86
|
+
<Button variant="ghost" onClick={close}>Cancel</Button>
|
|
87
|
+
<Button variant="primary" onClick={close}>Create</Button>
|
|
88
|
+
</>
|
|
89
|
+
}
|
|
90
|
+
>
|
|
91
|
+
<div className="space-y-4">
|
|
92
|
+
<Input label="Key" placeholder="billing-ui-v3" />
|
|
93
|
+
<Textarea label="Description" placeholder="Expose the rewritten billing funnel" className="h-28" />
|
|
94
|
+
<Select label="Rollout">
|
|
95
|
+
<option>10% staged</option>
|
|
96
|
+
<option>Everyone</option>
|
|
97
|
+
</Select>
|
|
98
|
+
</div>
|
|
99
|
+
</Modal>
|
|
100
|
+
</div>`;
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<ShowcaseWrapper
|
|
104
|
+
title="Modals"
|
|
105
|
+
description="Accessible modal shell with open state, title, description, size, close button, and footer props."
|
|
106
|
+
code={code}
|
|
107
|
+
filename="ModalExample.tsx"
|
|
108
|
+
docs={
|
|
109
|
+
<ComponentDocs
|
|
110
|
+
rows={[
|
|
111
|
+
{ name: "open", type: "boolean", defaultValue: "false", description: "Controls modal visibility." },
|
|
112
|
+
{ name: "onClose", type: "() => void", description: "Called by overlay and close button." },
|
|
113
|
+
{ name: "size", type: "sm | md | lg | xl | full", defaultValue: "md", description: "Controls panel max width." },
|
|
114
|
+
{ name: "title", type: "string", description: "Accessible dialog heading." },
|
|
115
|
+
{ name: "footer", type: "ReactNode", description: "Renders action row with consistent spacing." },
|
|
116
|
+
{ name: "closeOnOutsideClick", type: "boolean", defaultValue: "true", description: "Controls pointer dismissal outside the dialog." },
|
|
117
|
+
{ name: "closeOnEscape", type: "boolean", defaultValue: "true", description: "Controls Escape-key dismissal." },
|
|
118
|
+
]}
|
|
119
|
+
/>
|
|
120
|
+
}
|
|
121
|
+
>
|
|
122
|
+
<div className="ph-panel space-y-4">
|
|
123
|
+
<h3 className="text-sm font-semibold uppercase tracking-wider text-ph-mutedtext">Patterns</h3>
|
|
124
|
+
|
|
125
|
+
<div className="flex flex-wrap gap-3">
|
|
126
|
+
<Button variant="secondary" onClick={() => setOpenModal("info")}>
|
|
127
|
+
Info
|
|
128
|
+
</Button>
|
|
129
|
+
<Button variant="success" onClick={() => setOpenModal("success")}>
|
|
130
|
+
Success
|
|
131
|
+
</Button>
|
|
132
|
+
<Button variant="danger" onClick={() => setOpenModal("error")}>
|
|
133
|
+
Error
|
|
134
|
+
</Button>
|
|
135
|
+
<Button variant="primary" icon={<IconPlus className="h-4 w-4" aria-hidden />} onClick={() => setOpenModal("form")}>
|
|
136
|
+
Form modal
|
|
137
|
+
</Button>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<Modal
|
|
141
|
+
open={openModal === "info"}
|
|
142
|
+
onClose={close}
|
|
143
|
+
title="Configure capture"
|
|
144
|
+
description="Lightweight overlay + white sheet — Lemon modals skew toward tight copy and decisive buttons."
|
|
145
|
+
footer={<Button variant="secondary" onClick={close}>Close</Button>}
|
|
146
|
+
/>
|
|
147
|
+
|
|
148
|
+
<Modal
|
|
149
|
+
open={openModal === "success"}
|
|
150
|
+
onClose={close}
|
|
151
|
+
showCloseButton={false}
|
|
152
|
+
footer={<Button variant="success" onClick={close}>Continue</Button>}
|
|
153
|
+
>
|
|
154
|
+
<div className="flex items-start gap-3">
|
|
155
|
+
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-[var(--ph-success-bg)] text-[var(--ph-success-text)]">
|
|
156
|
+
<IconCheck className="h-5 w-5" />
|
|
157
|
+
</div>
|
|
158
|
+
<div>
|
|
159
|
+
<h3 className="text-lg font-bold text-ph-success">Saved</h3>
|
|
160
|
+
<p className="mt-1 text-sm text-ph-subtle">Your dashboard layout synced to the team.</p>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</Modal>
|
|
164
|
+
|
|
165
|
+
<Modal
|
|
166
|
+
open={openModal === "error"}
|
|
167
|
+
onClose={close}
|
|
168
|
+
showCloseButton={false}
|
|
169
|
+
footer={
|
|
170
|
+
<>
|
|
171
|
+
<Button variant="ghost" onClick={close}>Cancel</Button>
|
|
172
|
+
<Button variant="danger" onClick={close}>View logs</Button>
|
|
173
|
+
</>
|
|
174
|
+
}
|
|
175
|
+
>
|
|
176
|
+
<div className="flex items-start gap-3">
|
|
177
|
+
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-[var(--ph-danger-bg)] text-[var(--ph-danger-text)]">
|
|
178
|
+
<IconClose className="h-5 w-5" />
|
|
179
|
+
</div>
|
|
180
|
+
<div>
|
|
181
|
+
<h3 className="text-lg font-bold text-ph-danger">Query failed</h3>
|
|
182
|
+
<p className="mt-1 text-sm text-ph-subtle">ClickHouse returned a timeout — retry or narrow the date range.</p>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</Modal>
|
|
186
|
+
|
|
187
|
+
<Modal
|
|
188
|
+
open={openModal === "form"}
|
|
189
|
+
onClose={close}
|
|
190
|
+
size="lg"
|
|
191
|
+
title="Create feature flag"
|
|
192
|
+
footer={
|
|
193
|
+
<>
|
|
194
|
+
<Button variant="ghost" onClick={close}>Cancel</Button>
|
|
195
|
+
<Button variant="primary" onClick={close}>Create</Button>
|
|
196
|
+
</>
|
|
197
|
+
}
|
|
198
|
+
>
|
|
199
|
+
<div className="space-y-4">
|
|
200
|
+
<Input label="Key" placeholder="billing-ui-v3" />
|
|
201
|
+
<Textarea label="Description" placeholder="Expose the rewritten billing funnel" className="h-28" />
|
|
202
|
+
<Select label="Rollout">
|
|
203
|
+
<option>10% staged</option>
|
|
204
|
+
<option>Everyone</option>
|
|
205
|
+
</Select>
|
|
206
|
+
</div>
|
|
207
|
+
</Modal>
|
|
208
|
+
</div>
|
|
209
|
+
</ShowcaseWrapper>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
@@ -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
|
+
}
|