@021.is/brand-studio 0.3.0 → 0.6.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/AGENTS.md +15 -5
- package/README.md +26 -0
- package/dist/{BrandStudio-D2DcT8Fu.d.ts → BrandStudio-D1QR4hIC.d.ts} +1 -1
- package/dist/app/index.d.ts +2 -2
- package/dist/app/index.js +3 -2
- package/dist/chunk-6J2NFZLN.js +50 -0
- package/dist/{chunk-ZE5UZAY6.js → chunk-F4CFQDS7.js} +2 -1
- package/dist/{chunk-Z2DJJJDC.js → chunk-L4FQAO3K.js} +178 -18
- package/dist/chunk-MDTU2JR5.js +35 -0
- package/dist/{chunk-55AYEWNQ.js → chunk-YDZA26YU.js} +1 -22
- package/dist/define/index.d.ts +45 -3
- package/dist/define/index.js +2 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -4
- package/dist/loading/index.d.ts +1 -1
- package/dist/loading/index.js +3 -2
- package/dist/types-BycZ2igw.d.ts +119 -0
- package/package.json +2 -2
- package/dist/chunk-QT5N4K7D.js +0 -8
- package/dist/types-PWNYyaBF.d.ts +0 -66
package/AGENTS.md
CHANGED
|
@@ -46,16 +46,26 @@ src/
|
|
|
46
46
|
- **Named exports only.** **No CSS framework lock-in** — inline `style` / `var(--md-*)`, accept `className`.
|
|
47
47
|
- Sections theme from `var(--md-<role>)`, never from a hand-authored palette.
|
|
48
48
|
|
|
49
|
+
## The downloads contract — MANDATORY (v0.4+)
|
|
50
|
+
|
|
51
|
+
Every consumer ships icon + logo download URLs under `/brand/download`. Wire `BrandConfig.downloads = buildStandardDownloads({ basePath })` (or supply explicit `BrandDownload[]`). The lib renders the link grid; the host app serves each URL — one Next.js route handler that renders the SVG sized + recoloured per path params is the canonical pattern.
|
|
52
|
+
|
|
53
|
+
- URL shape: `<basePath>/<kind>/<size>/<mode>.<format>` — `kind` ∈ {icon, logo} · `mode` ∈ {light, dark} · `format` defaults to `svg`.
|
|
54
|
+
- Canonical sizes: icon 64/128/256/512/1024 (square edge); logo 32/48/64/96/128 (height).
|
|
55
|
+
- Consumers that don't wire `downloads` fall back to the legacy on-click SVG-blob generator with a banner pointing at this contract. The fallback is for migration only — every published app must wire the matrix.
|
|
56
|
+
- Enforce: `grep -L "buildStandardDownloads\|downloads:" brand.config.ts` in every consumer repo's CI = regression.
|
|
57
|
+
|
|
49
58
|
## Build + publish
|
|
50
59
|
|
|
51
|
-
- `bun run build` (tsup + `scripts/add-use-client.mjs`) → `dist/`. `bun run typecheck` + `bun run lint` green before commit.
|
|
52
|
-
- `npm pack` → tgz (
|
|
53
|
-
- Bump `version` on
|
|
60
|
+
- `bun run build` (tsup + `scripts/add-use-client.mjs`) → `dist/`. `bun run typecheck` + `bun run lint` + `bun run test` green before commit.
|
|
61
|
+
- `npm pack` → tgz (`021is-brand-studio-<version>.tgz`). Publish destination is **`registry.npmjs.org`** as `@021.is/brand-studio` (verified live for 0.3.0 — earlier note about GitHub Packages is stale). `npm publish` needs Edvard's classic npm token + **his explicit OK** — never auto-publish.
|
|
62
|
+
- Bump `version` on every change; consumers update via `bun add @021.is/brand-studio@<version>`.
|
|
54
63
|
|
|
55
64
|
## Active threads
|
|
56
65
|
|
|
57
|
-
- **v0.
|
|
58
|
-
- **v0.
|
|
66
|
+
- **v0.4.0 (current) — downloads URL contract.** ✅ Added `BrandConfig.downloads` + `buildStandardDownloads()` helper + rewrote `<DownloadSection>` as a URL link grid (open · copy · save). Legacy on-click SVG generator kept as fallback for v0.3.x consumers. zeropost is the reference wiring.
|
|
67
|
+
- **v0.3.0 — generic + MD3.** ✅ Ripped out all zeropost/postal content (icons, mailbox marks, FlagDroop/Stamp motions, forest/cream defaults). Added the MD3 color engine + seed-based `defineBrand`. `private:false`, publishable. Live on npm 2026-06-03.
|
|
68
|
+
- **v0.5.0 — export CLI.** `npx brand-studio export ./brand.config.ts` → icon.svg / apple-icon.png / og.png (satori/resvg). Complements the runtime URL contract for static-export use cases.
|
|
59
69
|
- **v1.0.0 — visual editor + plugin API.**
|
|
60
70
|
|
|
61
71
|
## See
|
package/README.md
CHANGED
|
@@ -54,6 +54,32 @@ export default defineBrand({
|
|
|
54
54
|
|
|
55
55
|
`defineBrand` eagerly resolves `config.scheme` (the full `{ light, dark }` role set) so downstream consumers never wait on a derivation.
|
|
56
56
|
|
|
57
|
+
## Expose the download matrix (mandatory, v0.4+)
|
|
58
|
+
|
|
59
|
+
Every consumer ships a `/brand/download` link grid for the **app icon** and **logo** at **multiple sizes** in **both light and dark** variants. Wire `BrandConfig.downloads` with `buildStandardDownloads(basePath)` and serve the URLs from your host app:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
// brand.config.ts
|
|
63
|
+
import { defineBrand, buildStandardDownloads } from "@021.is/brand-studio/define";
|
|
64
|
+
|
|
65
|
+
export default defineBrand({
|
|
66
|
+
name: "Acme",
|
|
67
|
+
// ... color, type, voice ...
|
|
68
|
+
downloads: buildStandardDownloads({ basePath: "/brand/download" }),
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Default URL shape: `<basePath>/<kind>/<size>/<mode>.<format>`
|
|
73
|
+
Example: `/brand/download/icon/256/light.svg` · `/brand/download/logo/64/dark.svg`
|
|
74
|
+
|
|
75
|
+
Canonical matrix:
|
|
76
|
+
- **Icon** sizes: 64 / 128 / 256 / 512 / 1024 (square edge px)
|
|
77
|
+
- **Logo** sizes: 32 / 48 / 64 / 96 / 128 (height px)
|
|
78
|
+
- Each size in both `light` and `dark`
|
|
79
|
+
- Format: `svg` by default (PNG opt-in via the `formats` option)
|
|
80
|
+
|
|
81
|
+
The host app serves each URL — typically one Next.js route handler that renders the SVG mark sized + recoloured per the path params. Consumers that don't wire `downloads` keep working: the Download section falls back to the v0.3.x on-click SVG-blob generator, with a banner pointing at this section.
|
|
82
|
+
|
|
57
83
|
## Mount the brand page
|
|
58
84
|
|
|
59
85
|
```tsx
|
package/dist/app/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { B as BrandIcon, a as BrandStudio, b as BrandStudioProps } from '../BrandStudio-
|
|
1
|
+
export { B as BrandIcon, a as BrandStudio, b as BrandStudioProps } from '../BrandStudio-D1QR4hIC.js';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import { ReactNode } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { c as BrandStudioSection } from '../types-BycZ2igw.js';
|
|
5
5
|
export { c as contrastBadge, a as contrastRatio, r as relativeLuminance } from '../contrast-TVW3pzdd.js';
|
|
6
6
|
import '../generateScheme-BDDcIzA3.js';
|
|
7
7
|
|
package/dist/app/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { BrandStudio, Navigation, buildNavigation } from '../chunk-
|
|
3
|
-
import '../chunk-
|
|
2
|
+
export { BrandStudio, Navigation, buildNavigation } from '../chunk-L4FQAO3K.js';
|
|
3
|
+
import '../chunk-YDZA26YU.js';
|
|
4
|
+
import '../chunk-MDTU2JR5.js';
|
|
4
5
|
export { contrastBadge, contrastRatio, relativeLuminance } from '../chunk-JQV3ASME.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { DownloadKind, DownloadFormat, DownloadMode } from './chunk-MDTU2JR5.js';
|
|
2
|
+
import { generateScheme } from './chunk-JQV3ASME.js';
|
|
3
|
+
|
|
4
|
+
// src/define/defineBrand.ts
|
|
5
|
+
function defineBrand(config) {
|
|
6
|
+
return { ...config, scheme: config.scheme ?? generateScheme(config.color) };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/define/downloads.ts
|
|
10
|
+
var STANDARD_ICON_SIZES = [64, 128, 256, 512, 1024];
|
|
11
|
+
var STANDARD_LOGO_SIZES = [32, 48, 64, 96, 128];
|
|
12
|
+
var KIND_PATH = {
|
|
13
|
+
[DownloadKind.Icon]: "app-icon",
|
|
14
|
+
[DownloadKind.Logo]: "logo"
|
|
15
|
+
};
|
|
16
|
+
function buildStandardDownloads(input) {
|
|
17
|
+
const brand = slugify(input.brand);
|
|
18
|
+
if (!brand) throw new Error("buildStandardDownloads: `brand` is required (non-empty after slug)");
|
|
19
|
+
const basePath = (input.basePath ?? "/brand").replace(/\/+$/, "");
|
|
20
|
+
const iconSizes = input.iconSizes ?? STANDARD_ICON_SIZES;
|
|
21
|
+
const logoSizes = input.logoSizes ?? STANDARD_LOGO_SIZES;
|
|
22
|
+
const formats = input.formats ?? [DownloadFormat.Svg];
|
|
23
|
+
const modes = [DownloadMode.Light, DownloadMode.Dark];
|
|
24
|
+
const items = [];
|
|
25
|
+
for (const kind of [DownloadKind.Icon, DownloadKind.Logo]) {
|
|
26
|
+
const sizes = kind === DownloadKind.Icon ? iconSizes : logoSizes;
|
|
27
|
+
const kindPath = KIND_PATH[kind];
|
|
28
|
+
for (const size of sizes) {
|
|
29
|
+
for (const mode of modes) {
|
|
30
|
+
for (const format of formats) {
|
|
31
|
+
const filename = `${brand}-${size}-${mode}.${format}`;
|
|
32
|
+
items.push({
|
|
33
|
+
kind,
|
|
34
|
+
mode,
|
|
35
|
+
size,
|
|
36
|
+
format,
|
|
37
|
+
url: `${basePath}/${kindPath}/${filename}`,
|
|
38
|
+
filename
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { items };
|
|
45
|
+
}
|
|
46
|
+
function slugify(input) {
|
|
47
|
+
return input.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { STANDARD_ICON_SIZES, STANDARD_LOGO_SIZES, buildStandardDownloads, defineBrand, slugify };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { SpinnerLoadingMark } from './chunk-YDZA26YU.js';
|
|
3
|
+
import { LoadingVariant } from './chunk-MDTU2JR5.js';
|
|
3
4
|
import { motion } from 'framer-motion';
|
|
4
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
6
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SpinnerLoadingMark } from './chunk-YDZA26YU.js';
|
|
2
|
+
import { BrandStudioSection, DownloadMode, DownloadKind, DownloadFormat } from './chunk-MDTU2JR5.js';
|
|
2
3
|
import { generateScheme, schemeToCssText, ROLE_GROUPS, contrastBadge, contrastRatio } from './chunk-JQV3ASME.js';
|
|
3
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
5
|
import { useRef, useState } from 'react';
|
|
@@ -178,17 +179,6 @@ function ColorsSection({ scheme }) {
|
|
|
178
179
|
}
|
|
179
180
|
var ICON_SIZES = [64, 128, 256, 512, 1024];
|
|
180
181
|
var WORDMARK_HEIGHTS = [32, 48, 64, 96, 128];
|
|
181
|
-
function triggerDownload(svgString, filename) {
|
|
182
|
-
const blob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
|
|
183
|
-
const url = URL.createObjectURL(blob);
|
|
184
|
-
const a = document.createElement("a");
|
|
185
|
-
a.href = url;
|
|
186
|
-
a.download = filename;
|
|
187
|
-
document.body.appendChild(a);
|
|
188
|
-
a.click();
|
|
189
|
-
a.remove();
|
|
190
|
-
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
191
|
-
}
|
|
192
182
|
function DownloadSection({
|
|
193
183
|
config,
|
|
194
184
|
staticLogo,
|
|
@@ -209,7 +199,17 @@ function DownloadSection({
|
|
|
209
199
|
const darkLabel = scheme.dark.onSurfaceVariant;
|
|
210
200
|
const iconDarkNode = staticLogoDark ?? staticLogo;
|
|
211
201
|
const hasDistinctDark = staticLogoDark !== void 0 && staticLogoDark !== null;
|
|
212
|
-
|
|
202
|
+
const downloads = config.downloads?.items ?? [];
|
|
203
|
+
const iconLight = findEntry(downloads, DownloadKind.Icon, DownloadMode.Light, iconSize);
|
|
204
|
+
const iconDark = findEntry(downloads, DownloadKind.Icon, DownloadMode.Dark, iconSize);
|
|
205
|
+
const logoLight = findEntry(downloads, DownloadKind.Logo, DownloadMode.Light, wmHeight);
|
|
206
|
+
const logoDark = findEntry(downloads, DownloadKind.Logo, DownloadMode.Dark, wmHeight);
|
|
207
|
+
async function downloadIcon(mode) {
|
|
208
|
+
const entry = mode === "light" ? iconLight : iconDark;
|
|
209
|
+
if (entry) {
|
|
210
|
+
await fetchAndSave(entry.url, entry.filename ?? lastSegment(entry.url));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
213
|
const ref = mode === "light" ? iconLightRef : iconDarkRef;
|
|
214
214
|
const svg = ref.current?.querySelector("svg");
|
|
215
215
|
if (!svg) return;
|
|
@@ -217,12 +217,17 @@ function DownloadSection({
|
|
|
217
217
|
clone.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
218
218
|
clone.setAttribute("width", String(iconSize));
|
|
219
219
|
clone.setAttribute("height", String(iconSize));
|
|
220
|
-
|
|
220
|
+
triggerBlobDownload(
|
|
221
221
|
new XMLSerializer().serializeToString(clone),
|
|
222
222
|
`${config.name}-icon-${iconSize}-${mode}.svg`
|
|
223
223
|
);
|
|
224
224
|
}
|
|
225
225
|
async function downloadWordmark(mode) {
|
|
226
|
+
const entry = mode === "light" ? logoLight : logoDark;
|
|
227
|
+
if (entry) {
|
|
228
|
+
await fetchAndSave(entry.url, entry.filename ?? lastSegment(entry.url));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
226
231
|
await document.fonts?.ready;
|
|
227
232
|
const text = measureRef.current?.querySelector("text");
|
|
228
233
|
if (!text) return;
|
|
@@ -237,7 +242,7 @@ function DownloadSection({
|
|
|
237
242
|
`<text x="${(pad - bbox.x).toFixed(1)}" y="${pad.toFixed(1)}" dominant-baseline="text-before-edge" font-family="${sans}, system-ui, sans-serif" font-weight="600" font-size="100" letter-spacing="-3" fill="${fill}">${config.name}</text>`,
|
|
238
243
|
"</svg>"
|
|
239
244
|
].join("");
|
|
240
|
-
|
|
245
|
+
triggerBlobDownload(out, `${config.name}-wordmark-${wmHeight}-${mode}.svg`);
|
|
241
246
|
}
|
|
242
247
|
return /* @__PURE__ */ jsxs("section", { children: [
|
|
243
248
|
/* @__PURE__ */ jsx(
|
|
@@ -257,11 +262,11 @@ function DownloadSection({
|
|
|
257
262
|
{
|
|
258
263
|
style: {
|
|
259
264
|
color: "var(--md-on-surface-variant)",
|
|
260
|
-
maxWidth: "
|
|
265
|
+
maxWidth: "44rem",
|
|
261
266
|
margin: "0 0 2.5rem",
|
|
262
267
|
lineHeight: 1.6
|
|
263
268
|
},
|
|
264
|
-
children: "Export the app icon and wordmark as standalone SVGs in light and dark variants. Pick a size, download,
|
|
269
|
+
children: "Export the app icon and wordmark as standalone SVGs in light and dark variants. Pick a size, download, or copy the stable URL beneath the buttons to embed or share."
|
|
265
270
|
}
|
|
266
271
|
),
|
|
267
272
|
/* @__PURE__ */ jsxs(
|
|
@@ -302,6 +307,7 @@ function DownloadSection({
|
|
|
302
307
|
}
|
|
303
308
|
)
|
|
304
309
|
] }),
|
|
310
|
+
iconLight || iconDark ? /* @__PURE__ */ jsx(UrlPair, { light: iconLight, dark: iconDark }) : null,
|
|
305
311
|
staticLogo && !hasDistinctDark ? /* @__PURE__ */ jsxs(Note, { children: [
|
|
306
312
|
"No dark icon supplied \u2014 dark export reuses the light mark. Pass",
|
|
307
313
|
" ",
|
|
@@ -343,7 +349,8 @@ function DownloadSection({
|
|
|
343
349
|
children: "Dark SVG"
|
|
344
350
|
}
|
|
345
351
|
)
|
|
346
|
-
] })
|
|
352
|
+
] }),
|
|
353
|
+
logoLight || logoDark ? /* @__PURE__ */ jsx(UrlPair, { light: logoLight, dark: logoDark }) : null
|
|
347
354
|
] })
|
|
348
355
|
]
|
|
349
356
|
}
|
|
@@ -390,6 +397,139 @@ function DownloadSection({
|
|
|
390
397
|
)
|
|
391
398
|
] });
|
|
392
399
|
}
|
|
400
|
+
function findEntry(items, kind, mode, size) {
|
|
401
|
+
const entry = items.find(
|
|
402
|
+
(it) => it.kind === kind && it.mode === mode && it.size === size && it.format === DownloadFormat.Svg
|
|
403
|
+
);
|
|
404
|
+
return entry ?? null;
|
|
405
|
+
}
|
|
406
|
+
function triggerBlobDownload(svgString, filename) {
|
|
407
|
+
const blob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
|
|
408
|
+
const url = URL.createObjectURL(blob);
|
|
409
|
+
const a = document.createElement("a");
|
|
410
|
+
a.href = url;
|
|
411
|
+
a.download = filename;
|
|
412
|
+
document.body.appendChild(a);
|
|
413
|
+
a.click();
|
|
414
|
+
a.remove();
|
|
415
|
+
window.setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
416
|
+
}
|
|
417
|
+
async function fetchAndSave(url, filename) {
|
|
418
|
+
try {
|
|
419
|
+
const res = await fetch(url, { cache: "no-store" });
|
|
420
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
421
|
+
const blob = await res.blob();
|
|
422
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
423
|
+
const a = document.createElement("a");
|
|
424
|
+
a.href = objectUrl;
|
|
425
|
+
a.download = filename;
|
|
426
|
+
document.body.appendChild(a);
|
|
427
|
+
a.click();
|
|
428
|
+
a.remove();
|
|
429
|
+
window.setTimeout(() => URL.revokeObjectURL(objectUrl), 1e3);
|
|
430
|
+
} catch {
|
|
431
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function UrlPair({ light, dark }) {
|
|
435
|
+
return /* @__PURE__ */ jsxs(
|
|
436
|
+
"div",
|
|
437
|
+
{
|
|
438
|
+
style: {
|
|
439
|
+
marginTop: "0.7rem",
|
|
440
|
+
display: "grid",
|
|
441
|
+
gap: "0.35rem"
|
|
442
|
+
},
|
|
443
|
+
children: [
|
|
444
|
+
/* @__PURE__ */ jsx(UrlRow, { label: "LIGHT", entry: light }),
|
|
445
|
+
/* @__PURE__ */ jsx(UrlRow, { label: "DARK", entry: dark })
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
function UrlRow({ label, entry }) {
|
|
451
|
+
const [copied, setCopied] = useState(false);
|
|
452
|
+
const url = entry?.url ?? null;
|
|
453
|
+
function onCopy() {
|
|
454
|
+
if (!url || typeof navigator === "undefined" || !navigator.clipboard) return;
|
|
455
|
+
navigator.clipboard.writeText(toAbsolute(url)).then(() => {
|
|
456
|
+
setCopied(true);
|
|
457
|
+
window.setTimeout(() => setCopied(false), 1200);
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
const disabled = !url;
|
|
461
|
+
const downloadName = entry?.filename ?? lastSegment(url ?? "");
|
|
462
|
+
return /* @__PURE__ */ jsxs(
|
|
463
|
+
"div",
|
|
464
|
+
{
|
|
465
|
+
style: {
|
|
466
|
+
display: "flex",
|
|
467
|
+
alignItems: "center",
|
|
468
|
+
gap: "0.4rem",
|
|
469
|
+
padding: "0.4rem 0.6rem",
|
|
470
|
+
borderRadius: "0.45rem",
|
|
471
|
+
background: "var(--md-surface-container-low)",
|
|
472
|
+
border: "1px solid var(--md-outline-variant)",
|
|
473
|
+
opacity: disabled ? 0.55 : 1
|
|
474
|
+
},
|
|
475
|
+
children: [
|
|
476
|
+
/* @__PURE__ */ jsx("span", { style: urlLabelStyle, children: label }),
|
|
477
|
+
/* @__PURE__ */ jsx(
|
|
478
|
+
"a",
|
|
479
|
+
{
|
|
480
|
+
href: url ?? "#",
|
|
481
|
+
target: "_blank",
|
|
482
|
+
rel: "noreferrer",
|
|
483
|
+
download: downloadName || void 0,
|
|
484
|
+
style: {
|
|
485
|
+
flex: 1,
|
|
486
|
+
color: "var(--md-on-surface)",
|
|
487
|
+
textDecoration: "none",
|
|
488
|
+
fontFamily: "var(--bs-mono, ui-monospace, monospace)",
|
|
489
|
+
fontSize: "0.74rem",
|
|
490
|
+
letterSpacing: "0.01em",
|
|
491
|
+
minWidth: 0,
|
|
492
|
+
overflow: "hidden",
|
|
493
|
+
textOverflow: "ellipsis",
|
|
494
|
+
whiteSpace: "nowrap",
|
|
495
|
+
pointerEvents: disabled ? "none" : "auto"
|
|
496
|
+
},
|
|
497
|
+
title: url ?? "no URL configured for this size",
|
|
498
|
+
children: url ?? "\u2014"
|
|
499
|
+
}
|
|
500
|
+
),
|
|
501
|
+
/* @__PURE__ */ jsx(
|
|
502
|
+
"button",
|
|
503
|
+
{
|
|
504
|
+
type: "button",
|
|
505
|
+
onClick: onCopy,
|
|
506
|
+
disabled,
|
|
507
|
+
title: "Copy URL",
|
|
508
|
+
style: {
|
|
509
|
+
...copyButtonStyle,
|
|
510
|
+
cursor: disabled ? "not-allowed" : "pointer"
|
|
511
|
+
},
|
|
512
|
+
children: copied ? "Copied" : "Copy"
|
|
513
|
+
}
|
|
514
|
+
)
|
|
515
|
+
]
|
|
516
|
+
}
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
function lastSegment(url) {
|
|
520
|
+
const noQuery = url.split("?")[0] ?? "";
|
|
521
|
+
const parts = noQuery.split("/");
|
|
522
|
+
return parts[parts.length - 1] ?? "";
|
|
523
|
+
}
|
|
524
|
+
function toAbsolute(url) {
|
|
525
|
+
if (/^https?:\/\//.test(url)) return url;
|
|
526
|
+
if (typeof window === "undefined") return url;
|
|
527
|
+
try {
|
|
528
|
+
return new URL(url, window.location.origin).toString();
|
|
529
|
+
} catch {
|
|
530
|
+
return url;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
393
533
|
var mono = { fontFamily: "var(--bs-mono)" };
|
|
394
534
|
function NoAsset() {
|
|
395
535
|
return /* @__PURE__ */ jsx("span", { style: { color: "var(--md-on-surface-variant)", fontSize: "0.8rem" }, children: "no icon" });
|
|
@@ -518,6 +658,26 @@ var eyebrowStyle = {
|
|
|
518
658
|
color: "var(--md-primary)",
|
|
519
659
|
margin: 0
|
|
520
660
|
};
|
|
661
|
+
var urlLabelStyle = {
|
|
662
|
+
fontFamily: "var(--bs-mono, ui-monospace, monospace)",
|
|
663
|
+
fontSize: "0.62rem",
|
|
664
|
+
letterSpacing: "0.14em",
|
|
665
|
+
textTransform: "uppercase",
|
|
666
|
+
color: "var(--md-on-surface-variant)",
|
|
667
|
+
flexShrink: 0,
|
|
668
|
+
width: "3rem"
|
|
669
|
+
};
|
|
670
|
+
var copyButtonStyle = {
|
|
671
|
+
padding: "0.3rem 0.55rem",
|
|
672
|
+
borderRadius: "0.35rem",
|
|
673
|
+
border: "1px solid var(--md-outline-variant)",
|
|
674
|
+
background: "transparent",
|
|
675
|
+
color: "var(--md-primary)",
|
|
676
|
+
fontFamily: "var(--bs-mono, ui-monospace, monospace)",
|
|
677
|
+
fontSize: "0.68rem",
|
|
678
|
+
fontWeight: 600,
|
|
679
|
+
whiteSpace: "nowrap"
|
|
680
|
+
};
|
|
521
681
|
function buttonStyle(disabled, kind) {
|
|
522
682
|
const isPrimary = kind === "primary";
|
|
523
683
|
return {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var LoadingVariant = {
|
|
3
|
+
Spinner: "spinner",
|
|
4
|
+
Ring: "ring",
|
|
5
|
+
Pulse: "pulse"
|
|
6
|
+
};
|
|
7
|
+
var BrandStudioSection = {
|
|
8
|
+
Overview: "overview",
|
|
9
|
+
Logo: "logo",
|
|
10
|
+
Colors: "colors",
|
|
11
|
+
Typography: "typography",
|
|
12
|
+
Icons: "icons",
|
|
13
|
+
Motion: "motion",
|
|
14
|
+
Download: "download"
|
|
15
|
+
};
|
|
16
|
+
var MotionState = {
|
|
17
|
+
Idle: "idle",
|
|
18
|
+
Loading: "loading",
|
|
19
|
+
Success: "success",
|
|
20
|
+
Empty: "empty"
|
|
21
|
+
};
|
|
22
|
+
var DownloadKind = {
|
|
23
|
+
Icon: "icon",
|
|
24
|
+
Logo: "logo"
|
|
25
|
+
};
|
|
26
|
+
var DownloadMode = {
|
|
27
|
+
Light: "light",
|
|
28
|
+
Dark: "dark"
|
|
29
|
+
};
|
|
30
|
+
var DownloadFormat = {
|
|
31
|
+
Svg: "svg",
|
|
32
|
+
Png: "png"
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { BrandStudioSection, DownloadFormat, DownloadKind, DownloadMode, LoadingVariant, MotionState };
|
|
@@ -2,27 +2,6 @@
|
|
|
2
2
|
import { motion } from 'framer-motion';
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
|
-
// src/types.ts
|
|
6
|
-
var LoadingVariant = {
|
|
7
|
-
Spinner: "spinner",
|
|
8
|
-
Ring: "ring",
|
|
9
|
-
Pulse: "pulse"
|
|
10
|
-
};
|
|
11
|
-
var BrandStudioSection = {
|
|
12
|
-
Overview: "overview",
|
|
13
|
-
Logo: "logo",
|
|
14
|
-
Colors: "colors",
|
|
15
|
-
Typography: "typography",
|
|
16
|
-
Icons: "icons",
|
|
17
|
-
Motion: "motion",
|
|
18
|
-
Download: "download"
|
|
19
|
-
};
|
|
20
|
-
var MotionState = {
|
|
21
|
-
Idle: "idle",
|
|
22
|
-
Loading: "loading",
|
|
23
|
-
Success: "success",
|
|
24
|
-
Empty: "empty"
|
|
25
|
-
};
|
|
26
5
|
function SpinnerLoadingMark({
|
|
27
6
|
size = 200,
|
|
28
7
|
background = "transparent",
|
|
@@ -81,4 +60,4 @@ function SpinnerLoadingMark({
|
|
|
81
60
|
);
|
|
82
61
|
}
|
|
83
62
|
|
|
84
|
-
export {
|
|
63
|
+
export { SpinnerLoadingMark };
|
package/dist/define/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BrandConfig, R as ResolvedBrandConfig } from '../types-
|
|
2
|
-
export {
|
|
1
|
+
import { B as BrandConfig, R as ResolvedBrandConfig, D as DownloadFormat, b as BrandDownloads } from '../types-BycZ2igw.js';
|
|
2
|
+
export { a as BrandDownload, d as BrandType, e as DownloadKind, f as DownloadMode } from '../types-BycZ2igw.js';
|
|
3
3
|
export { B as BrandScheme, C as ColorScheme, a as ColorSpec, H as Hex, d as Role, S as SchemeVariant, g as generateScheme } from '../generateScheme-BDDcIzA3.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -22,4 +22,46 @@ export { B as BrandScheme, C as ColorScheme, a as ColorSpec, H as Hex, d as Role
|
|
|
22
22
|
*/
|
|
23
23
|
declare function defineBrand(config: BrandConfig): ResolvedBrandConfig;
|
|
24
24
|
|
|
25
|
-
export
|
|
25
|
+
/** Canonical icon export sizes — square pixel edges. */
|
|
26
|
+
declare const STANDARD_ICON_SIZES: readonly [64, 128, 256, 512, 1024];
|
|
27
|
+
/** Canonical logo export sizes — pixel heights. */
|
|
28
|
+
declare const STANDARD_LOGO_SIZES: readonly [32, 48, 64, 96, 128];
|
|
29
|
+
type StandardDownloadsInput = {
|
|
30
|
+
/**
|
|
31
|
+
* The brand slug embedded in every URL. Required — this is the SEO win;
|
|
32
|
+
* `/brand/app-icon/zeropost-256-light.svg` indexes far better than
|
|
33
|
+
* `/brand/light.svg`. Pass the lowercased brand name (e.g. `"zeropost"`)
|
|
34
|
+
* or any slug. Auto-slugified to lowercase ASCII + hyphens.
|
|
35
|
+
*/
|
|
36
|
+
brand: string;
|
|
37
|
+
/**
|
|
38
|
+
* Mount path the host app serves the assets under, no trailing slash.
|
|
39
|
+
* Default `/brand`. Full URL shape:
|
|
40
|
+
* `<basePath>/<kind-path>/<brand>-<size>-<mode>.<format>`
|
|
41
|
+
* Example: `/brand/app-icon/zeropost-256-light.svg`
|
|
42
|
+
* Kind paths: `app-icon` (square mark) · `logo` (wordmark).
|
|
43
|
+
*
|
|
44
|
+
* The kind segment never collides with brand-studio's own section routes
|
|
45
|
+
* (`/brand/logo`, `/brand/colors`, …) because assets are two-segment URLs
|
|
46
|
+
* (`/brand/logo/<slug>.svg`) while sections are one-segment (`/brand/logo`).
|
|
47
|
+
* The host route handler at `app/brand/[kind]/[slug]/route.ts` beats the
|
|
48
|
+
* brand-page catch-all for two-segment URLs.
|
|
49
|
+
*/
|
|
50
|
+
basePath?: string;
|
|
51
|
+
/** Icon edges in px. Default `STANDARD_ICON_SIZES`. */
|
|
52
|
+
iconSizes?: readonly number[];
|
|
53
|
+
/** Logo heights in px. Default `STANDARD_LOGO_SIZES`. */
|
|
54
|
+
logoSizes?: readonly number[];
|
|
55
|
+
/** Formats to emit per (kind, size, mode). Default `["svg"]`. */
|
|
56
|
+
formats?: readonly (typeof DownloadFormat)[keyof typeof DownloadFormat][];
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Build the canonical icon + logo × {light, dark} × sizes × formats matrix.
|
|
60
|
+
* Every brand-studio consumer ships this (or a superset) so users always have
|
|
61
|
+
* shareable, SEO-friendly URLs to the brand marks.
|
|
62
|
+
*/
|
|
63
|
+
declare function buildStandardDownloads(input: StandardDownloadsInput): BrandDownloads;
|
|
64
|
+
/** Lowercase ASCII, replace non-alphanumeric with hyphens, collapse + trim. */
|
|
65
|
+
declare function slugify(input: string): string;
|
|
66
|
+
|
|
67
|
+
export { BrandConfig, BrandDownloads, DownloadFormat, ResolvedBrandConfig, STANDARD_ICON_SIZES, STANDARD_LOGO_SIZES, type StandardDownloadsInput, buildStandardDownloads, defineBrand, slugify };
|
package/dist/define/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { defineBrand } from '../chunk-
|
|
1
|
+
export { STANDARD_ICON_SIZES, STANDARD_LOGO_SIZES, buildStandardDownloads, defineBrand, slugify } from '../chunk-6J2NFZLN.js';
|
|
2
|
+
export { DownloadFormat, DownloadKind, DownloadMode } from '../chunk-MDTU2JR5.js';
|
|
2
3
|
export { SchemeVariant, generateScheme } from '../chunk-JQV3ASME.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export { Disc, DiscProps, Ring, RingProps, Squircle, SquircleProps } from './shapes/index.js';
|
|
2
2
|
export { AppearGrow, AppearGrowProps, Drift, DriftProps, PulseLoop, PulseLoopProps, RingDraw, RingDrawProps, Sequence, SequenceProps, SequenceStep, SequenceStepProps, Strikethrough, StrikethroughProps, Sweep, SweepDirection, SweepProps, Wobble, WobbleProps } from './motion/index.js';
|
|
3
3
|
export { LoadingMark, LoadingMarkProps, PulseLoadingMark, PulseLoadingMarkProps, RingLoadingMark, RingLoadingMarkProps, SpinnerLoadingMark, SpinnerLoadingMarkProps } from './loading/index.js';
|
|
4
|
-
export { B as BrandConfig, a as
|
|
4
|
+
export { B as BrandConfig, a as BrandDownload, b as BrandDownloads, c as BrandStudioSection, d as BrandType, D as DownloadFormat, e as DownloadKind, f as DownloadMode, L as LoadingVariant, M as MotionState, R as ResolvedBrandConfig } from './types-BycZ2igw.js';
|
|
5
5
|
export { B as BrandScheme, C as ColorScheme, a as ColorSpec, H as Hex, R as ROLE, b as ROLE_GROUPS, c as ROLE_ORDER, d as Role, S as SchemeVariant, g as generateScheme } from './generateScheme-BDDcIzA3.js';
|
|
6
6
|
export { cssVarName, schemeToCssText, schemeVars } from './color/index.js';
|
|
7
7
|
export { C as ContrastTier, c as contrastBadge, a as contrastRatio, r as relativeLuminance } from './contrast-TVW3pzdd.js';
|
|
8
|
-
export { a as BrandStudio, b as BrandStudioProps } from './BrandStudio-
|
|
9
|
-
export { defineBrand } from './define/index.js';
|
|
8
|
+
export { a as BrandStudio, b as BrandStudioProps } from './BrandStudio-D1QR4hIC.js';
|
|
9
|
+
export { STANDARD_ICON_SIZES, STANDARD_LOGO_SIZES, StandardDownloadsInput, buildStandardDownloads, defineBrand, slugify } from './define/index.js';
|
|
10
10
|
import 'react/jsx-runtime';
|
|
11
11
|
import 'react';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
export { Disc, Ring, Squircle } from './chunk-LJ4HZCAP.js';
|
|
3
3
|
export { AppearGrow, Drift, PulseLoop, RingDraw, Sequence, SequenceStep, Strikethrough, Sweep, Wobble } from './chunk-7325RQRP.js';
|
|
4
|
-
export { LoadingMark, PulseLoadingMark, RingLoadingMark } from './chunk-
|
|
5
|
-
export { BrandStudio } from './chunk-
|
|
6
|
-
export {
|
|
7
|
-
export { defineBrand } from './chunk-
|
|
4
|
+
export { LoadingMark, PulseLoadingMark, RingLoadingMark } from './chunk-F4CFQDS7.js';
|
|
5
|
+
export { BrandStudio } from './chunk-L4FQAO3K.js';
|
|
6
|
+
export { SpinnerLoadingMark } from './chunk-YDZA26YU.js';
|
|
7
|
+
export { STANDARD_ICON_SIZES, STANDARD_LOGO_SIZES, buildStandardDownloads, defineBrand, slugify } from './chunk-6J2NFZLN.js';
|
|
8
|
+
export { BrandStudioSection, DownloadFormat, DownloadKind, DownloadMode, LoadingVariant, MotionState } from './chunk-MDTU2JR5.js';
|
|
8
9
|
export { ContrastTier, ROLE, ROLE_GROUPS, ROLE_ORDER, SchemeVariant, contrastBadge, contrastRatio, cssVarName, generateScheme, relativeLuminance, schemeToCssText, schemeVars } from './chunk-JQV3ASME.js';
|
package/dist/loading/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode, CSSProperties } from 'react';
|
|
3
|
-
import { L as LoadingVariant } from '../types-
|
|
3
|
+
import { L as LoadingVariant } from '../types-BycZ2igw.js';
|
|
4
4
|
import '../generateScheme-BDDcIzA3.js';
|
|
5
5
|
|
|
6
6
|
type LoadingMarkProps = {
|
package/dist/loading/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { LoadingMark, PulseLoadingMark, RingLoadingMark } from '../chunk-
|
|
3
|
-
export {
|
|
2
|
+
export { LoadingMark, PulseLoadingMark, RingLoadingMark } from '../chunk-F4CFQDS7.js';
|
|
3
|
+
export { SpinnerLoadingMark } from '../chunk-YDZA26YU.js';
|
|
4
|
+
export { LoadingVariant } from '../chunk-MDTU2JR5.js';
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { a as ColorSpec, B as BrandScheme } from './generateScheme-BDDcIzA3.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared types for @021.is/brand-studio.
|
|
5
|
+
*
|
|
6
|
+
* Const-as-object enums (no inline string-literal unions in public signatures).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Generic loading-mark variants. No brand-coded marks live in the lib. */
|
|
10
|
+
declare const LoadingVariant: {
|
|
11
|
+
readonly Spinner: "spinner";
|
|
12
|
+
readonly Ring: "ring";
|
|
13
|
+
readonly Pulse: "pulse";
|
|
14
|
+
};
|
|
15
|
+
type LoadingVariant = (typeof LoadingVariant)[keyof typeof LoadingVariant];
|
|
16
|
+
declare const BrandStudioSection: {
|
|
17
|
+
readonly Overview: "overview";
|
|
18
|
+
readonly Logo: "logo";
|
|
19
|
+
readonly Colors: "colors";
|
|
20
|
+
readonly Typography: "typography";
|
|
21
|
+
readonly Icons: "icons";
|
|
22
|
+
readonly Motion: "motion";
|
|
23
|
+
readonly Download: "download";
|
|
24
|
+
};
|
|
25
|
+
type BrandStudioSection = (typeof BrandStudioSection)[keyof typeof BrandStudioSection];
|
|
26
|
+
declare const MotionState: {
|
|
27
|
+
readonly Idle: "idle";
|
|
28
|
+
readonly Loading: "loading";
|
|
29
|
+
readonly Success: "success";
|
|
30
|
+
readonly Empty: "empty";
|
|
31
|
+
};
|
|
32
|
+
type MotionState = (typeof MotionState)[keyof typeof MotionState];
|
|
33
|
+
/**
|
|
34
|
+
* Mandatory download contract — every brand-studio consumer SHOULD expose its
|
|
35
|
+
* app icon + logo at multiple sizes, in both light- and dark-surface variants,
|
|
36
|
+
* as shareable URLs. The lib renders them as a link grid on `/brand/download`.
|
|
37
|
+
*
|
|
38
|
+
* Host apps wire `BrandConfig.downloads` to a route handler (or static files)
|
|
39
|
+
* that returns the asset. Use `buildStandardDownloads(basePath)` for the
|
|
40
|
+
* canonical 5×2×2 matrix.
|
|
41
|
+
*/
|
|
42
|
+
declare const DownloadKind: {
|
|
43
|
+
readonly Icon: "icon";
|
|
44
|
+
readonly Logo: "logo";
|
|
45
|
+
};
|
|
46
|
+
type DownloadKind = (typeof DownloadKind)[keyof typeof DownloadKind];
|
|
47
|
+
declare const DownloadMode: {
|
|
48
|
+
readonly Light: "light";
|
|
49
|
+
readonly Dark: "dark";
|
|
50
|
+
};
|
|
51
|
+
type DownloadMode = (typeof DownloadMode)[keyof typeof DownloadMode];
|
|
52
|
+
declare const DownloadFormat: {
|
|
53
|
+
readonly Svg: "svg";
|
|
54
|
+
readonly Png: "png";
|
|
55
|
+
};
|
|
56
|
+
type DownloadFormat = (typeof DownloadFormat)[keyof typeof DownloadFormat];
|
|
57
|
+
type BrandDownload = {
|
|
58
|
+
kind: DownloadKind;
|
|
59
|
+
mode: DownloadMode;
|
|
60
|
+
/** Pixel size — square edge for icons, height for logos. */
|
|
61
|
+
size: number;
|
|
62
|
+
/** Asset format. SVG is the canonical export; PNG is optional raster. */
|
|
63
|
+
format: DownloadFormat;
|
|
64
|
+
/** Absolute or root-relative URL the host app serves. */
|
|
65
|
+
url: string;
|
|
66
|
+
/**
|
|
67
|
+
* Filename the user should see when downloading. Used as the
|
|
68
|
+
* `<a download="…">` attribute. Defaults to the URL's last segment.
|
|
69
|
+
*/
|
|
70
|
+
filename?: string;
|
|
71
|
+
/** Optional override for the link label. */
|
|
72
|
+
label?: string;
|
|
73
|
+
};
|
|
74
|
+
type BrandDownloads = {
|
|
75
|
+
/** Linear list of download entries. Order is preserved for the link grid. */
|
|
76
|
+
items: readonly BrandDownload[];
|
|
77
|
+
};
|
|
78
|
+
type BrandType = {
|
|
79
|
+
sans: string;
|
|
80
|
+
mono?: string;
|
|
81
|
+
serif?: string;
|
|
82
|
+
};
|
|
83
|
+
type BrandConfig = {
|
|
84
|
+
/** Brand display name, shown on the overview + exports. */
|
|
85
|
+
name: string;
|
|
86
|
+
/** Short tagline shown on the brand-kit overview. */
|
|
87
|
+
tagline?: string;
|
|
88
|
+
/** Operator legal entity, shown in the brand-kit footer. */
|
|
89
|
+
operator?: string;
|
|
90
|
+
/** Domain (used for "view live" links). */
|
|
91
|
+
domain?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Color spec — a seed (+ optional key colors / overrides) the MD3 engine
|
|
94
|
+
* derives a complete light + dark role set from. See `defineBrand`.
|
|
95
|
+
*/
|
|
96
|
+
color: ColorSpec;
|
|
97
|
+
type: BrandType;
|
|
98
|
+
/** Voice rules, rendered as a bullet list. */
|
|
99
|
+
voice?: readonly string[];
|
|
100
|
+
/**
|
|
101
|
+
* Download URL contract — icon + logo at multiple sizes × {light, dark}.
|
|
102
|
+
* Rendered as a link grid under `/brand/download`. Use
|
|
103
|
+
* `buildStandardDownloads(basePath)` for the canonical matrix or supply
|
|
104
|
+
* explicit entries. When absent, the Download section falls back to
|
|
105
|
+
* on-click SVG-blob generation (legacy behaviour).
|
|
106
|
+
*/
|
|
107
|
+
downloads?: BrandDownloads;
|
|
108
|
+
/**
|
|
109
|
+
* Resolved MD3 light + dark role sets. Populated by `defineBrand`; do not set
|
|
110
|
+
* by hand. Sections read it (and the injected `--md-*` CSS vars) for theming.
|
|
111
|
+
*/
|
|
112
|
+
scheme?: BrandScheme;
|
|
113
|
+
};
|
|
114
|
+
/** A `BrandConfig` after `defineBrand` has resolved its `scheme`. */
|
|
115
|
+
type ResolvedBrandConfig = BrandConfig & {
|
|
116
|
+
scheme: BrandScheme;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export { type BrandConfig as B, DownloadFormat as D, LoadingVariant as L, MotionState as M, type ResolvedBrandConfig as R, type BrandDownload as a, type BrandDownloads as b, BrandStudioSection as c, type BrandType as d, DownloadKind as e, DownloadMode as f };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@021.is/brand-studio",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Generic MD3 brand-kit toolkit: seed → full light + dark role set, composable SVG shapes + motion + loading marks,
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "Generic MD3 brand-kit toolkit: seed → full light + dark role set, composable SVG shapes + motion + loading marks, mountable <BrandStudio> /brand page, mandatory icon + logo download-URL contract. Ships no brand content — every app supplies its own logo, icons, and seed colour.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "edvone",
|
package/dist/chunk-QT5N4K7D.js
DELETED
package/dist/types-PWNYyaBF.d.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { a as ColorSpec, B as BrandScheme } from './generateScheme-BDDcIzA3.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Shared types for @021.is/brand-studio.
|
|
5
|
-
*
|
|
6
|
-
* Const-as-object enums (no inline string-literal unions in public signatures).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/** Generic loading-mark variants. No brand-coded marks live in the lib. */
|
|
10
|
-
declare const LoadingVariant: {
|
|
11
|
-
readonly Spinner: "spinner";
|
|
12
|
-
readonly Ring: "ring";
|
|
13
|
-
readonly Pulse: "pulse";
|
|
14
|
-
};
|
|
15
|
-
type LoadingVariant = (typeof LoadingVariant)[keyof typeof LoadingVariant];
|
|
16
|
-
declare const BrandStudioSection: {
|
|
17
|
-
readonly Overview: "overview";
|
|
18
|
-
readonly Logo: "logo";
|
|
19
|
-
readonly Colors: "colors";
|
|
20
|
-
readonly Typography: "typography";
|
|
21
|
-
readonly Icons: "icons";
|
|
22
|
-
readonly Motion: "motion";
|
|
23
|
-
readonly Download: "download";
|
|
24
|
-
};
|
|
25
|
-
type BrandStudioSection = (typeof BrandStudioSection)[keyof typeof BrandStudioSection];
|
|
26
|
-
declare const MotionState: {
|
|
27
|
-
readonly Idle: "idle";
|
|
28
|
-
readonly Loading: "loading";
|
|
29
|
-
readonly Success: "success";
|
|
30
|
-
readonly Empty: "empty";
|
|
31
|
-
};
|
|
32
|
-
type MotionState = (typeof MotionState)[keyof typeof MotionState];
|
|
33
|
-
type BrandType = {
|
|
34
|
-
sans: string;
|
|
35
|
-
mono?: string;
|
|
36
|
-
serif?: string;
|
|
37
|
-
};
|
|
38
|
-
type BrandConfig = {
|
|
39
|
-
/** Brand display name, shown on the overview + exports. */
|
|
40
|
-
name: string;
|
|
41
|
-
/** Short tagline shown on the brand-kit overview. */
|
|
42
|
-
tagline?: string;
|
|
43
|
-
/** Operator legal entity, shown in the brand-kit footer. */
|
|
44
|
-
operator?: string;
|
|
45
|
-
/** Domain (used for "view live" links). */
|
|
46
|
-
domain?: string;
|
|
47
|
-
/**
|
|
48
|
-
* Color spec — a seed (+ optional key colors / overrides) the MD3 engine
|
|
49
|
-
* derives a complete light + dark role set from. See `defineBrand`.
|
|
50
|
-
*/
|
|
51
|
-
color: ColorSpec;
|
|
52
|
-
type: BrandType;
|
|
53
|
-
/** Voice rules, rendered as a bullet list. */
|
|
54
|
-
voice?: readonly string[];
|
|
55
|
-
/**
|
|
56
|
-
* Resolved MD3 light + dark role sets. Populated by `defineBrand`; do not set
|
|
57
|
-
* by hand. Sections read it (and the injected `--md-*` CSS vars) for theming.
|
|
58
|
-
*/
|
|
59
|
-
scheme?: BrandScheme;
|
|
60
|
-
};
|
|
61
|
-
/** A `BrandConfig` after `defineBrand` has resolved its `scheme`. */
|
|
62
|
-
type ResolvedBrandConfig = BrandConfig & {
|
|
63
|
-
scheme: BrandScheme;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export { type BrandConfig as B, LoadingVariant as L, MotionState as M, type ResolvedBrandConfig as R, BrandStudioSection as a, type BrandType as b };
|