@orangecheck/app-design 0.1.2 → 0.2.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/dist/brand.d.mts +13 -2
- package/dist/brand.d.ts +13 -2
- package/dist/brand.js +79 -23
- package/dist/brand.js.map +1 -1
- package/dist/brand.mjs +79 -24
- package/dist/brand.mjs.map +1 -1
- package/dist/components.d.mts +12 -1
- package/dist/components.d.ts +12 -1
- package/dist/components.js +42 -0
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +42 -1
- package/dist/components.mjs.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +147 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +145 -24
- package/dist/index.mjs.map +1 -1
- package/dist/primitives.d.mts +4 -1
- package/dist/primitives.d.ts +4 -1
- package/dist/primitives.js +26 -0
- package/dist/primitives.js.map +1 -1
- package/dist/primitives.mjs +26 -1
- package/dist/primitives.mjs.map +1 -1
- package/package.json +1 -1
package/dist/brand.d.mts
CHANGED
|
@@ -23,7 +23,7 @@ interface LockupProps {
|
|
|
23
23
|
}
|
|
24
24
|
declare function Lockup({ name, size, className }: LockupProps): react.JSX.Element;
|
|
25
25
|
|
|
26
|
-
declare const SPHERE_GRADIENT = "radial-gradient(
|
|
26
|
+
declare const SPHERE_GRADIENT = "radial-gradient(86% 86% at 36% 32%, #fff7f0 0%, #ffdec8 14%, #ffa069 34%, #ff7030 56%, #f65210 78%, #de4006 100%)";
|
|
27
27
|
interface HalftoneSphereProps {
|
|
28
28
|
src: string;
|
|
29
29
|
alt: string;
|
|
@@ -43,4 +43,15 @@ interface IsoCheckProps {
|
|
|
43
43
|
}
|
|
44
44
|
declare function IsoCheck({ size, settle, shadow, title, className }: IsoCheckProps): react.JSX.Element;
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
interface CrowdProps {
|
|
47
|
+
cols?: number;
|
|
48
|
+
rows?: number;
|
|
49
|
+
real?: number;
|
|
50
|
+
seed?: number;
|
|
51
|
+
tone?: 'ink' | 'canvas';
|
|
52
|
+
label?: string;
|
|
53
|
+
className?: string;
|
|
54
|
+
}
|
|
55
|
+
declare function Crowd({ cols, rows, real, seed, tone, label, className, }: CrowdProps): react.JSX.Element;
|
|
56
|
+
|
|
57
|
+
export { AppIcon, type AppIconProps, Crowd, type CrowdProps, HalftoneSphere, type HalftoneSphereProps, IsoCheck, type IsoCheckProps, Lockup, type LockupProps, MARK_FACES, Mark, type MarkProps, SPHERE_GRADIENT };
|
package/dist/brand.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ interface LockupProps {
|
|
|
23
23
|
}
|
|
24
24
|
declare function Lockup({ name, size, className }: LockupProps): react.JSX.Element;
|
|
25
25
|
|
|
26
|
-
declare const SPHERE_GRADIENT = "radial-gradient(
|
|
26
|
+
declare const SPHERE_GRADIENT = "radial-gradient(86% 86% at 36% 32%, #fff7f0 0%, #ffdec8 14%, #ffa069 34%, #ff7030 56%, #f65210 78%, #de4006 100%)";
|
|
27
27
|
interface HalftoneSphereProps {
|
|
28
28
|
src: string;
|
|
29
29
|
alt: string;
|
|
@@ -43,4 +43,15 @@ interface IsoCheckProps {
|
|
|
43
43
|
}
|
|
44
44
|
declare function IsoCheck({ size, settle, shadow, title, className }: IsoCheckProps): react.JSX.Element;
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
interface CrowdProps {
|
|
47
|
+
cols?: number;
|
|
48
|
+
rows?: number;
|
|
49
|
+
real?: number;
|
|
50
|
+
seed?: number;
|
|
51
|
+
tone?: 'ink' | 'canvas';
|
|
52
|
+
label?: string;
|
|
53
|
+
className?: string;
|
|
54
|
+
}
|
|
55
|
+
declare function Crowd({ cols, rows, real, seed, tone, label, className, }: CrowdProps): react.JSX.Element;
|
|
56
|
+
|
|
57
|
+
export { AppIcon, type AppIconProps, Crowd, type CrowdProps, HalftoneSphere, type HalftoneSphereProps, IsoCheck, type IsoCheckProps, Lockup, type LockupProps, MARK_FACES, Mark, type MarkProps, SPHERE_GRADIENT };
|
package/dist/brand.js
CHANGED
|
@@ -93,30 +93,25 @@ function Lockup({ name = "orangecheck", size = 28, className }) {
|
|
|
93
93
|
}
|
|
94
94
|
);
|
|
95
95
|
}
|
|
96
|
-
var SPHERE_GRADIENT = "radial-gradient(
|
|
96
|
+
var SPHERE_GRADIENT = "radial-gradient(86% 86% at 36% 32%, #fff7f0 0%, #ffdec8 14%, #ffa069 34%, #ff7030 56%, #f65210 78%, #de4006 100%)";
|
|
97
|
+
var SPHERE_DEPTH = "inset -14px -22px 44px rgb(150 40 0 / 0.16), 0 36px 70px -34px rgb(234 88 11 / 0.45)";
|
|
98
|
+
function Ball({ src, alt, float }) {
|
|
99
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
100
|
+
"div",
|
|
101
|
+
{
|
|
102
|
+
className: cn("relative size-full overflow-hidden rounded-full", float && "oca-animate-float"),
|
|
103
|
+
style: { background: SPHERE_GRADIENT, boxShadow: SPHERE_DEPTH },
|
|
104
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt, className: "absolute inset-0 size-full select-none", draggable: false })
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
97
108
|
function HalftoneSphere({ src, alt, stadium = false, float = false, className, style }) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
105
|
-
"div",
|
|
106
|
-
{
|
|
107
|
-
"aria-hidden": true,
|
|
108
|
-
className: "oca-stadium pointer-events-none absolute inset-[-6%] rounded-full md:[inset:-12%_14%_0%_-26%] md:rounded-[17%]"
|
|
109
|
-
}
|
|
110
|
-
)
|
|
111
|
-
) : null,
|
|
112
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
113
|
-
"div",
|
|
114
|
-
{
|
|
115
|
-
className: cn("relative size-full overflow-hidden rounded-full", float && "oca-animate-float"),
|
|
116
|
-
style: { background: SPHERE_GRADIENT },
|
|
117
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt, className: "absolute inset-0 size-full select-none", draggable: false })
|
|
118
|
-
}
|
|
119
|
-
)
|
|
109
|
+
if (!stadium) {
|
|
110
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("relative aspect-square w-full", className), style, children: /* @__PURE__ */ jsxRuntime.jsx(Ball, { src, alt, float }) });
|
|
111
|
+
}
|
|
112
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative aspect-[1.255/1.127] w-full", className), style, children: [
|
|
113
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "oca-stadium pointer-events-none absolute left-0 top-0 h-full w-[88.4%] rounded-[32%]" }),
|
|
114
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 right-0 aspect-square w-[79.7%]", children: /* @__PURE__ */ jsxRuntime.jsx(Ball, { src, alt, float }) })
|
|
120
115
|
] });
|
|
121
116
|
}
|
|
122
117
|
function IsoCheck({ size = 360, settle = false, shadow = true, title, className }) {
|
|
@@ -132,8 +127,69 @@ function IsoCheck({ size = 360, settle = false, shadow = true, title, className
|
|
|
132
127
|
) : null
|
|
133
128
|
] });
|
|
134
129
|
}
|
|
130
|
+
var CELL_W = 22;
|
|
131
|
+
var CELL_H = 27;
|
|
132
|
+
function picks(count, total, seed) {
|
|
133
|
+
let s = seed >>> 0;
|
|
134
|
+
const out = /* @__PURE__ */ new Set();
|
|
135
|
+
while (out.size < Math.min(count, total)) {
|
|
136
|
+
s = Math.imul(s, 1664525) + 1013904223 >>> 0;
|
|
137
|
+
out.add(s % total);
|
|
138
|
+
}
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
function Crowd({
|
|
142
|
+
cols = 26,
|
|
143
|
+
rows = 9,
|
|
144
|
+
real = 7,
|
|
145
|
+
seed = 21,
|
|
146
|
+
tone = "ink",
|
|
147
|
+
label = "A crowd of identical accounts. Only a few are real.",
|
|
148
|
+
className
|
|
149
|
+
}) {
|
|
150
|
+
const width = cols * CELL_W;
|
|
151
|
+
const scales = Array.from({ length: rows }, (_, r) => 0.5 + 0.5 * (r / Math.max(1, rows - 1)));
|
|
152
|
+
const height = scales.reduce((h, s) => h + CELL_H * s, 0);
|
|
153
|
+
const nearFrom = Math.floor(rows / 2) * cols;
|
|
154
|
+
const realSet = new Set([...picks(real, rows * cols - nearFrom, seed)].map((i) => i + nearFrom));
|
|
155
|
+
const bot = tone === "ink" ? "#ffffff" : "#0a0a0a";
|
|
156
|
+
let y = 0;
|
|
157
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
158
|
+
"svg",
|
|
159
|
+
{
|
|
160
|
+
role: "img",
|
|
161
|
+
"aria-label": label,
|
|
162
|
+
viewBox: `0 0 ${width} ${Math.ceil(height)}`,
|
|
163
|
+
className: cn("block h-auto w-full", className),
|
|
164
|
+
children: scales.map((s, r) => {
|
|
165
|
+
const rowY = y;
|
|
166
|
+
y += CELL_H * s;
|
|
167
|
+
const rowW = cols * CELL_W * s;
|
|
168
|
+
const x0 = (width - rowW) / 2;
|
|
169
|
+
return Array.from({ length: cols }, (_, c) => {
|
|
170
|
+
const i = r * cols + c;
|
|
171
|
+
const isReal = realSet.has(i);
|
|
172
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
173
|
+
"g",
|
|
174
|
+
{
|
|
175
|
+
transform: `translate(${x0 + c * CELL_W * s} ${rowY}) scale(${s})`,
|
|
176
|
+
fill: isReal ? "var(--oca-orange)" : bot,
|
|
177
|
+
fillOpacity: isReal ? 1 : 0.1 + 0.16 * s,
|
|
178
|
+
children: [
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 11, cy: 8, r: 4.4 }),
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 25a8 8.5 0 0 1 16 0Z" })
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
i
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
}
|
|
135
190
|
|
|
136
191
|
exports.AppIcon = AppIcon;
|
|
192
|
+
exports.Crowd = Crowd;
|
|
137
193
|
exports.HalftoneSphere = HalftoneSphere;
|
|
138
194
|
exports.IsoCheck = IsoCheck;
|
|
139
195
|
exports.Lockup = Lockup;
|
package/dist/brand.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/cn.ts","../src/brand/mark.tsx","../src/brand/sphere.tsx","../src/brand/iso-check.tsx"],"names":["extendTailwindMerge","clsx","jsxs","jsx"],"mappings":"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","file":"brand.js","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n// tailwind-merge would treat `oca-display-1` and `text-foreground` as the same\n// group and drop one; teach it the package's own type utilities.\nconst merge = extendTailwindMerge<'oca-type'>({\n extend: {\n classGroups: {\n 'oca-type': [\n 'oca-display-1',\n 'oca-display-2',\n 'oca-display-3',\n 'oca-title',\n 'oca-title-sm',\n 'oca-eyebrow',\n 'oca-lead',\n 'oca-body',\n 'oca-numeral',\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]): string {\n return merge(clsx(inputs));\n}\n","import type { SVGProps } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The isometric check, measured from Sou's deck (slide 9) onto a 16×8 grid:\n * a chevron with a 3-unit short arm and a 5-unit long arm, one unit thick,\n * extruded two units. Three faces, three oranges.\n */\n\nconst TOP = '0,3 2,2 6,4 14,0 16,1 6,6';\nconst LEFT = '0,3 6,6 6,8 0,5';\nconst RIGHT = '6,6 16,1 16,3 6,8';\n\nexport const MARK_FACES = { top: '#FED8AB', left: '#FB933C', right: '#EA580B' } as const;\n\nexport interface MarkProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n /** Accessible name. Omit to render the mark as decoration. */\n title?: string;\n /** Rendered width in px; height follows the 2:1 grid. */\n size?: number;\n}\n\nexport function Mark({ title, size, className, ...rest }: MarkProps) {\n return (\n <svg\n viewBox=\"0 0 16 8\"\n width={size}\n height={size ? size / 2 : undefined}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </svg>\n );\n}\n\nexport interface AppIconProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n title?: string;\n size?: number;\n}\n\n/** The app icon: the mark on an ink squircle, as in the deck's lockup. */\nexport function AppIcon({ title, size = 32, className, ...rest }: AppIconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n width={size}\n height={size}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <rect\n width=\"24\"\n height=\"24\"\n rx=\"6.25\"\n style={{ fill: 'var(--oca-icon-tile, #0A0A0A)', stroke: 'var(--oca-icon-ring, transparent)' }}\n strokeWidth=\"0.5\"\n />\n <g transform=\"translate(4.25 8.1) scale(0.97)\">\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </g>\n </svg>\n );\n}\n\nexport interface LockupProps {\n /** The word beside the icon. */\n name?: string;\n /** Icon size in px; the word scales with it. */\n size?: number;\n className?: string;\n}\n\n/** Icon and wordmark, lowercase, as the deck sets it. */\nexport function Lockup({ name = 'orangecheck', size = 28, className }: LockupProps) {\n return (\n <span\n className={cn('inline-flex items-center font-medium tracking-[-0.01em]', className)}\n style={{ gap: size * 0.32, fontSize: size * 0.56 }}\n >\n <AppIcon size={size} />\n <span>{name}</span>\n </span>\n );\n}\n","import type { CSSProperties } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The deck's photograph: a halftone portrait on an orange sphere that glows\n * near-white behind the subject and saturates at the rim, with a hairline\n * stadium behind it. The dot layer is an image of black dots on transparent,\n * made by scripts/halftone.py from any photo, so the sphere stays CSS and the\n * dots stay crisp at any size.\n */\n\nexport const SPHERE_GRADIENT =\n 'radial-gradient(circle at 50% 42%, #fff8f3 0%, #ffe2d3 22%, #ffb48d 45%, #ff8a55 68%, #ff6a2c 100%)';\n\nexport interface HalftoneSphereProps {\n /** The dot layer (black dots on transparent, already circular). */\n src: string;\n /** Describe the person or subject; empty string marks it decorative. */\n alt: string;\n /** Draw the hairline stadium behind the sphere, as the hero does. */\n stadium?: boolean;\n /** Let the sphere drift a few pixels. Off under reduced motion. */\n float?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function HalftoneSphere({ src, alt, stadium = false, float = false, className, style }: HalftoneSphereProps) {\n return (\n <div className={cn('relative aspect-square w-full', className)} style={style}>\n {stadium ? (\n // Measured from the deck's title slide: a rounded square, its corners\n // 17% of the sphere, level with the sphere's foot, reaching left behind\n // the headline. On phones a ring inside the gutter, since the offset\n // would push the page sideways.\n <div\n aria-hidden\n className=\"oca-stadium pointer-events-none absolute inset-[-6%] rounded-full md:[inset:-12%_14%_0%_-26%] md:rounded-[17%]\"\n />\n ) : null}\n <div\n className={cn('relative size-full overflow-hidden rounded-full', float && 'oca-animate-float')}\n style={{ background: SPHERE_GRADIENT }}\n >\n {/* eslint-disable-next-line @next/next/no-img-element -- a static dot layer, sized by CSS */}\n <img src={src} alt={alt} className=\"absolute inset-0 size-full select-none\" draggable={false} />\n </div>\n </div>\n );\n}\n","import { cn } from '../lib/cn';\nimport { Mark } from './mark';\n\nexport interface IsoCheckProps {\n /** Width in px; the check keeps its 2:1 grid. */\n size?: number;\n /** Drop it into place on first paint, the deck's closing gesture. */\n settle?: boolean;\n /** A soft floor shadow, so it reads as an object on the canvas. */\n shadow?: boolean;\n title?: string;\n className?: string;\n}\n\n/** The isometric check as an object: the deck's closing illustration. */\nexport function IsoCheck({ size = 360, settle = false, shadow = true, title, className }: IsoCheckProps) {\n return (\n <div className={cn('relative inline-block', settle && 'oca-animate-settle', className)} style={{ width: size }}>\n <Mark size={size} title={title} className=\"relative z-10 block\" />\n {shadow ? (\n <div\n aria-hidden\n className=\"absolute left-[8%] right-[8%] rounded-[50%] opacity-60 blur-xl\"\n style={{ height: size * 0.08, bottom: -size * 0.04, background: 'rgb(234 88 11 / 0.18)' }}\n />\n ) : null}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/cn.ts","../src/brand/mark.tsx","../src/brand/sphere.tsx","../src/brand/iso-check.tsx","../src/brand/crowd.tsx"],"names":["extendTailwindMerge","clsx","jsxs","jsx"],"mappings":"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","file":"brand.js","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n// tailwind-merge would treat `oca-display-1` and `text-foreground` as the same\n// group and drop one; teach it the package's own type utilities.\nconst merge = extendTailwindMerge<'oca-type'>({\n extend: {\n classGroups: {\n 'oca-type': [\n 'oca-display-1',\n 'oca-display-2',\n 'oca-display-3',\n 'oca-title',\n 'oca-title-sm',\n 'oca-eyebrow',\n 'oca-lead',\n 'oca-body',\n 'oca-numeral',\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]): string {\n return merge(clsx(inputs));\n}\n","import type { SVGProps } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The isometric check, measured from Sou's deck (slide 9) onto a 16×8 grid:\n * a chevron with a 3-unit short arm and a 5-unit long arm, one unit thick,\n * extruded two units. Three faces, three oranges.\n */\n\nconst TOP = '0,3 2,2 6,4 14,0 16,1 6,6';\nconst LEFT = '0,3 6,6 6,8 0,5';\nconst RIGHT = '6,6 16,1 16,3 6,8';\n\nexport const MARK_FACES = { top: '#FED8AB', left: '#FB933C', right: '#EA580B' } as const;\n\nexport interface MarkProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n /** Accessible name. Omit to render the mark as decoration. */\n title?: string;\n /** Rendered width in px; height follows the 2:1 grid. */\n size?: number;\n}\n\nexport function Mark({ title, size, className, ...rest }: MarkProps) {\n return (\n <svg\n viewBox=\"0 0 16 8\"\n width={size}\n height={size ? size / 2 : undefined}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </svg>\n );\n}\n\nexport interface AppIconProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n title?: string;\n size?: number;\n}\n\n/** The app icon: the mark on an ink squircle, as in the deck's lockup. */\nexport function AppIcon({ title, size = 32, className, ...rest }: AppIconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n width={size}\n height={size}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <rect\n width=\"24\"\n height=\"24\"\n rx=\"6.25\"\n style={{ fill: 'var(--oca-icon-tile, #0A0A0A)', stroke: 'var(--oca-icon-ring, transparent)' }}\n strokeWidth=\"0.5\"\n />\n <g transform=\"translate(4.25 8.1) scale(0.97)\">\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </g>\n </svg>\n );\n}\n\nexport interface LockupProps {\n /** The word beside the icon. */\n name?: string;\n /** Icon size in px; the word scales with it. */\n size?: number;\n className?: string;\n}\n\n/** Icon and wordmark, lowercase, as the deck sets it. */\nexport function Lockup({ name = 'orangecheck', size = 28, className }: LockupProps) {\n return (\n <span\n className={cn('inline-flex items-center font-medium tracking-[-0.01em]', className)}\n style={{ gap: size * 0.32, fontSize: size * 0.56 }}\n >\n <AppIcon size={size} />\n <span>{name}</span>\n </span>\n );\n}\n","import type { CSSProperties } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The deck's photograph: a halftone portrait on an orange ball, lit from the\n * upper left, with a hairline stadium behind it. The dot layer is an image of\n * black dots on transparent, made by scripts/halftone.py, so the ball stays CSS\n * and the dots stay crisp at any size.\n */\n\nexport const SPHERE_GRADIENT =\n 'radial-gradient(86% 86% at 36% 32%, #fff7f0 0%, #ffdec8 14%, #ffa069 34%, #ff7030 56%, #f65210 78%, #de4006 100%)';\n\nconst SPHERE_DEPTH = 'inset -14px -22px 44px rgb(150 40 0 / 0.16), 0 36px 70px -34px rgb(234 88 11 / 0.45)';\n\nexport interface HalftoneSphereProps {\n /** The dot layer (black dots on transparent, already circular). */\n src: string;\n /** Describe the person or subject; empty string marks it decorative. */\n alt: string;\n /** Draw the hairline stadium behind the sphere, as the hero does. */\n stadium?: boolean;\n /** Let the sphere drift a few pixels. Off under reduced motion. */\n float?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction Ball({ src, alt, float }: { src: string; alt: string; float: boolean }) {\n return (\n <div\n className={cn('relative size-full overflow-hidden rounded-full', float && 'oca-animate-float')}\n style={{ background: SPHERE_GRADIENT, boxShadow: SPHERE_DEPTH }}\n >\n {/* eslint-disable-next-line @next/next/no-img-element -- a static dot layer, sized by CSS */}\n <img src={src} alt={alt} className=\"absolute inset-0 size-full select-none\" draggable={false} />\n </div>\n );\n}\n\nexport function HalftoneSphere({ src, alt, stadium = false, float = false, className, style }: HalftoneSphereProps) {\n if (!stadium) {\n return (\n <div className={cn('relative aspect-square w-full', className)} style={style}>\n <Ball src={src} alt={alt} float={float} />\n </div>\n );\n }\n // Measured from the deck's title slide against the ball's width S: the stadium\n // starts 0.255 S left of and 0.127 S above the ball, is 1.11 S wide, and ends\n // level with its foot. Both live inside this box, so nothing reaches the text.\n return (\n <div className={cn('relative aspect-[1.255/1.127] w-full', className)} style={style}>\n <div aria-hidden className=\"oca-stadium pointer-events-none absolute left-0 top-0 h-full w-[88.4%] rounded-[32%]\" />\n <div className=\"absolute bottom-0 right-0 aspect-square w-[79.7%]\">\n <Ball src={src} alt={alt} float={float} />\n </div>\n </div>\n );\n}\n","import { cn } from '../lib/cn';\nimport { Mark } from './mark';\n\nexport interface IsoCheckProps {\n /** Width in px; the check keeps its 2:1 grid. */\n size?: number;\n /** Drop it into place on first paint, the deck's closing gesture. */\n settle?: boolean;\n /** A soft floor shadow, so it reads as an object on the canvas. */\n shadow?: boolean;\n title?: string;\n className?: string;\n}\n\n/** The isometric check as an object: the deck's closing illustration. */\nexport function IsoCheck({ size = 360, settle = false, shadow = true, title, className }: IsoCheckProps) {\n return (\n <div className={cn('relative inline-block', settle && 'oca-animate-settle', className)} style={{ width: size }}>\n <Mark size={size} title={title} className=\"relative z-10 block\" />\n {shadow ? (\n <div\n aria-hidden\n className=\"absolute left-[8%] right-[8%] rounded-[50%] opacity-60 blur-xl\"\n style={{ height: size * 0.08, bottom: -size * 0.04, background: 'rgb(234 88 11 / 0.18)' }}\n />\n ) : null}\n </div>\n );\n}\n","import { cn } from '../lib/cn';\n\n/*\n * \"A bot farm can pretend to be a crowd\": a crowd of identical figures in\n * perspective, nearer rows larger, with a few real ones in orange. Identical on\n * purpose: copies are what a bot farm is. Positions come from a fixed seed so\n * server and client draw the same crowd.\n */\n\nexport interface CrowdProps {\n cols?: number;\n rows?: number;\n /** How many figures are real (orange). */\n real?: number;\n seed?: number;\n /** Ground it sits on: figures are light on ink, dark on canvas. */\n tone?: 'ink' | 'canvas';\n /** Spoken by screen readers. */\n label?: string;\n className?: string;\n}\n\nconst CELL_W = 22;\nconst CELL_H = 27;\n\nfunction picks(count: number, total: number, seed: number): Set<number> {\n let s = seed >>> 0;\n const out = new Set<number>();\n while (out.size < Math.min(count, total)) {\n s = (Math.imul(s, 1664525) + 1013904223) >>> 0;\n out.add(s % total);\n }\n return out;\n}\n\nexport function Crowd({\n cols = 26,\n rows = 9,\n real = 7,\n seed = 21,\n tone = 'ink',\n label = 'A crowd of identical accounts. Only a few are real.',\n className,\n}: CrowdProps) {\n const width = cols * CELL_W;\n const scales = Array.from({ length: rows }, (_, r) => 0.5 + 0.5 * (r / Math.max(1, rows - 1)));\n const height = scales.reduce((h, s) => h + CELL_H * s, 0);\n // Real figures only in the nearer half, where they are big enough to see.\n const nearFrom = Math.floor(rows / 2) * cols;\n const realSet = new Set([...picks(real, rows * cols - nearFrom, seed)].map((i) => i + nearFrom));\n const bot = tone === 'ink' ? '#ffffff' : '#0a0a0a';\n let y = 0;\n return (\n <svg\n role=\"img\"\n aria-label={label}\n viewBox={`0 0 ${width} ${Math.ceil(height)}`}\n className={cn('block h-auto w-full', className)}\n >\n {scales.map((s, r) => {\n const rowY = y;\n y += CELL_H * s;\n const rowW = cols * CELL_W * s;\n const x0 = (width - rowW) / 2;\n return Array.from({ length: cols }, (_, c) => {\n const i = r * cols + c;\n const isReal = realSet.has(i);\n return (\n <g\n key={i}\n transform={`translate(${x0 + c * CELL_W * s} ${rowY}) scale(${s})`}\n fill={isReal ? 'var(--oca-orange)' : bot}\n fillOpacity={isReal ? 1 : 0.1 + 0.16 * s}\n >\n <circle cx={11} cy={8} r={4.4} />\n <path d=\"M3 25a8 8.5 0 0 1 16 0Z\" />\n </g>\n );\n });\n })}\n </svg>\n );\n}\n"]}
|
package/dist/brand.mjs
CHANGED
|
@@ -91,30 +91,25 @@ function Lockup({ name = "orangecheck", size = 28, className }) {
|
|
|
91
91
|
}
|
|
92
92
|
);
|
|
93
93
|
}
|
|
94
|
-
var SPHERE_GRADIENT = "radial-gradient(
|
|
94
|
+
var SPHERE_GRADIENT = "radial-gradient(86% 86% at 36% 32%, #fff7f0 0%, #ffdec8 14%, #ffa069 34%, #ff7030 56%, #f65210 78%, #de4006 100%)";
|
|
95
|
+
var SPHERE_DEPTH = "inset -14px -22px 44px rgb(150 40 0 / 0.16), 0 36px 70px -34px rgb(234 88 11 / 0.45)";
|
|
96
|
+
function Ball({ src, alt, float }) {
|
|
97
|
+
return /* @__PURE__ */ jsx(
|
|
98
|
+
"div",
|
|
99
|
+
{
|
|
100
|
+
className: cn("relative size-full overflow-hidden rounded-full", float && "oca-animate-float"),
|
|
101
|
+
style: { background: SPHERE_GRADIENT, boxShadow: SPHERE_DEPTH },
|
|
102
|
+
children: /* @__PURE__ */ jsx("img", { src, alt, className: "absolute inset-0 size-full select-none", draggable: false })
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
}
|
|
95
106
|
function HalftoneSphere({ src, alt, stadium = false, float = false, className, style }) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
/* @__PURE__ */ jsx(
|
|
103
|
-
"div",
|
|
104
|
-
{
|
|
105
|
-
"aria-hidden": true,
|
|
106
|
-
className: "oca-stadium pointer-events-none absolute inset-[-6%] rounded-full md:[inset:-12%_14%_0%_-26%] md:rounded-[17%]"
|
|
107
|
-
}
|
|
108
|
-
)
|
|
109
|
-
) : null,
|
|
110
|
-
/* @__PURE__ */ jsx(
|
|
111
|
-
"div",
|
|
112
|
-
{
|
|
113
|
-
className: cn("relative size-full overflow-hidden rounded-full", float && "oca-animate-float"),
|
|
114
|
-
style: { background: SPHERE_GRADIENT },
|
|
115
|
-
children: /* @__PURE__ */ jsx("img", { src, alt, className: "absolute inset-0 size-full select-none", draggable: false })
|
|
116
|
-
}
|
|
117
|
-
)
|
|
107
|
+
if (!stadium) {
|
|
108
|
+
return /* @__PURE__ */ jsx("div", { className: cn("relative aspect-square w-full", className), style, children: /* @__PURE__ */ jsx(Ball, { src, alt, float }) });
|
|
109
|
+
}
|
|
110
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative aspect-[1.255/1.127] w-full", className), style, children: [
|
|
111
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "oca-stadium pointer-events-none absolute left-0 top-0 h-full w-[88.4%] rounded-[32%]" }),
|
|
112
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-0 right-0 aspect-square w-[79.7%]", children: /* @__PURE__ */ jsx(Ball, { src, alt, float }) })
|
|
118
113
|
] });
|
|
119
114
|
}
|
|
120
115
|
function IsoCheck({ size = 360, settle = false, shadow = true, title, className }) {
|
|
@@ -130,7 +125,67 @@ function IsoCheck({ size = 360, settle = false, shadow = true, title, className
|
|
|
130
125
|
) : null
|
|
131
126
|
] });
|
|
132
127
|
}
|
|
128
|
+
var CELL_W = 22;
|
|
129
|
+
var CELL_H = 27;
|
|
130
|
+
function picks(count, total, seed) {
|
|
131
|
+
let s = seed >>> 0;
|
|
132
|
+
const out = /* @__PURE__ */ new Set();
|
|
133
|
+
while (out.size < Math.min(count, total)) {
|
|
134
|
+
s = Math.imul(s, 1664525) + 1013904223 >>> 0;
|
|
135
|
+
out.add(s % total);
|
|
136
|
+
}
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
function Crowd({
|
|
140
|
+
cols = 26,
|
|
141
|
+
rows = 9,
|
|
142
|
+
real = 7,
|
|
143
|
+
seed = 21,
|
|
144
|
+
tone = "ink",
|
|
145
|
+
label = "A crowd of identical accounts. Only a few are real.",
|
|
146
|
+
className
|
|
147
|
+
}) {
|
|
148
|
+
const width = cols * CELL_W;
|
|
149
|
+
const scales = Array.from({ length: rows }, (_, r) => 0.5 + 0.5 * (r / Math.max(1, rows - 1)));
|
|
150
|
+
const height = scales.reduce((h, s) => h + CELL_H * s, 0);
|
|
151
|
+
const nearFrom = Math.floor(rows / 2) * cols;
|
|
152
|
+
const realSet = new Set([...picks(real, rows * cols - nearFrom, seed)].map((i) => i + nearFrom));
|
|
153
|
+
const bot = tone === "ink" ? "#ffffff" : "#0a0a0a";
|
|
154
|
+
let y = 0;
|
|
155
|
+
return /* @__PURE__ */ jsx(
|
|
156
|
+
"svg",
|
|
157
|
+
{
|
|
158
|
+
role: "img",
|
|
159
|
+
"aria-label": label,
|
|
160
|
+
viewBox: `0 0 ${width} ${Math.ceil(height)}`,
|
|
161
|
+
className: cn("block h-auto w-full", className),
|
|
162
|
+
children: scales.map((s, r) => {
|
|
163
|
+
const rowY = y;
|
|
164
|
+
y += CELL_H * s;
|
|
165
|
+
const rowW = cols * CELL_W * s;
|
|
166
|
+
const x0 = (width - rowW) / 2;
|
|
167
|
+
return Array.from({ length: cols }, (_, c) => {
|
|
168
|
+
const i = r * cols + c;
|
|
169
|
+
const isReal = realSet.has(i);
|
|
170
|
+
return /* @__PURE__ */ jsxs(
|
|
171
|
+
"g",
|
|
172
|
+
{
|
|
173
|
+
transform: `translate(${x0 + c * CELL_W * s} ${rowY}) scale(${s})`,
|
|
174
|
+
fill: isReal ? "var(--oca-orange)" : bot,
|
|
175
|
+
fillOpacity: isReal ? 1 : 0.1 + 0.16 * s,
|
|
176
|
+
children: [
|
|
177
|
+
/* @__PURE__ */ jsx("circle", { cx: 11, cy: 8, r: 4.4 }),
|
|
178
|
+
/* @__PURE__ */ jsx("path", { d: "M3 25a8 8.5 0 0 1 16 0Z" })
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
i
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
}
|
|
133
188
|
|
|
134
|
-
export { AppIcon, HalftoneSphere, IsoCheck, Lockup, MARK_FACES, Mark, SPHERE_GRADIENT };
|
|
189
|
+
export { AppIcon, Crowd, HalftoneSphere, IsoCheck, Lockup, MARK_FACES, Mark, SPHERE_GRADIENT };
|
|
135
190
|
//# sourceMappingURL=brand.mjs.map
|
|
136
191
|
//# sourceMappingURL=brand.mjs.map
|
package/dist/brand.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/cn.ts","../src/brand/mark.tsx","../src/brand/sphere.tsx","../src/brand/iso-check.tsx"],"names":["jsxs","jsx"],"mappings":"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","file":"brand.mjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n// tailwind-merge would treat `oca-display-1` and `text-foreground` as the same\n// group and drop one; teach it the package's own type utilities.\nconst merge = extendTailwindMerge<'oca-type'>({\n extend: {\n classGroups: {\n 'oca-type': [\n 'oca-display-1',\n 'oca-display-2',\n 'oca-display-3',\n 'oca-title',\n 'oca-title-sm',\n 'oca-eyebrow',\n 'oca-lead',\n 'oca-body',\n 'oca-numeral',\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]): string {\n return merge(clsx(inputs));\n}\n","import type { SVGProps } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The isometric check, measured from Sou's deck (slide 9) onto a 16×8 grid:\n * a chevron with a 3-unit short arm and a 5-unit long arm, one unit thick,\n * extruded two units. Three faces, three oranges.\n */\n\nconst TOP = '0,3 2,2 6,4 14,0 16,1 6,6';\nconst LEFT = '0,3 6,6 6,8 0,5';\nconst RIGHT = '6,6 16,1 16,3 6,8';\n\nexport const MARK_FACES = { top: '#FED8AB', left: '#FB933C', right: '#EA580B' } as const;\n\nexport interface MarkProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n /** Accessible name. Omit to render the mark as decoration. */\n title?: string;\n /** Rendered width in px; height follows the 2:1 grid. */\n size?: number;\n}\n\nexport function Mark({ title, size, className, ...rest }: MarkProps) {\n return (\n <svg\n viewBox=\"0 0 16 8\"\n width={size}\n height={size ? size / 2 : undefined}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </svg>\n );\n}\n\nexport interface AppIconProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n title?: string;\n size?: number;\n}\n\n/** The app icon: the mark on an ink squircle, as in the deck's lockup. */\nexport function AppIcon({ title, size = 32, className, ...rest }: AppIconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n width={size}\n height={size}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <rect\n width=\"24\"\n height=\"24\"\n rx=\"6.25\"\n style={{ fill: 'var(--oca-icon-tile, #0A0A0A)', stroke: 'var(--oca-icon-ring, transparent)' }}\n strokeWidth=\"0.5\"\n />\n <g transform=\"translate(4.25 8.1) scale(0.97)\">\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </g>\n </svg>\n );\n}\n\nexport interface LockupProps {\n /** The word beside the icon. */\n name?: string;\n /** Icon size in px; the word scales with it. */\n size?: number;\n className?: string;\n}\n\n/** Icon and wordmark, lowercase, as the deck sets it. */\nexport function Lockup({ name = 'orangecheck', size = 28, className }: LockupProps) {\n return (\n <span\n className={cn('inline-flex items-center font-medium tracking-[-0.01em]', className)}\n style={{ gap: size * 0.32, fontSize: size * 0.56 }}\n >\n <AppIcon size={size} />\n <span>{name}</span>\n </span>\n );\n}\n","import type { CSSProperties } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The deck's photograph: a halftone portrait on an orange sphere that glows\n * near-white behind the subject and saturates at the rim, with a hairline\n * stadium behind it. The dot layer is an image of black dots on transparent,\n * made by scripts/halftone.py from any photo, so the sphere stays CSS and the\n * dots stay crisp at any size.\n */\n\nexport const SPHERE_GRADIENT =\n 'radial-gradient(circle at 50% 42%, #fff8f3 0%, #ffe2d3 22%, #ffb48d 45%, #ff8a55 68%, #ff6a2c 100%)';\n\nexport interface HalftoneSphereProps {\n /** The dot layer (black dots on transparent, already circular). */\n src: string;\n /** Describe the person or subject; empty string marks it decorative. */\n alt: string;\n /** Draw the hairline stadium behind the sphere, as the hero does. */\n stadium?: boolean;\n /** Let the sphere drift a few pixels. Off under reduced motion. */\n float?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function HalftoneSphere({ src, alt, stadium = false, float = false, className, style }: HalftoneSphereProps) {\n return (\n <div className={cn('relative aspect-square w-full', className)} style={style}>\n {stadium ? (\n // Measured from the deck's title slide: a rounded square, its corners\n // 17% of the sphere, level with the sphere's foot, reaching left behind\n // the headline. On phones a ring inside the gutter, since the offset\n // would push the page sideways.\n <div\n aria-hidden\n className=\"oca-stadium pointer-events-none absolute inset-[-6%] rounded-full md:[inset:-12%_14%_0%_-26%] md:rounded-[17%]\"\n />\n ) : null}\n <div\n className={cn('relative size-full overflow-hidden rounded-full', float && 'oca-animate-float')}\n style={{ background: SPHERE_GRADIENT }}\n >\n {/* eslint-disable-next-line @next/next/no-img-element -- a static dot layer, sized by CSS */}\n <img src={src} alt={alt} className=\"absolute inset-0 size-full select-none\" draggable={false} />\n </div>\n </div>\n );\n}\n","import { cn } from '../lib/cn';\nimport { Mark } from './mark';\n\nexport interface IsoCheckProps {\n /** Width in px; the check keeps its 2:1 grid. */\n size?: number;\n /** Drop it into place on first paint, the deck's closing gesture. */\n settle?: boolean;\n /** A soft floor shadow, so it reads as an object on the canvas. */\n shadow?: boolean;\n title?: string;\n className?: string;\n}\n\n/** The isometric check as an object: the deck's closing illustration. */\nexport function IsoCheck({ size = 360, settle = false, shadow = true, title, className }: IsoCheckProps) {\n return (\n <div className={cn('relative inline-block', settle && 'oca-animate-settle', className)} style={{ width: size }}>\n <Mark size={size} title={title} className=\"relative z-10 block\" />\n {shadow ? (\n <div\n aria-hidden\n className=\"absolute left-[8%] right-[8%] rounded-[50%] opacity-60 blur-xl\"\n style={{ height: size * 0.08, bottom: -size * 0.04, background: 'rgb(234 88 11 / 0.18)' }}\n />\n ) : null}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/cn.ts","../src/brand/mark.tsx","../src/brand/sphere.tsx","../src/brand/iso-check.tsx","../src/brand/crowd.tsx"],"names":["jsx","jsxs"],"mappings":"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","file":"brand.mjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n// tailwind-merge would treat `oca-display-1` and `text-foreground` as the same\n// group and drop one; teach it the package's own type utilities.\nconst merge = extendTailwindMerge<'oca-type'>({\n extend: {\n classGroups: {\n 'oca-type': [\n 'oca-display-1',\n 'oca-display-2',\n 'oca-display-3',\n 'oca-title',\n 'oca-title-sm',\n 'oca-eyebrow',\n 'oca-lead',\n 'oca-body',\n 'oca-numeral',\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]): string {\n return merge(clsx(inputs));\n}\n","import type { SVGProps } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The isometric check, measured from Sou's deck (slide 9) onto a 16×8 grid:\n * a chevron with a 3-unit short arm and a 5-unit long arm, one unit thick,\n * extruded two units. Three faces, three oranges.\n */\n\nconst TOP = '0,3 2,2 6,4 14,0 16,1 6,6';\nconst LEFT = '0,3 6,6 6,8 0,5';\nconst RIGHT = '6,6 16,1 16,3 6,8';\n\nexport const MARK_FACES = { top: '#FED8AB', left: '#FB933C', right: '#EA580B' } as const;\n\nexport interface MarkProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n /** Accessible name. Omit to render the mark as decoration. */\n title?: string;\n /** Rendered width in px; height follows the 2:1 grid. */\n size?: number;\n}\n\nexport function Mark({ title, size, className, ...rest }: MarkProps) {\n return (\n <svg\n viewBox=\"0 0 16 8\"\n width={size}\n height={size ? size / 2 : undefined}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </svg>\n );\n}\n\nexport interface AppIconProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n title?: string;\n size?: number;\n}\n\n/** The app icon: the mark on an ink squircle, as in the deck's lockup. */\nexport function AppIcon({ title, size = 32, className, ...rest }: AppIconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n width={size}\n height={size}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <rect\n width=\"24\"\n height=\"24\"\n rx=\"6.25\"\n style={{ fill: 'var(--oca-icon-tile, #0A0A0A)', stroke: 'var(--oca-icon-ring, transparent)' }}\n strokeWidth=\"0.5\"\n />\n <g transform=\"translate(4.25 8.1) scale(0.97)\">\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </g>\n </svg>\n );\n}\n\nexport interface LockupProps {\n /** The word beside the icon. */\n name?: string;\n /** Icon size in px; the word scales with it. */\n size?: number;\n className?: string;\n}\n\n/** Icon and wordmark, lowercase, as the deck sets it. */\nexport function Lockup({ name = 'orangecheck', size = 28, className }: LockupProps) {\n return (\n <span\n className={cn('inline-flex items-center font-medium tracking-[-0.01em]', className)}\n style={{ gap: size * 0.32, fontSize: size * 0.56 }}\n >\n <AppIcon size={size} />\n <span>{name}</span>\n </span>\n );\n}\n","import type { CSSProperties } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The deck's photograph: a halftone portrait on an orange ball, lit from the\n * upper left, with a hairline stadium behind it. The dot layer is an image of\n * black dots on transparent, made by scripts/halftone.py, so the ball stays CSS\n * and the dots stay crisp at any size.\n */\n\nexport const SPHERE_GRADIENT =\n 'radial-gradient(86% 86% at 36% 32%, #fff7f0 0%, #ffdec8 14%, #ffa069 34%, #ff7030 56%, #f65210 78%, #de4006 100%)';\n\nconst SPHERE_DEPTH = 'inset -14px -22px 44px rgb(150 40 0 / 0.16), 0 36px 70px -34px rgb(234 88 11 / 0.45)';\n\nexport interface HalftoneSphereProps {\n /** The dot layer (black dots on transparent, already circular). */\n src: string;\n /** Describe the person or subject; empty string marks it decorative. */\n alt: string;\n /** Draw the hairline stadium behind the sphere, as the hero does. */\n stadium?: boolean;\n /** Let the sphere drift a few pixels. Off under reduced motion. */\n float?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction Ball({ src, alt, float }: { src: string; alt: string; float: boolean }) {\n return (\n <div\n className={cn('relative size-full overflow-hidden rounded-full', float && 'oca-animate-float')}\n style={{ background: SPHERE_GRADIENT, boxShadow: SPHERE_DEPTH }}\n >\n {/* eslint-disable-next-line @next/next/no-img-element -- a static dot layer, sized by CSS */}\n <img src={src} alt={alt} className=\"absolute inset-0 size-full select-none\" draggable={false} />\n </div>\n );\n}\n\nexport function HalftoneSphere({ src, alt, stadium = false, float = false, className, style }: HalftoneSphereProps) {\n if (!stadium) {\n return (\n <div className={cn('relative aspect-square w-full', className)} style={style}>\n <Ball src={src} alt={alt} float={float} />\n </div>\n );\n }\n // Measured from the deck's title slide against the ball's width S: the stadium\n // starts 0.255 S left of and 0.127 S above the ball, is 1.11 S wide, and ends\n // level with its foot. Both live inside this box, so nothing reaches the text.\n return (\n <div className={cn('relative aspect-[1.255/1.127] w-full', className)} style={style}>\n <div aria-hidden className=\"oca-stadium pointer-events-none absolute left-0 top-0 h-full w-[88.4%] rounded-[32%]\" />\n <div className=\"absolute bottom-0 right-0 aspect-square w-[79.7%]\">\n <Ball src={src} alt={alt} float={float} />\n </div>\n </div>\n );\n}\n","import { cn } from '../lib/cn';\nimport { Mark } from './mark';\n\nexport interface IsoCheckProps {\n /** Width in px; the check keeps its 2:1 grid. */\n size?: number;\n /** Drop it into place on first paint, the deck's closing gesture. */\n settle?: boolean;\n /** A soft floor shadow, so it reads as an object on the canvas. */\n shadow?: boolean;\n title?: string;\n className?: string;\n}\n\n/** The isometric check as an object: the deck's closing illustration. */\nexport function IsoCheck({ size = 360, settle = false, shadow = true, title, className }: IsoCheckProps) {\n return (\n <div className={cn('relative inline-block', settle && 'oca-animate-settle', className)} style={{ width: size }}>\n <Mark size={size} title={title} className=\"relative z-10 block\" />\n {shadow ? (\n <div\n aria-hidden\n className=\"absolute left-[8%] right-[8%] rounded-[50%] opacity-60 blur-xl\"\n style={{ height: size * 0.08, bottom: -size * 0.04, background: 'rgb(234 88 11 / 0.18)' }}\n />\n ) : null}\n </div>\n );\n}\n","import { cn } from '../lib/cn';\n\n/*\n * \"A bot farm can pretend to be a crowd\": a crowd of identical figures in\n * perspective, nearer rows larger, with a few real ones in orange. Identical on\n * purpose: copies are what a bot farm is. Positions come from a fixed seed so\n * server and client draw the same crowd.\n */\n\nexport interface CrowdProps {\n cols?: number;\n rows?: number;\n /** How many figures are real (orange). */\n real?: number;\n seed?: number;\n /** Ground it sits on: figures are light on ink, dark on canvas. */\n tone?: 'ink' | 'canvas';\n /** Spoken by screen readers. */\n label?: string;\n className?: string;\n}\n\nconst CELL_W = 22;\nconst CELL_H = 27;\n\nfunction picks(count: number, total: number, seed: number): Set<number> {\n let s = seed >>> 0;\n const out = new Set<number>();\n while (out.size < Math.min(count, total)) {\n s = (Math.imul(s, 1664525) + 1013904223) >>> 0;\n out.add(s % total);\n }\n return out;\n}\n\nexport function Crowd({\n cols = 26,\n rows = 9,\n real = 7,\n seed = 21,\n tone = 'ink',\n label = 'A crowd of identical accounts. Only a few are real.',\n className,\n}: CrowdProps) {\n const width = cols * CELL_W;\n const scales = Array.from({ length: rows }, (_, r) => 0.5 + 0.5 * (r / Math.max(1, rows - 1)));\n const height = scales.reduce((h, s) => h + CELL_H * s, 0);\n // Real figures only in the nearer half, where they are big enough to see.\n const nearFrom = Math.floor(rows / 2) * cols;\n const realSet = new Set([...picks(real, rows * cols - nearFrom, seed)].map((i) => i + nearFrom));\n const bot = tone === 'ink' ? '#ffffff' : '#0a0a0a';\n let y = 0;\n return (\n <svg\n role=\"img\"\n aria-label={label}\n viewBox={`0 0 ${width} ${Math.ceil(height)}`}\n className={cn('block h-auto w-full', className)}\n >\n {scales.map((s, r) => {\n const rowY = y;\n y += CELL_H * s;\n const rowW = cols * CELL_W * s;\n const x0 = (width - rowW) / 2;\n return Array.from({ length: cols }, (_, c) => {\n const i = r * cols + c;\n const isReal = realSet.has(i);\n return (\n <g\n key={i}\n transform={`translate(${x0 + c * CELL_W * s} ${rowY}) scale(${s})`}\n fill={isReal ? 'var(--oca-orange)' : bot}\n fillOpacity={isReal ? 1 : 0.1 + 0.16 * s}\n >\n <circle cx={11} cy={8} r={4.4} />\n <path d=\"M3 25a8 8.5 0 0 1 16 0Z\" />\n </g>\n );\n });\n })}\n </svg>\n );\n}\n"]}
|
package/dist/components.d.mts
CHANGED
|
@@ -344,6 +344,17 @@ declare function CodeBlock({ code, caption, className, }: {
|
|
|
344
344
|
className?: string;
|
|
345
345
|
}): react.JSX.Element;
|
|
346
346
|
|
|
347
|
+
interface SplitSegment {
|
|
348
|
+
pct: number;
|
|
349
|
+
label: ReactNode;
|
|
350
|
+
tone?: 'ink' | 'card';
|
|
351
|
+
}
|
|
352
|
+
declare function SplitBar({ segments, caption, className, }: {
|
|
353
|
+
segments: SplitSegment[];
|
|
354
|
+
caption?: ReactNode;
|
|
355
|
+
className?: string;
|
|
356
|
+
}): react.JSX.Element;
|
|
357
|
+
|
|
347
358
|
type TruthStatus = 'yes' | 'testing' | 'not-yet' | 'no';
|
|
348
359
|
interface TruthRow {
|
|
349
360
|
status: TruthStatus;
|
|
@@ -471,4 +482,4 @@ declare function ActivityList({ items, empty, className }: {
|
|
|
471
482
|
className?: string;
|
|
472
483
|
}): react.JSX.Element;
|
|
473
484
|
|
|
474
|
-
export { Accent, type ActivityItem, ActivityList, CodeBlock, type Column, Container, CopyButton, DataTable, Display, type DisplayProps, EmptyState, Eyebrow, Footnote, HashChip, type KeyValueItem, KeyValueList, Lead, Notice, PackageCard, type PackageItem, PageHeader, type ProgressStep, ProgressSteps, Prose, Sats, SatsFigure, type SatsProps, type SatsTextOptions, Section, SectionIntro, type SectionProps, StatCard, StatGrid, StepGrid, type StepGridProps, type StepItem, type StepState, type TruthRow, type TruthStatus, TruthTable, UsdApprox, satsText, sectionVariants, useCopy };
|
|
485
|
+
export { Accent, type ActivityItem, ActivityList, CodeBlock, type Column, Container, CopyButton, DataTable, Display, type DisplayProps, EmptyState, Eyebrow, Footnote, HashChip, type KeyValueItem, KeyValueList, Lead, Notice, PackageCard, type PackageItem, PageHeader, type ProgressStep, ProgressSteps, Prose, Sats, SatsFigure, type SatsProps, type SatsTextOptions, Section, SectionIntro, type SectionProps, SplitBar, type SplitSegment, StatCard, StatGrid, StepGrid, type StepGridProps, type StepItem, type StepState, type TruthRow, type TruthStatus, TruthTable, UsdApprox, satsText, sectionVariants, useCopy };
|
package/dist/components.d.ts
CHANGED
|
@@ -344,6 +344,17 @@ declare function CodeBlock({ code, caption, className, }: {
|
|
|
344
344
|
className?: string;
|
|
345
345
|
}): react.JSX.Element;
|
|
346
346
|
|
|
347
|
+
interface SplitSegment {
|
|
348
|
+
pct: number;
|
|
349
|
+
label: ReactNode;
|
|
350
|
+
tone?: 'ink' | 'card';
|
|
351
|
+
}
|
|
352
|
+
declare function SplitBar({ segments, caption, className, }: {
|
|
353
|
+
segments: SplitSegment[];
|
|
354
|
+
caption?: ReactNode;
|
|
355
|
+
className?: string;
|
|
356
|
+
}): react.JSX.Element;
|
|
357
|
+
|
|
347
358
|
type TruthStatus = 'yes' | 'testing' | 'not-yet' | 'no';
|
|
348
359
|
interface TruthRow {
|
|
349
360
|
status: TruthStatus;
|
|
@@ -471,4 +482,4 @@ declare function ActivityList({ items, empty, className }: {
|
|
|
471
482
|
className?: string;
|
|
472
483
|
}): react.JSX.Element;
|
|
473
484
|
|
|
474
|
-
export { Accent, type ActivityItem, ActivityList, CodeBlock, type Column, Container, CopyButton, DataTable, Display, type DisplayProps, EmptyState, Eyebrow, Footnote, HashChip, type KeyValueItem, KeyValueList, Lead, Notice, PackageCard, type PackageItem, PageHeader, type ProgressStep, ProgressSteps, Prose, Sats, SatsFigure, type SatsProps, type SatsTextOptions, Section, SectionIntro, type SectionProps, StatCard, StatGrid, StepGrid, type StepGridProps, type StepItem, type StepState, type TruthRow, type TruthStatus, TruthTable, UsdApprox, satsText, sectionVariants, useCopy };
|
|
485
|
+
export { Accent, type ActivityItem, ActivityList, CodeBlock, type Column, Container, CopyButton, DataTable, Display, type DisplayProps, EmptyState, Eyebrow, Footnote, HashChip, type KeyValueItem, KeyValueList, Lead, Notice, PackageCard, type PackageItem, PageHeader, type ProgressStep, ProgressSteps, Prose, Sats, SatsFigure, type SatsProps, type SatsTextOptions, Section, SectionIntro, type SectionProps, SplitBar, type SplitSegment, StatCard, StatGrid, StepGrid, type StepGridProps, type StepItem, type StepState, type TruthRow, type TruthStatus, TruthTable, UsdApprox, satsText, sectionVariants, useCopy };
|
package/dist/components.js
CHANGED
|
@@ -216,6 +216,47 @@ function CodeBlock({
|
|
|
216
216
|
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "overflow-x-auto p-5 font-mono text-[0.875rem] leading-relaxed text-oca-ink-muted", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: code }) })
|
|
217
217
|
] });
|
|
218
218
|
}
|
|
219
|
+
function SplitBar({
|
|
220
|
+
segments,
|
|
221
|
+
caption,
|
|
222
|
+
className
|
|
223
|
+
}) {
|
|
224
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: cn("flex flex-col gap-5", className), children: [
|
|
225
|
+
caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "text-[0.9375rem]", children: caption }) : null,
|
|
226
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-16 w-full gap-1.5 overflow-hidden rounded-[1.25rem] md:h-20", children: segments.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
227
|
+
"div",
|
|
228
|
+
{
|
|
229
|
+
className: cn(
|
|
230
|
+
"flex min-w-0 items-end rounded-[1rem] px-4 pb-3",
|
|
231
|
+
s.tone === "card" ? "bg-white text-oca-ink" : "bg-oca-ink text-white"
|
|
232
|
+
),
|
|
233
|
+
style: { flexBasis: `${s.pct}%` },
|
|
234
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "oca-tabular text-[1.5rem] leading-none tracking-[-0.02em] md:text-[1.875rem]", children: [
|
|
235
|
+
s.pct,
|
|
236
|
+
"%"
|
|
237
|
+
] })
|
|
238
|
+
},
|
|
239
|
+
i
|
|
240
|
+
)) }),
|
|
241
|
+
/* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid gap-x-8 gap-y-2 sm:grid-cols-2", children: segments.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2.5", children: [
|
|
242
|
+
/* @__PURE__ */ jsxRuntime.jsxs("dt", { className: "sr-only", children: [
|
|
243
|
+
s.pct,
|
|
244
|
+
"%"
|
|
245
|
+
] }),
|
|
246
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
247
|
+
"span",
|
|
248
|
+
{
|
|
249
|
+
"aria-hidden": true,
|
|
250
|
+
className: cn(
|
|
251
|
+
"inline-block size-2.5 shrink-0 translate-y-[-1px] rounded-full",
|
|
252
|
+
s.tone === "card" ? "bg-white" : "bg-oca-ink"
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
),
|
|
256
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { className: "text-[0.9375rem] leading-snug", children: s.label })
|
|
257
|
+
] }, i)) })
|
|
258
|
+
] });
|
|
259
|
+
}
|
|
219
260
|
var LABEL = {
|
|
220
261
|
yes: "Yes",
|
|
221
262
|
testing: "In testing",
|
|
@@ -607,6 +648,7 @@ exports.Sats = Sats;
|
|
|
607
648
|
exports.SatsFigure = SatsFigure;
|
|
608
649
|
exports.Section = Section;
|
|
609
650
|
exports.SectionIntro = SectionIntro;
|
|
651
|
+
exports.SplitBar = SplitBar;
|
|
610
652
|
exports.StatCard = StatCard;
|
|
611
653
|
exports.StatGrid = StatGrid;
|
|
612
654
|
exports.StepGrid = StepGrid;
|