@orangecheck/ui 0.2.0 → 0.3.1
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 +4 -0
- package/dist/index.d.mts +53 -2
- package/dist/index.d.ts +53 -2
- package/dist/index.js +141 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +137 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @orangecheck/ui
|
|
2
2
|
|
|
3
|
+
> **Full reference:** [docs.ochk.io/sdk/ui](https://docs.ochk.io/sdk/ui) — auto-generated from the TypeScript source on every release.
|
|
4
|
+
> Hand-written prose below is the high-level overview; the docs site is the source of truth for every export, type, and signature.
|
|
5
|
+
|
|
6
|
+
|
|
3
7
|
OrangeCheck family-internal UI for the `.ochk.io` sub-sites.
|
|
4
8
|
|
|
5
9
|
This package is **not** for third-party integrators. For embeddable
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,61 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
2
3
|
|
|
3
|
-
type EcosystemSlug = 'home' | 'docs' | 'fleet' | 'attest' | 'lock' | 'vote' | 'stamp' | 'agent' | 'pledge';
|
|
4
|
+
type EcosystemSlug = 'home' | 'docs' | 'fleet' | 'me' | 'vault' | 'attest' | 'lock' | 'vote' | 'stamp' | 'agent' | 'pledge';
|
|
4
5
|
interface EcosystemSwitcherProps {
|
|
5
6
|
current: EcosystemSlug;
|
|
6
7
|
className?: string;
|
|
7
8
|
}
|
|
8
9
|
declare function EcosystemSwitcher({ current, className, }: EcosystemSwitcherProps): react_jsx_runtime.JSX.Element;
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
interface AppShellProps {
|
|
12
|
+
eyebrow?: ReactNode;
|
|
13
|
+
title?: ReactNode;
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
headerActions?: ReactNode;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
declare function AppShell({ eyebrow, title, description, headerActions, children, className, }: AppShellProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
interface SectionHeaderProps {
|
|
22
|
+
label: string;
|
|
23
|
+
meta?: ReactNode;
|
|
24
|
+
tone?: 'primary' | 'muted' | 'warning' | 'success' | 'destructive';
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
declare function SectionHeader({ label, meta, tone, className, }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
interface EmptyStateCta {
|
|
30
|
+
label: string;
|
|
31
|
+
href: string;
|
|
32
|
+
external?: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface EmptyStateProps {
|
|
35
|
+
label: string;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
cta?: EmptyStateCta;
|
|
38
|
+
secondary?: EmptyStateCta;
|
|
39
|
+
tone?: 'info' | 'warning' | 'muted';
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
declare function EmptyState({ label, children, cta, secondary, tone, className, }: EmptyStateProps): react_jsx_runtime.JSX.Element;
|
|
43
|
+
|
|
44
|
+
interface StatItem {
|
|
45
|
+
label: string;
|
|
46
|
+
value: string;
|
|
47
|
+
sub?: string;
|
|
48
|
+
accent?: boolean;
|
|
49
|
+
tone?: 'default' | 'primary' | 'success' | 'warning' | 'destructive' | 'muted';
|
|
50
|
+
}
|
|
51
|
+
interface StatGridProps {
|
|
52
|
+
items: StatItem[];
|
|
53
|
+
columns?: 1 | 2 | 3 | 4;
|
|
54
|
+
className?: string;
|
|
55
|
+
}
|
|
56
|
+
declare function StatGrid({ items, columns, className }: StatGridProps): react_jsx_runtime.JSX.Element;
|
|
57
|
+
declare function StatTile({ children, ...item }: StatItem & {
|
|
58
|
+
children?: ReactNode;
|
|
59
|
+
}): react_jsx_runtime.JSX.Element;
|
|
60
|
+
|
|
61
|
+
export { AppShell, type AppShellProps, type EcosystemSlug, EcosystemSwitcher, type EcosystemSwitcherProps, EmptyState, type EmptyStateCta, type EmptyStateProps, SectionHeader, type SectionHeaderProps, StatGrid, type StatGridProps, type StatItem, StatTile };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,61 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
2
3
|
|
|
3
|
-
type EcosystemSlug = 'home' | 'docs' | 'fleet' | 'attest' | 'lock' | 'vote' | 'stamp' | 'agent' | 'pledge';
|
|
4
|
+
type EcosystemSlug = 'home' | 'docs' | 'fleet' | 'me' | 'vault' | 'attest' | 'lock' | 'vote' | 'stamp' | 'agent' | 'pledge';
|
|
4
5
|
interface EcosystemSwitcherProps {
|
|
5
6
|
current: EcosystemSlug;
|
|
6
7
|
className?: string;
|
|
7
8
|
}
|
|
8
9
|
declare function EcosystemSwitcher({ current, className, }: EcosystemSwitcherProps): react_jsx_runtime.JSX.Element;
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
interface AppShellProps {
|
|
12
|
+
eyebrow?: ReactNode;
|
|
13
|
+
title?: ReactNode;
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
headerActions?: ReactNode;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
declare function AppShell({ eyebrow, title, description, headerActions, children, className, }: AppShellProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
interface SectionHeaderProps {
|
|
22
|
+
label: string;
|
|
23
|
+
meta?: ReactNode;
|
|
24
|
+
tone?: 'primary' | 'muted' | 'warning' | 'success' | 'destructive';
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
declare function SectionHeader({ label, meta, tone, className, }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
interface EmptyStateCta {
|
|
30
|
+
label: string;
|
|
31
|
+
href: string;
|
|
32
|
+
external?: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface EmptyStateProps {
|
|
35
|
+
label: string;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
cta?: EmptyStateCta;
|
|
38
|
+
secondary?: EmptyStateCta;
|
|
39
|
+
tone?: 'info' | 'warning' | 'muted';
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
declare function EmptyState({ label, children, cta, secondary, tone, className, }: EmptyStateProps): react_jsx_runtime.JSX.Element;
|
|
43
|
+
|
|
44
|
+
interface StatItem {
|
|
45
|
+
label: string;
|
|
46
|
+
value: string;
|
|
47
|
+
sub?: string;
|
|
48
|
+
accent?: boolean;
|
|
49
|
+
tone?: 'default' | 'primary' | 'success' | 'warning' | 'destructive' | 'muted';
|
|
50
|
+
}
|
|
51
|
+
interface StatGridProps {
|
|
52
|
+
items: StatItem[];
|
|
53
|
+
columns?: 1 | 2 | 3 | 4;
|
|
54
|
+
className?: string;
|
|
55
|
+
}
|
|
56
|
+
declare function StatGrid({ items, columns, className }: StatGridProps): react_jsx_runtime.JSX.Element;
|
|
57
|
+
declare function StatTile({ children, ...item }: StatItem & {
|
|
58
|
+
children?: ReactNode;
|
|
59
|
+
}): react_jsx_runtime.JSX.Element;
|
|
60
|
+
|
|
61
|
+
export { AppShell, type AppShellProps, type EcosystemSlug, EcosystemSwitcher, type EcosystemSwitcherProps, EmptyState, type EmptyStateCta, type EmptyStateProps, SectionHeader, type SectionHeaderProps, StatGrid, type StatGridProps, type StatItem, StatTile };
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,20 @@ var ENTRIES = [
|
|
|
32
32
|
sub: "managed \u2014 agent fleet",
|
|
33
33
|
docsHref: "https://docs.ochk.io/fleet"
|
|
34
34
|
},
|
|
35
|
+
{
|
|
36
|
+
slug: "me",
|
|
37
|
+
href: "https://me.ochk.io",
|
|
38
|
+
label: "oc\xB7me",
|
|
39
|
+
sub: "earn \u2014 consumer identity",
|
|
40
|
+
docsHref: "https://docs.ochk.io/me"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
slug: "vault",
|
|
44
|
+
href: "https://vault.ochk.io",
|
|
45
|
+
label: "oc\xB7vault",
|
|
46
|
+
sub: "keep \u2014 encrypted secrets",
|
|
47
|
+
docsHref: "https://docs.ochk.io/vault"
|
|
48
|
+
},
|
|
35
49
|
{
|
|
36
50
|
slug: "attest",
|
|
37
51
|
href: "https://attest.ochk.io",
|
|
@@ -164,7 +178,134 @@ function EcosystemSwitcher({
|
|
|
164
178
|
)
|
|
165
179
|
] });
|
|
166
180
|
}
|
|
181
|
+
function AppShell({
|
|
182
|
+
eyebrow,
|
|
183
|
+
title,
|
|
184
|
+
description,
|
|
185
|
+
headerActions,
|
|
186
|
+
children,
|
|
187
|
+
className
|
|
188
|
+
}) {
|
|
189
|
+
const hasHeader = Boolean(title);
|
|
190
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container " + (className ?? ""), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[calc(100vh-3rem)] flex-col", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 flex-col", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-6 md:pt-8", children: [
|
|
191
|
+
hasHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between", children: [
|
|
192
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-3xl", children: [
|
|
193
|
+
eyebrow && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-primary mb-3", children: eyebrow }),
|
|
194
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "font-display text-2xl font-bold tracking-tight sm:text-3xl", children: title }),
|
|
195
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mt-3 max-w-[64ch] text-sm leading-relaxed", children: description })
|
|
196
|
+
] }),
|
|
197
|
+
headerActions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: headerActions })
|
|
198
|
+
] }),
|
|
199
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: hasHeader ? "mt-8 pb-12" : "pb-12", children })
|
|
200
|
+
] }) }) }) });
|
|
201
|
+
}
|
|
202
|
+
var TONE_CLASS = {
|
|
203
|
+
primary: "text-primary",
|
|
204
|
+
muted: "text-muted-foreground",
|
|
205
|
+
warning: "text-warning",
|
|
206
|
+
success: "text-success",
|
|
207
|
+
destructive: "text-destructive"
|
|
208
|
+
};
|
|
209
|
+
function SectionHeader({
|
|
210
|
+
label,
|
|
211
|
+
meta,
|
|
212
|
+
tone = "primary",
|
|
213
|
+
className = ""
|
|
214
|
+
}) {
|
|
215
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `mb-3 flex items-baseline justify-between gap-2 ${className}`, children: [
|
|
216
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `label-mono ${TONE_CLASS[tone]}`, children: [
|
|
217
|
+
"\xA7 ",
|
|
218
|
+
label
|
|
219
|
+
] }) }),
|
|
220
|
+
meta && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/70 font-mono text-[10px] tracking-widest uppercase", children: meta })
|
|
221
|
+
] });
|
|
222
|
+
}
|
|
223
|
+
var TONE_CLASS2 = {
|
|
224
|
+
info: "border-primary/30 bg-primary/5",
|
|
225
|
+
warning: "border-warning/40 bg-warning/5",
|
|
226
|
+
muted: "border-border bg-muted/20"
|
|
227
|
+
};
|
|
228
|
+
var LABEL_TONE_CLASS = {
|
|
229
|
+
info: "text-primary",
|
|
230
|
+
warning: "text-warning",
|
|
231
|
+
muted: "text-muted-foreground"
|
|
232
|
+
};
|
|
233
|
+
function EmptyState({
|
|
234
|
+
label,
|
|
235
|
+
children,
|
|
236
|
+
cta,
|
|
237
|
+
secondary,
|
|
238
|
+
tone = "info",
|
|
239
|
+
className = ""
|
|
240
|
+
}) {
|
|
241
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `border p-5 md:p-6 ${TONE_CLASS2[tone]} ${className}`, children: [
|
|
242
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `label-mono mb-2 ${LABEL_TONE_CLASS[tone]}`, children: [
|
|
243
|
+
"\xA7 ",
|
|
244
|
+
label
|
|
245
|
+
] }),
|
|
246
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-foreground/85 max-w-2xl text-sm leading-relaxed", children }),
|
|
247
|
+
(cta || secondary) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex flex-wrap gap-3", children: [
|
|
248
|
+
cta && /* @__PURE__ */ jsxRuntime.jsx(CtaLink, { ...cta, variant: "primary" }),
|
|
249
|
+
secondary && /* @__PURE__ */ jsxRuntime.jsx(CtaLink, { ...secondary, variant: "secondary" })
|
|
250
|
+
] })
|
|
251
|
+
] });
|
|
252
|
+
}
|
|
253
|
+
function CtaLink({
|
|
254
|
+
label,
|
|
255
|
+
href,
|
|
256
|
+
external,
|
|
257
|
+
variant
|
|
258
|
+
}) {
|
|
259
|
+
const cls = variant === "primary" ? "bg-primary text-primary-foreground hover:bg-primary/90 inline-flex h-9 items-center justify-center rounded-md px-4 font-mono text-[11px] font-semibold tracking-widest uppercase" : "text-muted-foreground hover:text-foreground border-input hover:bg-accent inline-flex h-9 items-center justify-center rounded-md border px-4 font-mono text-[11px] tracking-widest uppercase";
|
|
260
|
+
const text = external ? `${label} \u2197` : label;
|
|
261
|
+
if (external) {
|
|
262
|
+
return /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noreferrer", className: cls, children: text });
|
|
263
|
+
}
|
|
264
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href, className: cls, children: text });
|
|
265
|
+
}
|
|
266
|
+
var TONE_CLASS3 = {
|
|
267
|
+
default: "",
|
|
268
|
+
primary: "text-primary",
|
|
269
|
+
success: "text-success",
|
|
270
|
+
warning: "text-warning",
|
|
271
|
+
destructive: "text-destructive",
|
|
272
|
+
muted: "text-muted-foreground"
|
|
273
|
+
};
|
|
274
|
+
var COL_CLASS = {
|
|
275
|
+
1: "",
|
|
276
|
+
2: "md:grid-cols-2",
|
|
277
|
+
3: "md:grid-cols-3",
|
|
278
|
+
4: "md:grid-cols-2 lg:grid-cols-4"
|
|
279
|
+
};
|
|
280
|
+
function StatGrid({ items, columns = 3, className = "" }) {
|
|
281
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `bg-border grid gap-px border ${COL_CLASS[columns]} ${className}`, children: items.map((it, i) => /* @__PURE__ */ jsxRuntime.jsx(Tile, { item: it }, `${it.label}-${i}`)) });
|
|
282
|
+
}
|
|
283
|
+
function Tile({ item }) {
|
|
284
|
+
const tone = item.tone ?? (item.accent ? "primary" : "default");
|
|
285
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-background p-5", children: [
|
|
286
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/80 font-mono text-[10px] tracking-widest uppercase", children: item.label }),
|
|
287
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
288
|
+
"div",
|
|
289
|
+
{
|
|
290
|
+
className: `font-display mt-1 text-2xl font-bold tabular-nums tracking-tight ${TONE_CLASS3[tone]}`,
|
|
291
|
+
children: item.value
|
|
292
|
+
}
|
|
293
|
+
),
|
|
294
|
+
item.sub && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/70 mt-1 font-mono text-[10px] tracking-widest uppercase", children: item.sub })
|
|
295
|
+
] });
|
|
296
|
+
}
|
|
297
|
+
function StatTile({ children, ...item }) {
|
|
298
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
299
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tile, { item }),
|
|
300
|
+
children
|
|
301
|
+
] });
|
|
302
|
+
}
|
|
167
303
|
|
|
304
|
+
exports.AppShell = AppShell;
|
|
168
305
|
exports.EcosystemSwitcher = EcosystemSwitcher;
|
|
306
|
+
exports.EmptyState = EmptyState;
|
|
307
|
+
exports.SectionHeader = SectionHeader;
|
|
308
|
+
exports.StatGrid = StatGrid;
|
|
309
|
+
exports.StatTile = StatTile;
|
|
169
310
|
//# sourceMappingURL=index.js.map
|
|
170
311
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ecosystem-switcher.tsx"],"names":["useState","useRef","useEffect","jsxs","jsx","Boxes","ChevronDown","Link","Check"],"mappings":"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","file":"index.js","sourcesContent":["import { Boxes, Check, ChevronDown } from 'lucide-react';\nimport Link from 'next/link';\nimport { useEffect, useRef, useState } from 'react';\n\n/**\n * EcosystemSwitcher — cross-product dropdown for jumping between every\n * site in the OrangeCheck family. Drop one into every site's LayoutHeader\n * and mark the active site via the `current` prop.\n *\n * <EcosystemSwitcher current=\"lock\" />\n *\n * The component is dependency-self-contained: no Radix, no Headless UI,\n * just outside-click + Escape handling so it works identically in every\n * site without forcing a peer-dep upgrade. Every link stays in-tab — the\n * family is one app from the user's POV.\n */\n\nexport type EcosystemSlug =\n | 'home'\n | 'docs'\n | 'fleet'\n | 'attest'\n | 'lock'\n | 'vote'\n | 'stamp'\n | 'agent'\n | 'pledge';\n\ninterface SwitcherEntry {\n slug: EcosystemSlug;\n href: string;\n label: string;\n sub: string;\n docsHref: string;\n}\n\nconst ENTRIES: SwitcherEntry[] = [\n {\n slug: 'home',\n href: 'https://ochk.io',\n label: 'orangecheck',\n sub: 'umbrella',\n docsHref: 'https://docs.ochk.io',\n },\n {\n slug: 'docs',\n href: 'https://docs.ochk.io',\n label: 'oc·docs',\n sub: 'unified docs',\n docsHref: 'https://docs.ochk.io',\n },\n {\n slug: 'fleet',\n href: 'https://fleet.ochk.io',\n label: 'oc·fleet',\n sub: 'managed — agent fleet',\n docsHref: 'https://docs.ochk.io/fleet',\n },\n {\n slug: 'attest',\n href: 'https://attest.ochk.io',\n label: 'oc·attest',\n sub: 'am — sybil resistance',\n docsHref: 'https://docs.ochk.io/attest',\n },\n {\n slug: 'lock',\n href: 'https://lock.ochk.io',\n label: 'oc·lock',\n sub: 'whisper — encryption',\n docsHref: 'https://docs.ochk.io/lock',\n },\n {\n slug: 'vote',\n href: 'https://vote.ochk.io',\n label: 'oc·vote',\n sub: 'decide — polls',\n docsHref: 'https://docs.ochk.io/vote',\n },\n {\n slug: 'stamp',\n href: 'https://stamp.ochk.io',\n label: 'oc·stamp',\n sub: 'declare — block-anchored',\n docsHref: 'https://docs.ochk.io/stamp',\n },\n {\n slug: 'agent',\n href: 'https://agent.ochk.io',\n label: 'oc·agent',\n sub: 'delegate — scoped auth',\n docsHref: 'https://docs.ochk.io/agent',\n },\n {\n slug: 'pledge',\n href: 'https://pledge.ochk.io',\n label: 'oc·pledge',\n sub: 'swear — bonded commitment',\n docsHref: 'https://docs.ochk.io/pledge',\n },\n];\n\nexport interface EcosystemSwitcherProps {\n current: EcosystemSlug;\n className?: string;\n}\n\nexport function EcosystemSwitcher({\n current,\n className,\n}: EcosystemSwitcherProps) {\n const [open, setOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n // Outside-click + Escape close.\n useEffect(() => {\n if (!open) return;\n function onDoc(e: MouseEvent) {\n if (!containerRef.current) return;\n if (!containerRef.current.contains(e.target as Node)) setOpen(false);\n }\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') setOpen(false);\n }\n document.addEventListener('mousedown', onDoc);\n document.addEventListener('keydown', onKey);\n return () => {\n document.removeEventListener('mousedown', onDoc);\n document.removeEventListener('keydown', onKey);\n };\n }, [open]);\n\n return (\n <div ref={containerRef} className={'relative ' + (className ?? '')}>\n <button\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-label=\"Switch OrangeCheck product\"\n title=\"Switch product\"\n onClick={() => setOpen((v) => !v)}\n className={\n 'inline-flex items-center gap-1 px-2 py-1 transition-colors ' +\n (open\n ? 'text-foreground'\n : 'text-muted-foreground hover:text-foreground')\n }\n >\n <Boxes className=\"h-4 w-4\" />\n <ChevronDown\n className={\n 'h-3.5 w-3.5 transition-transform ' + (open ? 'rotate-180' : '')\n }\n />\n </button>\n\n {open && (\n <div\n role=\"menu\"\n aria-label=\"Switch OrangeCheck product\"\n className=\"bg-background absolute right-0 top-full z-[60] mt-2 w-72 border shadow-lg\"\n >\n <div className=\"label-mono text-primary border-b px-4 py-2\">\n § the family\n </div>\n <ul className=\"py-1\">\n {ENTRIES.map((e) => {\n const isActive = e.slug === current;\n return (\n <li key={e.slug}>\n <Link\n href={e.href}\n onClick={() => setOpen(false)}\n aria-current={isActive ? 'page' : undefined}\n className={\n 'group flex items-baseline gap-3 px-4 py-2 transition-colors ' +\n (isActive\n ? 'bg-primary/5'\n : 'hover:bg-muted')\n }\n >\n <span\n className={\n 'font-display flex-1 text-[12px] font-semibold tracking-tight ' +\n (isActive\n ? 'text-primary'\n : 'text-foreground group-hover:text-primary transition-colors')\n }\n >\n {e.label}\n </span>\n <span className=\"text-muted-foreground font-mono text-[10px] tracking-wider uppercase\">\n {e.sub}\n </span>\n {isActive && (\n <Check className=\"text-primary h-3 w-3\" />\n )}\n </Link>\n </li>\n );\n })}\n </ul>\n <div className=\"border-t px-4 py-2 font-mono text-[10px] tracking-widest uppercase\">\n <Link\n href=\"https://docs.ochk.io\"\n onClick={() => setOpen(false)}\n className=\"text-muted-foreground hover:text-foreground inline-block transition-colors\"\n >\n docs.ochk.io →\n </Link>\n </div>\n </div>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/ecosystem-switcher.tsx","../src/app-shell.tsx","../src/section-header.tsx","../src/empty-state.tsx","../src/stat-grid.tsx"],"names":["useState","useRef","useEffect","jsxs","jsx","Boxes","ChevronDown","Link","Check","TONE_CLASS"],"mappings":"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","file":"index.js","sourcesContent":["import { Boxes, Check, ChevronDown } from 'lucide-react';\nimport Link from 'next/link';\nimport { useEffect, useRef, useState } from 'react';\n\n/**\n * EcosystemSwitcher — cross-product dropdown for jumping between every\n * site in the OrangeCheck family. Drop one into every site's LayoutHeader\n * and mark the active site via the `current` prop.\n *\n * <EcosystemSwitcher current=\"lock\" />\n *\n * The component is dependency-self-contained: no Radix, no Headless UI,\n * just outside-click + Escape handling so it works identically in every\n * site without forcing a peer-dep upgrade. Every link stays in-tab — the\n * family is one app from the user's POV.\n */\n\nexport type EcosystemSlug =\n | 'home'\n | 'docs'\n | 'fleet'\n | 'me'\n | 'vault'\n | 'attest'\n | 'lock'\n | 'vote'\n | 'stamp'\n | 'agent'\n | 'pledge';\n\ninterface SwitcherEntry {\n slug: EcosystemSlug;\n href: string;\n label: string;\n sub: string;\n docsHref: string;\n}\n\nconst ENTRIES: SwitcherEntry[] = [\n {\n slug: 'home',\n href: 'https://ochk.io',\n label: 'orangecheck',\n sub: 'umbrella',\n docsHref: 'https://docs.ochk.io',\n },\n {\n slug: 'docs',\n href: 'https://docs.ochk.io',\n label: 'oc·docs',\n sub: 'unified docs',\n docsHref: 'https://docs.ochk.io',\n },\n {\n slug: 'fleet',\n href: 'https://fleet.ochk.io',\n label: 'oc·fleet',\n sub: 'managed — agent fleet',\n docsHref: 'https://docs.ochk.io/fleet',\n },\n {\n slug: 'me',\n href: 'https://me.ochk.io',\n label: 'oc·me',\n sub: 'earn — consumer identity',\n docsHref: 'https://docs.ochk.io/me',\n },\n {\n slug: 'vault',\n href: 'https://vault.ochk.io',\n label: 'oc·vault',\n sub: 'keep — encrypted secrets',\n docsHref: 'https://docs.ochk.io/vault',\n },\n {\n slug: 'attest',\n href: 'https://attest.ochk.io',\n label: 'oc·attest',\n sub: 'am — sybil resistance',\n docsHref: 'https://docs.ochk.io/attest',\n },\n {\n slug: 'lock',\n href: 'https://lock.ochk.io',\n label: 'oc·lock',\n sub: 'whisper — encryption',\n docsHref: 'https://docs.ochk.io/lock',\n },\n {\n slug: 'vote',\n href: 'https://vote.ochk.io',\n label: 'oc·vote',\n sub: 'decide — polls',\n docsHref: 'https://docs.ochk.io/vote',\n },\n {\n slug: 'stamp',\n href: 'https://stamp.ochk.io',\n label: 'oc·stamp',\n sub: 'declare — block-anchored',\n docsHref: 'https://docs.ochk.io/stamp',\n },\n {\n slug: 'agent',\n href: 'https://agent.ochk.io',\n label: 'oc·agent',\n sub: 'delegate — scoped auth',\n docsHref: 'https://docs.ochk.io/agent',\n },\n {\n slug: 'pledge',\n href: 'https://pledge.ochk.io',\n label: 'oc·pledge',\n sub: 'swear — bonded commitment',\n docsHref: 'https://docs.ochk.io/pledge',\n },\n];\n\nexport interface EcosystemSwitcherProps {\n current: EcosystemSlug;\n className?: string;\n}\n\nexport function EcosystemSwitcher({\n current,\n className,\n}: EcosystemSwitcherProps) {\n const [open, setOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n // Outside-click + Escape close.\n useEffect(() => {\n if (!open) return;\n function onDoc(e: MouseEvent) {\n if (!containerRef.current) return;\n if (!containerRef.current.contains(e.target as Node)) setOpen(false);\n }\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') setOpen(false);\n }\n document.addEventListener('mousedown', onDoc);\n document.addEventListener('keydown', onKey);\n return () => {\n document.removeEventListener('mousedown', onDoc);\n document.removeEventListener('keydown', onKey);\n };\n }, [open]);\n\n return (\n <div ref={containerRef} className={'relative ' + (className ?? '')}>\n <button\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-label=\"Switch OrangeCheck product\"\n title=\"Switch product\"\n onClick={() => setOpen((v) => !v)}\n className={\n 'inline-flex items-center gap-1 px-2 py-1 transition-colors ' +\n (open\n ? 'text-foreground'\n : 'text-muted-foreground hover:text-foreground')\n }\n >\n <Boxes className=\"h-4 w-4\" />\n <ChevronDown\n className={\n 'h-3.5 w-3.5 transition-transform ' + (open ? 'rotate-180' : '')\n }\n />\n </button>\n\n {open && (\n <div\n role=\"menu\"\n aria-label=\"Switch OrangeCheck product\"\n className=\"bg-background absolute right-0 top-full z-[60] mt-2 w-72 border shadow-lg\"\n >\n <div className=\"label-mono text-primary border-b px-4 py-2\">\n § the family\n </div>\n <ul className=\"py-1\">\n {ENTRIES.map((e) => {\n const isActive = e.slug === current;\n return (\n <li key={e.slug}>\n <Link\n href={e.href}\n onClick={() => setOpen(false)}\n aria-current={isActive ? 'page' : undefined}\n className={\n 'group flex items-baseline gap-3 px-4 py-2 transition-colors ' +\n (isActive\n ? 'bg-primary/5'\n : 'hover:bg-muted')\n }\n >\n <span\n className={\n 'font-display flex-1 text-[12px] font-semibold tracking-tight ' +\n (isActive\n ? 'text-primary'\n : 'text-foreground group-hover:text-primary transition-colors')\n }\n >\n {e.label}\n </span>\n <span className=\"text-muted-foreground font-mono text-[10px] tracking-wider uppercase\">\n {e.sub}\n </span>\n {isActive && (\n <Check className=\"text-primary h-3 w-3\" />\n )}\n </Link>\n </li>\n );\n })}\n </ul>\n <div className=\"border-t px-4 py-2 font-mono text-[10px] tracking-widest uppercase\">\n <Link\n href=\"https://docs.ochk.io\"\n onClick={() => setOpen(false)}\n className=\"text-muted-foreground hover:text-foreground inline-block transition-colors\"\n >\n docs.ochk.io →\n </Link>\n </div>\n </div>\n )}\n </div>\n );\n}\n","import type { ReactNode } from 'react';\n\n/**\n * AppShell — shared page chrome for every authenticated dashboard surface\n * across the OC family (vault, me, fleet, future). Lifted from oc-me-web's\n * `MeShell` and oc-vault-web's `VaultShell` — same eyebrow / title /\n * description / actions header band, no sidebar (sidebars are app-specific\n * and stay in the consuming app).\n *\n * Usage:\n * <AppShell eyebrow=\"§ vault\" title=\"your vault.\" description=\"…\">\n * ...\n * </AppShell>\n *\n * The component is stateless and dependency-free. Tailwind classes assume\n * the consuming site loads the family `globals.css` (which defines\n * `.container`, `.label-mono`, the dark-by-default palette, etc.).\n */\n\nexport interface AppShellProps {\n eyebrow?: ReactNode;\n title?: ReactNode;\n description?: ReactNode;\n /** Right-aligned action node rendered next to the title (e.g. CTA buttons). */\n headerActions?: ReactNode;\n children: ReactNode;\n className?: string;\n}\n\nexport function AppShell({\n eyebrow,\n title,\n description,\n headerActions,\n children,\n className,\n}: AppShellProps) {\n const hasHeader = Boolean(title);\n return (\n <div className={'container ' + (className ?? '')}>\n <div className=\"flex min-h-[calc(100vh-3rem)] flex-col\">\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"pt-6 md:pt-8\">\n {hasHeader && (\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"max-w-3xl\">\n {eyebrow && (\n <div className=\"label-mono text-primary mb-3\">\n {eyebrow}\n </div>\n )}\n <h1 className=\"font-display text-2xl font-bold tracking-tight sm:text-3xl\">\n {title}\n </h1>\n {description && (\n <p className=\"text-muted-foreground mt-3 max-w-[64ch] text-sm leading-relaxed\">\n {description}\n </p>\n )}\n </div>\n {headerActions && (\n <div className=\"flex shrink-0 items-center gap-2\">\n {headerActions}\n </div>\n )}\n </div>\n )}\n <div className={hasHeader ? 'mt-8 pb-12' : 'pb-12'}>{children}</div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n","import type { ReactNode } from 'react';\n\nexport interface SectionHeaderProps {\n /** Plain section name — rendered after a \"§ \" glyph in label-mono. */\n label: string;\n /** Optional right-side string (count, \"most recent first\"). */\n meta?: ReactNode;\n tone?: 'primary' | 'muted' | 'warning' | 'success' | 'destructive';\n className?: string;\n}\n\nconst TONE_CLASS = {\n primary: 'text-primary',\n muted: 'text-muted-foreground',\n warning: 'text-warning',\n success: 'text-success',\n destructive: 'text-destructive',\n} as const;\n\n/**\n * SectionHeader — the canonical \"§ x\" section header used across every\n * /me, /vault, and /fleet dashboard surface. Lifted from oc-me-web's\n * `me/ui/SectionHeader` so the visual contract stays single-source.\n *\n * Pattern is `label-mono text-primary mb-3` with a \"§ \" glyph followed by\n * the label, plus an optional muted/uppercase right-side meta string.\n */\nexport function SectionHeader({\n label,\n meta,\n tone = 'primary',\n className = '',\n}: SectionHeaderProps) {\n return (\n <div className={`mb-3 flex items-baseline justify-between gap-2 ${className}`}>\n <div className=\"flex items-center gap-1.5\">\n <div className={`label-mono ${TONE_CLASS[tone]}`}>§ {label}</div>\n </div>\n {meta && (\n <span className=\"text-muted-foreground/70 font-mono text-[10px] tracking-widest uppercase\">\n {meta}\n </span>\n )}\n </div>\n );\n}\n","import Link from 'next/link';\nimport type { ReactNode } from 'react';\n\nexport interface EmptyStateCta {\n label: string;\n href: string;\n /** External links open in a new tab and get a ↗ glyph. */\n external?: boolean;\n}\n\nexport interface EmptyStateProps {\n /** Short heading — one mono-uppercased label like \"no entries yet\". */\n label: string;\n /** Body — short prose explaining what would appear here and how. */\n children: ReactNode;\n cta?: EmptyStateCta;\n secondary?: EmptyStateCta;\n tone?: 'info' | 'warning' | 'muted';\n className?: string;\n}\n\nconst TONE_CLASS = {\n info: 'border-primary/30 bg-primary/5',\n warning: 'border-warning/40 bg-warning/5',\n muted: 'border-border bg-muted/20',\n} as const;\n\nconst LABEL_TONE_CLASS = {\n info: 'text-primary',\n warning: 'text-warning',\n muted: 'text-muted-foreground',\n} as const;\n\n/**\n * EmptyState — the canonical empty-state card used across every /me,\n * /vault, and /fleet dashboard. Empty states should *teach*: explain what\n * would appear, and how to make it appear. Lifted from oc-me-web's\n * `me/ui/EmptyState`.\n */\nexport function EmptyState({\n label,\n children,\n cta,\n secondary,\n tone = 'info',\n className = '',\n}: EmptyStateProps) {\n return (\n <div className={`border p-5 md:p-6 ${TONE_CLASS[tone]} ${className}`}>\n <div className={`label-mono mb-2 ${LABEL_TONE_CLASS[tone]}`}>§ {label}</div>\n <div className=\"text-foreground/85 max-w-2xl text-sm leading-relaxed\">{children}</div>\n {(cta || secondary) && (\n <div className=\"mt-4 flex flex-wrap gap-3\">\n {cta && <CtaLink {...cta} variant=\"primary\" />}\n {secondary && <CtaLink {...secondary} variant=\"secondary\" />}\n </div>\n )}\n </div>\n );\n}\n\nfunction CtaLink({\n label,\n href,\n external,\n variant,\n}: EmptyStateCta & { variant: 'primary' | 'secondary' }) {\n const cls =\n variant === 'primary'\n ? 'bg-primary text-primary-foreground hover:bg-primary/90 inline-flex h-9 items-center justify-center rounded-md px-4 font-mono text-[11px] font-semibold tracking-widest uppercase'\n : 'text-muted-foreground hover:text-foreground border-input hover:bg-accent inline-flex h-9 items-center justify-center rounded-md border px-4 font-mono text-[11px] tracking-widest uppercase';\n const text = external ? `${label} ↗` : label;\n if (external) {\n return (\n <a href={href} target=\"_blank\" rel=\"noreferrer\" className={cls}>\n {text}\n </a>\n );\n }\n return (\n <Link href={href} className={cls}>\n {text}\n </Link>\n );\n}\n","import type { ReactNode } from 'react';\n\nexport interface StatItem {\n /** Short uppercased label rendered in mono. */\n label: string;\n /** Primary value · already formatted as a string. */\n value: string;\n /** Optional secondary line · USD conversion, \"last 30 days\", etc. */\n sub?: string;\n /** When true, value is rendered in primary tone (use for headline metric). */\n accent?: boolean;\n /** Optional tone for the value (overrides accent). */\n tone?: 'default' | 'primary' | 'success' | 'warning' | 'destructive' | 'muted';\n}\n\nexport interface StatGridProps {\n items: StatItem[];\n columns?: 1 | 2 | 3 | 4;\n className?: string;\n}\n\nconst TONE_CLASS = {\n default: '',\n primary: 'text-primary',\n success: 'text-success',\n warning: 'text-warning',\n destructive: 'text-destructive',\n muted: 'text-muted-foreground',\n} as const;\n\nconst COL_CLASS = {\n 1: '',\n 2: 'md:grid-cols-2',\n 3: 'md:grid-cols-3',\n 4: 'md:grid-cols-2 lg:grid-cols-4',\n} as const;\n\n/**\n * StatGrid — the canonical stats row used across family dashboards.\n * Lifted from oc-me-web's `me/ui/StatGrid`. Grid of equal-width tiles\n * separated by 1px borders. Always pre-format the value string —\n * the component does no number formatting.\n */\nexport function StatGrid({ items, columns = 3, className = '' }: StatGridProps) {\n return (\n <div className={`bg-border grid gap-px border ${COL_CLASS[columns]} ${className}`}>\n {items.map((it, i) => (\n <Tile key={`${it.label}-${i}`} item={it} />\n ))}\n </div>\n );\n}\n\nfunction Tile({ item }: { item: StatItem }) {\n const tone = item.tone ?? (item.accent ? 'primary' : 'default');\n return (\n <div className=\"bg-background p-5\">\n <div className=\"text-muted-foreground/80 font-mono text-[10px] tracking-widest uppercase\">\n {item.label}\n </div>\n <div\n className={`font-display mt-1 text-2xl font-bold tabular-nums tracking-tight ${TONE_CLASS[tone]}`}\n >\n {item.value}\n </div>\n {item.sub && (\n <div className=\"text-muted-foreground/70 mt-1 font-mono text-[10px] tracking-widest uppercase\">\n {item.sub}\n </div>\n )}\n </div>\n );\n}\n\nexport function StatTile({ children, ...item }: StatItem & { children?: ReactNode }) {\n return (\n <div>\n <Tile item={item} />\n {children}\n </div>\n );\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -26,6 +26,20 @@ var ENTRIES = [
|
|
|
26
26
|
sub: "managed \u2014 agent fleet",
|
|
27
27
|
docsHref: "https://docs.ochk.io/fleet"
|
|
28
28
|
},
|
|
29
|
+
{
|
|
30
|
+
slug: "me",
|
|
31
|
+
href: "https://me.ochk.io",
|
|
32
|
+
label: "oc\xB7me",
|
|
33
|
+
sub: "earn \u2014 consumer identity",
|
|
34
|
+
docsHref: "https://docs.ochk.io/me"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
slug: "vault",
|
|
38
|
+
href: "https://vault.ochk.io",
|
|
39
|
+
label: "oc\xB7vault",
|
|
40
|
+
sub: "keep \u2014 encrypted secrets",
|
|
41
|
+
docsHref: "https://docs.ochk.io/vault"
|
|
42
|
+
},
|
|
29
43
|
{
|
|
30
44
|
slug: "attest",
|
|
31
45
|
href: "https://attest.ochk.io",
|
|
@@ -158,7 +172,129 @@ function EcosystemSwitcher({
|
|
|
158
172
|
)
|
|
159
173
|
] });
|
|
160
174
|
}
|
|
175
|
+
function AppShell({
|
|
176
|
+
eyebrow,
|
|
177
|
+
title,
|
|
178
|
+
description,
|
|
179
|
+
headerActions,
|
|
180
|
+
children,
|
|
181
|
+
className
|
|
182
|
+
}) {
|
|
183
|
+
const hasHeader = Boolean(title);
|
|
184
|
+
return /* @__PURE__ */ jsx("div", { className: "container " + (className ?? ""), children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[calc(100vh-3rem)] flex-col", children: /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 flex-col", children: /* @__PURE__ */ jsxs("div", { className: "pt-6 md:pt-8", children: [
|
|
185
|
+
hasHeader && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between", children: [
|
|
186
|
+
/* @__PURE__ */ jsxs("div", { className: "max-w-3xl", children: [
|
|
187
|
+
eyebrow && /* @__PURE__ */ jsx("div", { className: "label-mono text-primary mb-3", children: eyebrow }),
|
|
188
|
+
/* @__PURE__ */ jsx("h1", { className: "font-display text-2xl font-bold tracking-tight sm:text-3xl", children: title }),
|
|
189
|
+
description && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mt-3 max-w-[64ch] text-sm leading-relaxed", children: description })
|
|
190
|
+
] }),
|
|
191
|
+
headerActions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children: headerActions })
|
|
192
|
+
] }),
|
|
193
|
+
/* @__PURE__ */ jsx("div", { className: hasHeader ? "mt-8 pb-12" : "pb-12", children })
|
|
194
|
+
] }) }) }) });
|
|
195
|
+
}
|
|
196
|
+
var TONE_CLASS = {
|
|
197
|
+
primary: "text-primary",
|
|
198
|
+
muted: "text-muted-foreground",
|
|
199
|
+
warning: "text-warning",
|
|
200
|
+
success: "text-success",
|
|
201
|
+
destructive: "text-destructive"
|
|
202
|
+
};
|
|
203
|
+
function SectionHeader({
|
|
204
|
+
label,
|
|
205
|
+
meta,
|
|
206
|
+
tone = "primary",
|
|
207
|
+
className = ""
|
|
208
|
+
}) {
|
|
209
|
+
return /* @__PURE__ */ jsxs("div", { className: `mb-3 flex items-baseline justify-between gap-2 ${className}`, children: [
|
|
210
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: /* @__PURE__ */ jsxs("div", { className: `label-mono ${TONE_CLASS[tone]}`, children: [
|
|
211
|
+
"\xA7 ",
|
|
212
|
+
label
|
|
213
|
+
] }) }),
|
|
214
|
+
meta && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 font-mono text-[10px] tracking-widest uppercase", children: meta })
|
|
215
|
+
] });
|
|
216
|
+
}
|
|
217
|
+
var TONE_CLASS2 = {
|
|
218
|
+
info: "border-primary/30 bg-primary/5",
|
|
219
|
+
warning: "border-warning/40 bg-warning/5",
|
|
220
|
+
muted: "border-border bg-muted/20"
|
|
221
|
+
};
|
|
222
|
+
var LABEL_TONE_CLASS = {
|
|
223
|
+
info: "text-primary",
|
|
224
|
+
warning: "text-warning",
|
|
225
|
+
muted: "text-muted-foreground"
|
|
226
|
+
};
|
|
227
|
+
function EmptyState({
|
|
228
|
+
label,
|
|
229
|
+
children,
|
|
230
|
+
cta,
|
|
231
|
+
secondary,
|
|
232
|
+
tone = "info",
|
|
233
|
+
className = ""
|
|
234
|
+
}) {
|
|
235
|
+
return /* @__PURE__ */ jsxs("div", { className: `border p-5 md:p-6 ${TONE_CLASS2[tone]} ${className}`, children: [
|
|
236
|
+
/* @__PURE__ */ jsxs("div", { className: `label-mono mb-2 ${LABEL_TONE_CLASS[tone]}`, children: [
|
|
237
|
+
"\xA7 ",
|
|
238
|
+
label
|
|
239
|
+
] }),
|
|
240
|
+
/* @__PURE__ */ jsx("div", { className: "text-foreground/85 max-w-2xl text-sm leading-relaxed", children }),
|
|
241
|
+
(cta || secondary) && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-wrap gap-3", children: [
|
|
242
|
+
cta && /* @__PURE__ */ jsx(CtaLink, { ...cta, variant: "primary" }),
|
|
243
|
+
secondary && /* @__PURE__ */ jsx(CtaLink, { ...secondary, variant: "secondary" })
|
|
244
|
+
] })
|
|
245
|
+
] });
|
|
246
|
+
}
|
|
247
|
+
function CtaLink({
|
|
248
|
+
label,
|
|
249
|
+
href,
|
|
250
|
+
external,
|
|
251
|
+
variant
|
|
252
|
+
}) {
|
|
253
|
+
const cls = variant === "primary" ? "bg-primary text-primary-foreground hover:bg-primary/90 inline-flex h-9 items-center justify-center rounded-md px-4 font-mono text-[11px] font-semibold tracking-widest uppercase" : "text-muted-foreground hover:text-foreground border-input hover:bg-accent inline-flex h-9 items-center justify-center rounded-md border px-4 font-mono text-[11px] tracking-widest uppercase";
|
|
254
|
+
const text = external ? `${label} \u2197` : label;
|
|
255
|
+
if (external) {
|
|
256
|
+
return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noreferrer", className: cls, children: text });
|
|
257
|
+
}
|
|
258
|
+
return /* @__PURE__ */ jsx(Link, { href, className: cls, children: text });
|
|
259
|
+
}
|
|
260
|
+
var TONE_CLASS3 = {
|
|
261
|
+
default: "",
|
|
262
|
+
primary: "text-primary",
|
|
263
|
+
success: "text-success",
|
|
264
|
+
warning: "text-warning",
|
|
265
|
+
destructive: "text-destructive",
|
|
266
|
+
muted: "text-muted-foreground"
|
|
267
|
+
};
|
|
268
|
+
var COL_CLASS = {
|
|
269
|
+
1: "",
|
|
270
|
+
2: "md:grid-cols-2",
|
|
271
|
+
3: "md:grid-cols-3",
|
|
272
|
+
4: "md:grid-cols-2 lg:grid-cols-4"
|
|
273
|
+
};
|
|
274
|
+
function StatGrid({ items, columns = 3, className = "" }) {
|
|
275
|
+
return /* @__PURE__ */ jsx("div", { className: `bg-border grid gap-px border ${COL_CLASS[columns]} ${className}`, children: items.map((it, i) => /* @__PURE__ */ jsx(Tile, { item: it }, `${it.label}-${i}`)) });
|
|
276
|
+
}
|
|
277
|
+
function Tile({ item }) {
|
|
278
|
+
const tone = item.tone ?? (item.accent ? "primary" : "default");
|
|
279
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-background p-5", children: [
|
|
280
|
+
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground/80 font-mono text-[10px] tracking-widest uppercase", children: item.label }),
|
|
281
|
+
/* @__PURE__ */ jsx(
|
|
282
|
+
"div",
|
|
283
|
+
{
|
|
284
|
+
className: `font-display mt-1 text-2xl font-bold tabular-nums tracking-tight ${TONE_CLASS3[tone]}`,
|
|
285
|
+
children: item.value
|
|
286
|
+
}
|
|
287
|
+
),
|
|
288
|
+
item.sub && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/70 mt-1 font-mono text-[10px] tracking-widest uppercase", children: item.sub })
|
|
289
|
+
] });
|
|
290
|
+
}
|
|
291
|
+
function StatTile({ children, ...item }) {
|
|
292
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
293
|
+
/* @__PURE__ */ jsx(Tile, { item }),
|
|
294
|
+
children
|
|
295
|
+
] });
|
|
296
|
+
}
|
|
161
297
|
|
|
162
|
-
export { EcosystemSwitcher };
|
|
298
|
+
export { AppShell, EcosystemSwitcher, EmptyState, SectionHeader, StatGrid, StatTile };
|
|
163
299
|
//# sourceMappingURL=index.mjs.map
|
|
164
300
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ecosystem-switcher.tsx"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { Boxes, Check, ChevronDown } from 'lucide-react';\nimport Link from 'next/link';\nimport { useEffect, useRef, useState } from 'react';\n\n/**\n * EcosystemSwitcher — cross-product dropdown for jumping between every\n * site in the OrangeCheck family. Drop one into every site's LayoutHeader\n * and mark the active site via the `current` prop.\n *\n * <EcosystemSwitcher current=\"lock\" />\n *\n * The component is dependency-self-contained: no Radix, no Headless UI,\n * just outside-click + Escape handling so it works identically in every\n * site without forcing a peer-dep upgrade. Every link stays in-tab — the\n * family is one app from the user's POV.\n */\n\nexport type EcosystemSlug =\n | 'home'\n | 'docs'\n | 'fleet'\n | 'attest'\n | 'lock'\n | 'vote'\n | 'stamp'\n | 'agent'\n | 'pledge';\n\ninterface SwitcherEntry {\n slug: EcosystemSlug;\n href: string;\n label: string;\n sub: string;\n docsHref: string;\n}\n\nconst ENTRIES: SwitcherEntry[] = [\n {\n slug: 'home',\n href: 'https://ochk.io',\n label: 'orangecheck',\n sub: 'umbrella',\n docsHref: 'https://docs.ochk.io',\n },\n {\n slug: 'docs',\n href: 'https://docs.ochk.io',\n label: 'oc·docs',\n sub: 'unified docs',\n docsHref: 'https://docs.ochk.io',\n },\n {\n slug: 'fleet',\n href: 'https://fleet.ochk.io',\n label: 'oc·fleet',\n sub: 'managed — agent fleet',\n docsHref: 'https://docs.ochk.io/fleet',\n },\n {\n slug: 'attest',\n href: 'https://attest.ochk.io',\n label: 'oc·attest',\n sub: 'am — sybil resistance',\n docsHref: 'https://docs.ochk.io/attest',\n },\n {\n slug: 'lock',\n href: 'https://lock.ochk.io',\n label: 'oc·lock',\n sub: 'whisper — encryption',\n docsHref: 'https://docs.ochk.io/lock',\n },\n {\n slug: 'vote',\n href: 'https://vote.ochk.io',\n label: 'oc·vote',\n sub: 'decide — polls',\n docsHref: 'https://docs.ochk.io/vote',\n },\n {\n slug: 'stamp',\n href: 'https://stamp.ochk.io',\n label: 'oc·stamp',\n sub: 'declare — block-anchored',\n docsHref: 'https://docs.ochk.io/stamp',\n },\n {\n slug: 'agent',\n href: 'https://agent.ochk.io',\n label: 'oc·agent',\n sub: 'delegate — scoped auth',\n docsHref: 'https://docs.ochk.io/agent',\n },\n {\n slug: 'pledge',\n href: 'https://pledge.ochk.io',\n label: 'oc·pledge',\n sub: 'swear — bonded commitment',\n docsHref: 'https://docs.ochk.io/pledge',\n },\n];\n\nexport interface EcosystemSwitcherProps {\n current: EcosystemSlug;\n className?: string;\n}\n\nexport function EcosystemSwitcher({\n current,\n className,\n}: EcosystemSwitcherProps) {\n const [open, setOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n // Outside-click + Escape close.\n useEffect(() => {\n if (!open) return;\n function onDoc(e: MouseEvent) {\n if (!containerRef.current) return;\n if (!containerRef.current.contains(e.target as Node)) setOpen(false);\n }\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') setOpen(false);\n }\n document.addEventListener('mousedown', onDoc);\n document.addEventListener('keydown', onKey);\n return () => {\n document.removeEventListener('mousedown', onDoc);\n document.removeEventListener('keydown', onKey);\n };\n }, [open]);\n\n return (\n <div ref={containerRef} className={'relative ' + (className ?? '')}>\n <button\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-label=\"Switch OrangeCheck product\"\n title=\"Switch product\"\n onClick={() => setOpen((v) => !v)}\n className={\n 'inline-flex items-center gap-1 px-2 py-1 transition-colors ' +\n (open\n ? 'text-foreground'\n : 'text-muted-foreground hover:text-foreground')\n }\n >\n <Boxes className=\"h-4 w-4\" />\n <ChevronDown\n className={\n 'h-3.5 w-3.5 transition-transform ' + (open ? 'rotate-180' : '')\n }\n />\n </button>\n\n {open && (\n <div\n role=\"menu\"\n aria-label=\"Switch OrangeCheck product\"\n className=\"bg-background absolute right-0 top-full z-[60] mt-2 w-72 border shadow-lg\"\n >\n <div className=\"label-mono text-primary border-b px-4 py-2\">\n § the family\n </div>\n <ul className=\"py-1\">\n {ENTRIES.map((e) => {\n const isActive = e.slug === current;\n return (\n <li key={e.slug}>\n <Link\n href={e.href}\n onClick={() => setOpen(false)}\n aria-current={isActive ? 'page' : undefined}\n className={\n 'group flex items-baseline gap-3 px-4 py-2 transition-colors ' +\n (isActive\n ? 'bg-primary/5'\n : 'hover:bg-muted')\n }\n >\n <span\n className={\n 'font-display flex-1 text-[12px] font-semibold tracking-tight ' +\n (isActive\n ? 'text-primary'\n : 'text-foreground group-hover:text-primary transition-colors')\n }\n >\n {e.label}\n </span>\n <span className=\"text-muted-foreground font-mono text-[10px] tracking-wider uppercase\">\n {e.sub}\n </span>\n {isActive && (\n <Check className=\"text-primary h-3 w-3\" />\n )}\n </Link>\n </li>\n );\n })}\n </ul>\n <div className=\"border-t px-4 py-2 font-mono text-[10px] tracking-widest uppercase\">\n <Link\n href=\"https://docs.ochk.io\"\n onClick={() => setOpen(false)}\n className=\"text-muted-foreground hover:text-foreground inline-block transition-colors\"\n >\n docs.ochk.io →\n </Link>\n </div>\n </div>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/ecosystem-switcher.tsx","../src/app-shell.tsx","../src/section-header.tsx","../src/empty-state.tsx","../src/stat-grid.tsx"],"names":["jsx","jsxs","TONE_CLASS","Link"],"mappings":";;;;;;AAsCA,IAAM,OAAA,GAA2B;AAAA,EAC7B;AAAA,IACI,IAAA,EAAM,MAAA;AAAA,IACN,IAAA,EAAM,iBAAA;AAAA,IACN,KAAA,EAAO,aAAA;AAAA,IACP,GAAA,EAAK,UAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,MAAA;AAAA,IACN,IAAA,EAAM,sBAAA;AAAA,IACN,KAAA,EAAO,YAAA;AAAA,IACP,GAAA,EAAK,cAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,OAAA;AAAA,IACN,IAAA,EAAM,uBAAA;AAAA,IACN,KAAA,EAAO,aAAA;AAAA,IACP,GAAA,EAAK,4BAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,IAAA;AAAA,IACN,IAAA,EAAM,oBAAA;AAAA,IACN,KAAA,EAAO,UAAA;AAAA,IACP,GAAA,EAAK,+BAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,OAAA;AAAA,IACN,IAAA,EAAM,uBAAA;AAAA,IACN,KAAA,EAAO,aAAA;AAAA,IACP,GAAA,EAAK,+BAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,QAAA;AAAA,IACN,IAAA,EAAM,wBAAA;AAAA,IACN,KAAA,EAAO,cAAA;AAAA,IACP,GAAA,EAAK,4BAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,MAAA;AAAA,IACN,IAAA,EAAM,sBAAA;AAAA,IACN,KAAA,EAAO,YAAA;AAAA,IACP,GAAA,EAAK,2BAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,MAAA;AAAA,IACN,IAAA,EAAM,sBAAA;AAAA,IACN,KAAA,EAAO,YAAA;AAAA,IACP,GAAA,EAAK,qBAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,OAAA;AAAA,IACN,IAAA,EAAM,uBAAA;AAAA,IACN,KAAA,EAAO,aAAA;AAAA,IACP,GAAA,EAAK,+BAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,OAAA;AAAA,IACN,IAAA,EAAM,uBAAA;AAAA,IACN,KAAA,EAAO,aAAA;AAAA,IACP,GAAA,EAAK,6BAAA;AAAA,IACL,QAAA,EAAU;AAAA,GACd;AAAA,EACA;AAAA,IACI,IAAA,EAAM,QAAA;AAAA,IACN,IAAA,EAAM,wBAAA;AAAA,IACN,KAAA,EAAO,cAAA;AAAA,IACP,GAAA,EAAK,gCAAA;AAAA,IACL,QAAA,EAAU;AAAA;AAElB,CAAA;AAOO,SAAS,iBAAA,CAAkB;AAAA,EAC9B,OAAA;AAAA,EACA;AACJ,CAAA,EAA2B;AACvB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,YAAA,GAAe,OAA8B,IAAI,CAAA;AAGvD,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,SAAS,MAAM,CAAA,EAAe;AAC1B,MAAA,IAAI,CAAC,aAAa,OAAA,EAAS;AAC3B,MAAA,IAAI,CAAC,aAAa,OAAA,CAAQ,QAAA,CAAS,EAAE,MAAc,CAAA,UAAW,KAAK,CAAA;AAAA,IACvE;AACA,IAAA,SAAS,MAAM,CAAA,EAAkB;AAC7B,MAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,QAAA,EAAU,OAAA,CAAQ,KAAK,CAAA;AAAA,IACzC;AACA,IAAA,QAAA,CAAS,gBAAA,CAAiB,aAAa,KAAK,CAAA;AAC5C,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,KAAK,CAAA;AAC1C,IAAA,OAAO,MAAM;AACT,MAAA,QAAA,CAAS,mBAAA,CAAoB,aAAa,KAAK,CAAA;AAC/C,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,KAAK,CAAA;AAAA,IACjD,CAAA;AAAA,EACJ,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,4BACK,KAAA,EAAA,EAAI,GAAA,EAAK,cAAc,SAAA,EAAW,WAAA,IAAe,aAAa,EAAA,CAAA,EAC3D,QAAA,EAAA;AAAA,oBAAA,IAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACG,IAAA,EAAK,QAAA;AAAA,QACL,eAAA,EAAc,MAAA;AAAA,QACd,eAAA,EAAe,IAAA;AAAA,QACf,YAAA,EAAW,4BAAA;AAAA,QACX,KAAA,EAAM,gBAAA;AAAA,QACN,SAAS,MAAM,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA;AAAA,QAChC,SAAA,EACI,6DAAA,IACC,IAAA,GACK,iBAAA,GACA,6CAAA,CAAA;AAAA,QAGV,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAM,WAAU,SAAA,EAAU,CAAA;AAAA,0BAC3B,GAAA;AAAA,YAAC,WAAA;AAAA,YAAA;AAAA,cACG,SAAA,EACI,mCAAA,IAAuC,IAAA,GAAO,YAAA,GAAe,EAAA;AAAA;AAAA;AAErE;AAAA;AAAA,KACJ;AAAA,IAEC,IAAA,oBACG,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACG,IAAA,EAAK,MAAA;AAAA,QACL,YAAA,EAAW,4BAAA;AAAA,QACX,SAAA,EAAU,2EAAA;AAAA,QAEV,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4CAAA,EAA6C,QAAA,EAAA,iBAAA,EAE5D,CAAA;AAAA,8BACC,IAAA,EAAA,EAAG,SAAA,EAAU,QACT,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM;AAChB,YAAA,MAAM,QAAA,GAAW,EAAE,IAAA,KAAS,OAAA;AAC5B,YAAA,2BACK,IAAA,EAAA,EACG,QAAA,kBAAA,IAAA;AAAA,cAAC,IAAA;AAAA,cAAA;AAAA,gBACG,MAAM,CAAA,CAAE,IAAA;AAAA,gBACR,OAAA,EAAS,MAAM,OAAA,CAAQ,KAAK,CAAA;AAAA,gBAC5B,cAAA,EAAc,WAAW,MAAA,GAAS,MAAA;AAAA,gBAClC,SAAA,EACI,8DAAA,IACC,QAAA,GACK,cAAA,GACA,gBAAA,CAAA;AAAA,gBAGV,QAAA,EAAA;AAAA,kCAAA,GAAA;AAAA,oBAAC,MAAA;AAAA,oBAAA;AAAA,sBACG,SAAA,EACI,+DAAA,IACC,QAAA,GACK,cAAA,GACA,4DAAA,CAAA;AAAA,sBAGT,QAAA,EAAA,CAAA,CAAE;AAAA;AAAA,mBACP;AAAA,kCACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,sEAAA,EACX,YAAE,GAAA,EACP,CAAA;AAAA,kBACC,QAAA,oBACG,GAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,sBAAA,EAAuB;AAAA;AAAA;AAAA,aAEhD,EAAA,EA5BK,EAAE,IA6BX,CAAA;AAAA,UAER,CAAC,CAAA,EACL,CAAA;AAAA,0BACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oEAAA,EACX,QAAA,kBAAA,GAAA;AAAA,YAAC,IAAA;AAAA,YAAA;AAAA,cACG,IAAA,EAAK,sBAAA;AAAA,cACL,OAAA,EAAS,MAAM,OAAA,CAAQ,KAAK,CAAA;AAAA,cAC5B,SAAA,EAAU,4EAAA;AAAA,cACb,QAAA,EAAA;AAAA;AAAA,WAED,EACJ;AAAA;AAAA;AAAA;AACJ,GAAA,EAER,CAAA;AAER;AC1MO,SAAS,QAAA,CAAS;AAAA,EACrB,OAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA;AACJ,CAAA,EAAkB;AACd,EAAA,MAAM,SAAA,GAAY,QAAQ,KAAK,CAAA;AAC/B,EAAA,uBACIA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAW,gBAAgB,SAAA,IAAa,EAAA,CAAA,EACzC,0BAAAA,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wCAAA,EACX,QAAA,kBAAAA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gCACX,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,cAAA,EACV,QAAA,EAAA;AAAA,IAAA,SAAA,oBACGA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mEAAA,EACX,QAAA,EAAA;AAAA,sBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACV,QAAA,EAAA;AAAA,QAAA,OAAA,oBACGD,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gCACV,QAAA,EAAA,OAAA,EACL,CAAA;AAAA,wBAEJA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,8DACT,QAAA,EAAA,KAAA,EACL,CAAA;AAAA,QACC,+BACGA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,mEACR,QAAA,EAAA,WAAA,EACL;AAAA,OAAA,EAER,CAAA;AAAA,MACC,iCACGA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oCACV,QAAA,EAAA,aAAA,EACL;AAAA,KAAA,EAER,CAAA;AAAA,oBAEJA,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAW,SAAA,GAAY,YAAA,GAAe,SAAU,QAAA,EAAS;AAAA,GAAA,EAClE,CAAA,EACJ,GACJ,CAAA,EACJ,CAAA;AAER;AC9DA,IAAM,UAAA,GAAa;AAAA,EACf,OAAA,EAAS,cAAA;AAAA,EACT,KAAA,EAAO,uBAAA;AAAA,EACP,OAAA,EAAS,cAAA;AAAA,EACT,OAAA,EAAS,cAAA;AAAA,EACT,WAAA,EAAa;AACjB,CAAA;AAUO,SAAS,aAAA,CAAc;AAAA,EAC1B,KAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA,GAAO,SAAA;AAAA,EACP,SAAA,GAAY;AAChB,CAAA,EAAuB;AACnB,EAAA,uBACIC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,+CAAA,EAAkD,SAAS,CAAA,CAAA,EACvE,QAAA,EAAA;AAAA,oBAAAD,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2BAAA,EACX,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,WAAA,EAAc,UAAA,CAAW,IAAI,CAAC,CAAA,CAAA,EAAI,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,MAAG;AAAA,KAAA,EAAM,CAAA,EAC/D,CAAA;AAAA,IACC,wBACGD,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4EACX,QAAA,EAAA,IAAA,EACL;AAAA,GAAA,EAER,CAAA;AAER;ACxBA,IAAME,WAAAA,GAAa;AAAA,EACf,IAAA,EAAM,gCAAA;AAAA,EACN,OAAA,EAAS,gCAAA;AAAA,EACT,KAAA,EAAO;AACX,CAAA;AAEA,IAAM,gBAAA,GAAmB;AAAA,EACrB,IAAA,EAAM,cAAA;AAAA,EACN,OAAA,EAAS,cAAA;AAAA,EACT,KAAA,EAAO;AACX,CAAA;AAQO,SAAS,UAAA,CAAW;AAAA,EACvB,KAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAA;AAAA,EACA,SAAA;AAAA,EACA,IAAA,GAAO,MAAA;AAAA,EACP,SAAA,GAAY;AAChB,CAAA,EAAoB;AAChB,EAAA,uBACID,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,kBAAA,EAAqBC,YAAW,IAAI,CAAC,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAC9D,QAAA,EAAA;AAAA,oBAAAD,KAAC,KAAA,EAAA,EAAI,SAAA,EAAW,mBAAmB,gBAAA,CAAiB,IAAI,CAAC,CAAA,CAAA,EAAI,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,MAAG;AAAA,KAAA,EAAM,CAAA;AAAA,oBACtED,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wDAAwD,QAAA,EAAS,CAAA;AAAA,IAAA,CAC9E,OAAO,SAAA,qBACLC,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,2BAAA,EACV,QAAA,EAAA;AAAA,MAAA,GAAA,oBAAOD,GAAAA,CAAC,OAAA,EAAA,EAAS,GAAG,GAAA,EAAK,SAAQ,SAAA,EAAU,CAAA;AAAA,MAC3C,6BAAaA,GAAAA,CAAC,WAAS,GAAG,SAAA,EAAW,SAAQ,WAAA,EAAY;AAAA,KAAA,EAC9D;AAAA,GAAA,EAER,CAAA;AAER;AAEA,SAAS,OAAA,CAAQ;AAAA,EACb,KAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA;AACJ,CAAA,EAAyD;AACrD,EAAA,MAAM,GAAA,GACF,OAAA,KAAY,SAAA,GACN,kLAAA,GACA,6LAAA;AACV,EAAA,MAAM,IAAA,GAAO,QAAA,GAAW,CAAA,EAAG,KAAK,CAAA,OAAA,CAAA,GAAO,KAAA;AACvC,EAAA,IAAI,QAAA,EAAU;AACV,IAAA,uBACIA,GAAAA,CAAC,GAAA,EAAA,EAAE,IAAA,EAAY,MAAA,EAAO,UAAS,GAAA,EAAI,YAAA,EAAa,SAAA,EAAW,GAAA,EACtD,QAAA,EAAA,IAAA,EACL,CAAA;AAAA,EAER;AACA,EAAA,uBACIA,GAAAA,CAACG,IAAAA,EAAA,EAAK,IAAA,EAAY,SAAA,EAAW,KACxB,QAAA,EAAA,IAAA,EACL,CAAA;AAER;AC/DA,IAAMD,WAAAA,GAAa;AAAA,EACf,OAAA,EAAS,EAAA;AAAA,EACT,OAAA,EAAS,cAAA;AAAA,EACT,OAAA,EAAS,cAAA;AAAA,EACT,OAAA,EAAS,cAAA;AAAA,EACT,WAAA,EAAa,kBAAA;AAAA,EACb,KAAA,EAAO;AACX,CAAA;AAEA,IAAM,SAAA,GAAY;AAAA,EACd,CAAA,EAAG,EAAA;AAAA,EACH,CAAA,EAAG,gBAAA;AAAA,EACH,CAAA,EAAG,gBAAA;AAAA,EACH,CAAA,EAAG;AACP,CAAA;AAQO,SAAS,SAAS,EAAE,KAAA,EAAO,UAAU,CAAA,EAAG,SAAA,GAAY,IAAG,EAAkB;AAC5E,EAAA,uBACIF,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,6BAAA,EAAgC,SAAA,CAAU,OAAO,CAAC,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAC1E,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,EAAA,EAAI,CAAA,qBACZA,GAAAA,CAAC,IAAA,EAAA,EAA8B,IAAA,EAAM,EAAA,EAAA,EAA1B,CAAA,EAAG,EAAA,CAAG,KAAK,CAAA,CAAA,EAAI,CAAC,CAAA,CAAc,CAC5C,CAAA,EACL,CAAA;AAER;AAEA,SAAS,IAAA,CAAK,EAAE,IAAA,EAAK,EAAuB;AACxC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,KAAS,IAAA,CAAK,SAAS,SAAA,GAAY,SAAA,CAAA;AACrD,EAAA,uBACIC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EACX,QAAA,EAAA;AAAA,oBAAAD,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0EAAA,EACV,eAAK,KAAA,EACV,CAAA;AAAA,oBACAA,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACG,SAAA,EAAW,CAAA,iEAAA,EAAoEE,WAAAA,CAAW,IAAI,CAAC,CAAA,CAAA;AAAA,QAE9F,QAAA,EAAA,IAAA,CAAK;AAAA;AAAA,KACV;AAAA,IACC,IAAA,CAAK,uBACFF,GAAAA,CAAC,SAAI,SAAA,EAAU,+EAAA,EACV,eAAK,GAAA,EACV;AAAA,GAAA,EAER,CAAA;AAER;AAEO,SAAS,QAAA,CAAS,EAAE,QAAA,EAAU,GAAG,MAAK,EAAwC;AACjF,EAAA,uBACIC,KAAC,KAAA,EAAA,EACG,QAAA,EAAA;AAAA,oBAAAD,GAAAA,CAAC,QAAK,IAAA,EAAY,CAAA;AAAA,IACjB;AAAA,GAAA,EACL,CAAA;AAER","file":"index.mjs","sourcesContent":["import { Boxes, Check, ChevronDown } from 'lucide-react';\nimport Link from 'next/link';\nimport { useEffect, useRef, useState } from 'react';\n\n/**\n * EcosystemSwitcher — cross-product dropdown for jumping between every\n * site in the OrangeCheck family. Drop one into every site's LayoutHeader\n * and mark the active site via the `current` prop.\n *\n * <EcosystemSwitcher current=\"lock\" />\n *\n * The component is dependency-self-contained: no Radix, no Headless UI,\n * just outside-click + Escape handling so it works identically in every\n * site without forcing a peer-dep upgrade. Every link stays in-tab — the\n * family is one app from the user's POV.\n */\n\nexport type EcosystemSlug =\n | 'home'\n | 'docs'\n | 'fleet'\n | 'me'\n | 'vault'\n | 'attest'\n | 'lock'\n | 'vote'\n | 'stamp'\n | 'agent'\n | 'pledge';\n\ninterface SwitcherEntry {\n slug: EcosystemSlug;\n href: string;\n label: string;\n sub: string;\n docsHref: string;\n}\n\nconst ENTRIES: SwitcherEntry[] = [\n {\n slug: 'home',\n href: 'https://ochk.io',\n label: 'orangecheck',\n sub: 'umbrella',\n docsHref: 'https://docs.ochk.io',\n },\n {\n slug: 'docs',\n href: 'https://docs.ochk.io',\n label: 'oc·docs',\n sub: 'unified docs',\n docsHref: 'https://docs.ochk.io',\n },\n {\n slug: 'fleet',\n href: 'https://fleet.ochk.io',\n label: 'oc·fleet',\n sub: 'managed — agent fleet',\n docsHref: 'https://docs.ochk.io/fleet',\n },\n {\n slug: 'me',\n href: 'https://me.ochk.io',\n label: 'oc·me',\n sub: 'earn — consumer identity',\n docsHref: 'https://docs.ochk.io/me',\n },\n {\n slug: 'vault',\n href: 'https://vault.ochk.io',\n label: 'oc·vault',\n sub: 'keep — encrypted secrets',\n docsHref: 'https://docs.ochk.io/vault',\n },\n {\n slug: 'attest',\n href: 'https://attest.ochk.io',\n label: 'oc·attest',\n sub: 'am — sybil resistance',\n docsHref: 'https://docs.ochk.io/attest',\n },\n {\n slug: 'lock',\n href: 'https://lock.ochk.io',\n label: 'oc·lock',\n sub: 'whisper — encryption',\n docsHref: 'https://docs.ochk.io/lock',\n },\n {\n slug: 'vote',\n href: 'https://vote.ochk.io',\n label: 'oc·vote',\n sub: 'decide — polls',\n docsHref: 'https://docs.ochk.io/vote',\n },\n {\n slug: 'stamp',\n href: 'https://stamp.ochk.io',\n label: 'oc·stamp',\n sub: 'declare — block-anchored',\n docsHref: 'https://docs.ochk.io/stamp',\n },\n {\n slug: 'agent',\n href: 'https://agent.ochk.io',\n label: 'oc·agent',\n sub: 'delegate — scoped auth',\n docsHref: 'https://docs.ochk.io/agent',\n },\n {\n slug: 'pledge',\n href: 'https://pledge.ochk.io',\n label: 'oc·pledge',\n sub: 'swear — bonded commitment',\n docsHref: 'https://docs.ochk.io/pledge',\n },\n];\n\nexport interface EcosystemSwitcherProps {\n current: EcosystemSlug;\n className?: string;\n}\n\nexport function EcosystemSwitcher({\n current,\n className,\n}: EcosystemSwitcherProps) {\n const [open, setOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n // Outside-click + Escape close.\n useEffect(() => {\n if (!open) return;\n function onDoc(e: MouseEvent) {\n if (!containerRef.current) return;\n if (!containerRef.current.contains(e.target as Node)) setOpen(false);\n }\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') setOpen(false);\n }\n document.addEventListener('mousedown', onDoc);\n document.addEventListener('keydown', onKey);\n return () => {\n document.removeEventListener('mousedown', onDoc);\n document.removeEventListener('keydown', onKey);\n };\n }, [open]);\n\n return (\n <div ref={containerRef} className={'relative ' + (className ?? '')}>\n <button\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-label=\"Switch OrangeCheck product\"\n title=\"Switch product\"\n onClick={() => setOpen((v) => !v)}\n className={\n 'inline-flex items-center gap-1 px-2 py-1 transition-colors ' +\n (open\n ? 'text-foreground'\n : 'text-muted-foreground hover:text-foreground')\n }\n >\n <Boxes className=\"h-4 w-4\" />\n <ChevronDown\n className={\n 'h-3.5 w-3.5 transition-transform ' + (open ? 'rotate-180' : '')\n }\n />\n </button>\n\n {open && (\n <div\n role=\"menu\"\n aria-label=\"Switch OrangeCheck product\"\n className=\"bg-background absolute right-0 top-full z-[60] mt-2 w-72 border shadow-lg\"\n >\n <div className=\"label-mono text-primary border-b px-4 py-2\">\n § the family\n </div>\n <ul className=\"py-1\">\n {ENTRIES.map((e) => {\n const isActive = e.slug === current;\n return (\n <li key={e.slug}>\n <Link\n href={e.href}\n onClick={() => setOpen(false)}\n aria-current={isActive ? 'page' : undefined}\n className={\n 'group flex items-baseline gap-3 px-4 py-2 transition-colors ' +\n (isActive\n ? 'bg-primary/5'\n : 'hover:bg-muted')\n }\n >\n <span\n className={\n 'font-display flex-1 text-[12px] font-semibold tracking-tight ' +\n (isActive\n ? 'text-primary'\n : 'text-foreground group-hover:text-primary transition-colors')\n }\n >\n {e.label}\n </span>\n <span className=\"text-muted-foreground font-mono text-[10px] tracking-wider uppercase\">\n {e.sub}\n </span>\n {isActive && (\n <Check className=\"text-primary h-3 w-3\" />\n )}\n </Link>\n </li>\n );\n })}\n </ul>\n <div className=\"border-t px-4 py-2 font-mono text-[10px] tracking-widest uppercase\">\n <Link\n href=\"https://docs.ochk.io\"\n onClick={() => setOpen(false)}\n className=\"text-muted-foreground hover:text-foreground inline-block transition-colors\"\n >\n docs.ochk.io →\n </Link>\n </div>\n </div>\n )}\n </div>\n );\n}\n","import type { ReactNode } from 'react';\n\n/**\n * AppShell — shared page chrome for every authenticated dashboard surface\n * across the OC family (vault, me, fleet, future). Lifted from oc-me-web's\n * `MeShell` and oc-vault-web's `VaultShell` — same eyebrow / title /\n * description / actions header band, no sidebar (sidebars are app-specific\n * and stay in the consuming app).\n *\n * Usage:\n * <AppShell eyebrow=\"§ vault\" title=\"your vault.\" description=\"…\">\n * ...\n * </AppShell>\n *\n * The component is stateless and dependency-free. Tailwind classes assume\n * the consuming site loads the family `globals.css` (which defines\n * `.container`, `.label-mono`, the dark-by-default palette, etc.).\n */\n\nexport interface AppShellProps {\n eyebrow?: ReactNode;\n title?: ReactNode;\n description?: ReactNode;\n /** Right-aligned action node rendered next to the title (e.g. CTA buttons). */\n headerActions?: ReactNode;\n children: ReactNode;\n className?: string;\n}\n\nexport function AppShell({\n eyebrow,\n title,\n description,\n headerActions,\n children,\n className,\n}: AppShellProps) {\n const hasHeader = Boolean(title);\n return (\n <div className={'container ' + (className ?? '')}>\n <div className=\"flex min-h-[calc(100vh-3rem)] flex-col\">\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"pt-6 md:pt-8\">\n {hasHeader && (\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"max-w-3xl\">\n {eyebrow && (\n <div className=\"label-mono text-primary mb-3\">\n {eyebrow}\n </div>\n )}\n <h1 className=\"font-display text-2xl font-bold tracking-tight sm:text-3xl\">\n {title}\n </h1>\n {description && (\n <p className=\"text-muted-foreground mt-3 max-w-[64ch] text-sm leading-relaxed\">\n {description}\n </p>\n )}\n </div>\n {headerActions && (\n <div className=\"flex shrink-0 items-center gap-2\">\n {headerActions}\n </div>\n )}\n </div>\n )}\n <div className={hasHeader ? 'mt-8 pb-12' : 'pb-12'}>{children}</div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n","import type { ReactNode } from 'react';\n\nexport interface SectionHeaderProps {\n /** Plain section name — rendered after a \"§ \" glyph in label-mono. */\n label: string;\n /** Optional right-side string (count, \"most recent first\"). */\n meta?: ReactNode;\n tone?: 'primary' | 'muted' | 'warning' | 'success' | 'destructive';\n className?: string;\n}\n\nconst TONE_CLASS = {\n primary: 'text-primary',\n muted: 'text-muted-foreground',\n warning: 'text-warning',\n success: 'text-success',\n destructive: 'text-destructive',\n} as const;\n\n/**\n * SectionHeader — the canonical \"§ x\" section header used across every\n * /me, /vault, and /fleet dashboard surface. Lifted from oc-me-web's\n * `me/ui/SectionHeader` so the visual contract stays single-source.\n *\n * Pattern is `label-mono text-primary mb-3` with a \"§ \" glyph followed by\n * the label, plus an optional muted/uppercase right-side meta string.\n */\nexport function SectionHeader({\n label,\n meta,\n tone = 'primary',\n className = '',\n}: SectionHeaderProps) {\n return (\n <div className={`mb-3 flex items-baseline justify-between gap-2 ${className}`}>\n <div className=\"flex items-center gap-1.5\">\n <div className={`label-mono ${TONE_CLASS[tone]}`}>§ {label}</div>\n </div>\n {meta && (\n <span className=\"text-muted-foreground/70 font-mono text-[10px] tracking-widest uppercase\">\n {meta}\n </span>\n )}\n </div>\n );\n}\n","import Link from 'next/link';\nimport type { ReactNode } from 'react';\n\nexport interface EmptyStateCta {\n label: string;\n href: string;\n /** External links open in a new tab and get a ↗ glyph. */\n external?: boolean;\n}\n\nexport interface EmptyStateProps {\n /** Short heading — one mono-uppercased label like \"no entries yet\". */\n label: string;\n /** Body — short prose explaining what would appear here and how. */\n children: ReactNode;\n cta?: EmptyStateCta;\n secondary?: EmptyStateCta;\n tone?: 'info' | 'warning' | 'muted';\n className?: string;\n}\n\nconst TONE_CLASS = {\n info: 'border-primary/30 bg-primary/5',\n warning: 'border-warning/40 bg-warning/5',\n muted: 'border-border bg-muted/20',\n} as const;\n\nconst LABEL_TONE_CLASS = {\n info: 'text-primary',\n warning: 'text-warning',\n muted: 'text-muted-foreground',\n} as const;\n\n/**\n * EmptyState — the canonical empty-state card used across every /me,\n * /vault, and /fleet dashboard. Empty states should *teach*: explain what\n * would appear, and how to make it appear. Lifted from oc-me-web's\n * `me/ui/EmptyState`.\n */\nexport function EmptyState({\n label,\n children,\n cta,\n secondary,\n tone = 'info',\n className = '',\n}: EmptyStateProps) {\n return (\n <div className={`border p-5 md:p-6 ${TONE_CLASS[tone]} ${className}`}>\n <div className={`label-mono mb-2 ${LABEL_TONE_CLASS[tone]}`}>§ {label}</div>\n <div className=\"text-foreground/85 max-w-2xl text-sm leading-relaxed\">{children}</div>\n {(cta || secondary) && (\n <div className=\"mt-4 flex flex-wrap gap-3\">\n {cta && <CtaLink {...cta} variant=\"primary\" />}\n {secondary && <CtaLink {...secondary} variant=\"secondary\" />}\n </div>\n )}\n </div>\n );\n}\n\nfunction CtaLink({\n label,\n href,\n external,\n variant,\n}: EmptyStateCta & { variant: 'primary' | 'secondary' }) {\n const cls =\n variant === 'primary'\n ? 'bg-primary text-primary-foreground hover:bg-primary/90 inline-flex h-9 items-center justify-center rounded-md px-4 font-mono text-[11px] font-semibold tracking-widest uppercase'\n : 'text-muted-foreground hover:text-foreground border-input hover:bg-accent inline-flex h-9 items-center justify-center rounded-md border px-4 font-mono text-[11px] tracking-widest uppercase';\n const text = external ? `${label} ↗` : label;\n if (external) {\n return (\n <a href={href} target=\"_blank\" rel=\"noreferrer\" className={cls}>\n {text}\n </a>\n );\n }\n return (\n <Link href={href} className={cls}>\n {text}\n </Link>\n );\n}\n","import type { ReactNode } from 'react';\n\nexport interface StatItem {\n /** Short uppercased label rendered in mono. */\n label: string;\n /** Primary value · already formatted as a string. */\n value: string;\n /** Optional secondary line · USD conversion, \"last 30 days\", etc. */\n sub?: string;\n /** When true, value is rendered in primary tone (use for headline metric). */\n accent?: boolean;\n /** Optional tone for the value (overrides accent). */\n tone?: 'default' | 'primary' | 'success' | 'warning' | 'destructive' | 'muted';\n}\n\nexport interface StatGridProps {\n items: StatItem[];\n columns?: 1 | 2 | 3 | 4;\n className?: string;\n}\n\nconst TONE_CLASS = {\n default: '',\n primary: 'text-primary',\n success: 'text-success',\n warning: 'text-warning',\n destructive: 'text-destructive',\n muted: 'text-muted-foreground',\n} as const;\n\nconst COL_CLASS = {\n 1: '',\n 2: 'md:grid-cols-2',\n 3: 'md:grid-cols-3',\n 4: 'md:grid-cols-2 lg:grid-cols-4',\n} as const;\n\n/**\n * StatGrid — the canonical stats row used across family dashboards.\n * Lifted from oc-me-web's `me/ui/StatGrid`. Grid of equal-width tiles\n * separated by 1px borders. Always pre-format the value string —\n * the component does no number formatting.\n */\nexport function StatGrid({ items, columns = 3, className = '' }: StatGridProps) {\n return (\n <div className={`bg-border grid gap-px border ${COL_CLASS[columns]} ${className}`}>\n {items.map((it, i) => (\n <Tile key={`${it.label}-${i}`} item={it} />\n ))}\n </div>\n );\n}\n\nfunction Tile({ item }: { item: StatItem }) {\n const tone = item.tone ?? (item.accent ? 'primary' : 'default');\n return (\n <div className=\"bg-background p-5\">\n <div className=\"text-muted-foreground/80 font-mono text-[10px] tracking-widest uppercase\">\n {item.label}\n </div>\n <div\n className={`font-display mt-1 text-2xl font-bold tabular-nums tracking-tight ${TONE_CLASS[tone]}`}\n >\n {item.value}\n </div>\n {item.sub && (\n <div className=\"text-muted-foreground/70 mt-1 font-mono text-[10px] tracking-widest uppercase\">\n {item.sub}\n </div>\n )}\n </div>\n );\n}\n\nexport function StatTile({ children, ...item }: StatItem & { children?: ReactNode }) {\n return (\n <div>\n <Tile item={item} />\n {children}\n </div>\n );\n}\n"]}
|
package/package.json
CHANGED