@brunosouzas/design-system 0.1.0 → 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/README.md CHANGED
@@ -90,7 +90,7 @@ npm run stills -- publish-subscribe # 24 phase/final PNGs (six per
90
90
  npm run stills -- publish-subscribe --dry-run # print 24 commands, no effects
91
91
  npm run render -- publish-subscribe --dry-run # print eight commands; real video waits for owner stills approval
92
92
  npm run build # compile the package into dist/ (the package test needs it)
93
- npm run cover -- cover.json --out card.svg # build a blog cover from its spec
93
+ npm run cover -- cover.json --out card.svg # build a blog cover (or a banner) from its spec
94
94
  npm run pieces:sheet -- --out out/pieces.svg # every piece once, labelled, for review
95
95
  npm run studio # Remotion Studio, for frame-by-frame review
96
96
  ```
@@ -130,7 +130,7 @@ The components take every colour and size from the tokens, and what is visible a
130
130
 
131
131
  - `toSvg(node)` writes a tree as SVG text; `toReact(node)` turns the same tree into React elements. Both describe the same elements, attributes and text, which the tests check.
132
132
  - `pose(node, { x, y, tilt, squash, hop, scale, shake, opacity })` animates any piece around its base point; a scene recomputes the numbers every frame.
133
- - Every colour parameter is a token path (`"color.healthy"`, `"illustration.accent"`), never a hex value, except the two line fills of the map pieces below. Each piece checks its parameters before drawing and names the first wrong one.
133
+ - Every colour parameter is a token path (`"color.healthy"`, `"illustration.accent"`), never a hex value, except the two line fills of the map pieces below. Each piece checks its parameters before drawing and names the first wrong one. Positions and points take any finite number, because a map has no edge; sizes stay within 10000. A drawing that would hold a non-finite number throws `<piece>: the drawing overflows`.
134
134
  - The 35 pieces, with their anchors, parameters and defaults, are listed in [design §4](openspec/changes/archive/2026-10-23-illustration-pieces/design.md) (the 26 cover pieces) and in [design §3](openspec/changes/archive/2026-10-23-metro-and-diagram-pieces/design.md) of `metro-and-diagram-pieces` (the nine below); the rules are in [`openspec/specs/illustration-pieces/`](openspec/specs/illustration-pieces/spec.md). `npm run pieces:sheet -- --out <file.svg>` draws them all.
135
135
 
136
136
  ### Maps and diagrams
@@ -151,7 +151,7 @@ const badge = lineBadge({ x: 250, y: 40, text: "SH", fill: "#7B3FE4", surface: "
151
151
 
152
152
  ### A cover
153
153
 
154
- A cover is a JSON spec kept with its article, outside this repository: drafts are private, and only the pieces are public. `npm run cover -- <spec.json> --out <file.svg>` validates it, reports every problem with its JSON path, and writes an 800x420 SVG; the same spec always gives the same bytes.
154
+ A cover is a JSON spec kept with its article, outside this repository: drafts are private, and only the pieces are public. `npm run cover -- <spec.json> --out <file.svg>` validates it, reports every problem with its JSON path, and writes an 800x420 SVG; the same spec always gives the same bytes. With `"format": "banner"` the same command writes a site banner instead (see below).
155
155
 
156
156
  ```json
157
157
  {
@@ -169,9 +169,19 @@ A cover is a JSON spec kept with its article, outside this repository: drafts ar
169
169
 
170
170
  - `background` names one of the 21 pairs in `coverBackground` (a background and its ring colour, measured from the published covers). Each pair is used by one cover only.
171
171
  - `pieces` are drawn in order; their words go on top.
172
+ - The `rings` centre stays within ±10000 in a cover spec, and a piece that overflows is reported at its entry (`pieces[1]: the drawing overflows`).
172
173
  - `custom` (optional) is the cover's one free-form object, a JSON node tree limited to drawing tags and a fixed list of attributes, with no external references. An object that repeats becomes a piece instead.
173
174
  - The three published covers that proved the pieces are the test fixtures in `test/fixtures/covers/`.
174
175
 
176
+ ### Banners
177
+
178
+ A spec with `"format": "banner"` (the default is `"cover"`) builds a home banner for a site: `banner.width` x `banner.height` (1200x420) with corners rounded at `banner.radius` (20), the measures of brunosouzas.com's published banner. Same pieces, validation and command. Two things differ from a cover:
179
+
180
+ - the rings go on until they reach the frame's farthest corner (22 rings for a centre at 600, 225 with radius 60), where a cover draws 14;
181
+ - pieces and labels are clipped to the rounded frame too, so nothing pokes past a corner.
182
+
183
+ The banner is one image that scales down as a whole. Words in it become small on a phone (a 19px label is about 6px at 375px wide), so keep them few or none. `test/fixtures/covers/home-banner.json` is the brunosouzas.com home banner redrawn from the pieces.
184
+
175
185
  ### A new piece
176
186
 
177
187
  Add it to `src/pieces/library.ts` (or `src/pieces/metro.ts` for a map or diagram piece) with `definePiece(name, schema, draw)`, take its colours and sizes from the tokens (a new colour goes to `tokens/source.json` first), register it in `PIECES`, and give it a sample in `scripts/pieces-sheet.ts`. The catalogue test then checks that it draws with only its required parameters and uses token colours only.
@@ -2,6 +2,9 @@ import { type PieceName } from "./library.ts";
2
2
  import { type SvgNode } from "./node.ts";
3
3
  import { type Problem } from "./params.ts";
4
4
  export declare const SAFE_ID: RegExp;
5
+ /** Cover (800x420, the default) or banner (1200x420, rounded corners): spec cover-cli, "Banner output". */
6
+ export declare const FORMATS: readonly ["cover", "banner"];
7
+ export type CoverFormat = (typeof FORMATS)[number];
5
8
  export type CoverPiece = {
6
9
  piece: PieceName;
7
10
  } & Record<string, unknown>;
@@ -14,6 +17,7 @@ export type CoverSpec = {
14
17
  id: string;
15
18
  title: string;
16
19
  description: string;
20
+ format?: CoverFormat;
17
21
  background: string;
18
22
  rings: {
19
23
  cx: number;
@@ -28,5 +32,7 @@ export declare const backgroundNames: () => string[];
28
32
  export declare const comparePaths: (a: string, b: string) => number;
29
33
  /** Every problem of a parsed spec, sorted by path; empty when the spec is valid. */
30
34
  export declare const validateCoverSpec: (spec: unknown) => Problem[];
31
- /** The cover's node tree. The spec must be valid (validateCoverSpec returned no problem). */
35
+ /** Rings a banner draws: out to the frame's farthest corner (spec cover-cli, "Banner rings reach the corners"). */
36
+ export declare const bannerRingCount: (cx: number, cy: number, radius?: number) => number;
37
+ /** The cover's (or banner's) node tree. The spec must be valid (validateCoverSpec returned no problem). */
32
38
  export declare const coverTree: (spec: CoverSpec) => SvgNode;
@@ -10,9 +10,11 @@
10
10
  import { tokens } from "../../tokens/generated/tokens.js";
11
11
  import { PIECE_NAMES, PIECES, rings } from "./library.js";
12
12
  import { el, g } from "./node.js";
13
- import { COLOUR_TOKENS, checkParams, isColourLiteral, PATH_DATA } from "./params.js";
13
+ import { COLOUR_TOKENS, checkParams, isColourLiteral, MAX_SIZE, PATH_DATA } from "./params.js";
14
14
  export const SAFE_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
15
- const TOP_LEVEL = ["id", "title", "description", "background", "rings", "pieces", "custom"];
15
+ const TOP_LEVEL = ["id", "title", "description", "format", "background", "rings", "pieces", "custom"];
16
+ /** Cover (800x420, the default) or banner (1200x420, rounded corners): spec cover-cli, "Banner output". */
17
+ export const FORMATS = ["cover", "banner"];
16
18
  const CUSTOM_TAGS = ["g", "rect", "circle", "ellipse", "line", "polyline", "polygon", "path", "text"];
17
19
  // Attributes a free-form object may use (design §6): geometry, paint, text and transform.
18
20
  const CUSTOM_ATTRS = new Set([
@@ -153,10 +155,27 @@ export const validateCoverSpec = (spec) => {
153
155
  }
154
156
  if (!isPlainObject(spec.rings))
155
157
  out.push({ path: "rings", message: "missing or not an object (expected cx, cy and an optional radius)" });
156
- else
157
- out.push(...checkParams(rings.schema, spec.rings, "rings").filter((problem) => problem.path !== "rings.color"));
158
+ else {
159
+ const ringProblems = checkParams(rings.schema, spec.rings, "rings").filter((problem) => problem.path !== "rings.color" && problem.path !== "rings.count");
160
+ out.push(...ringProblems);
161
+ // The piece takes any finite centre; a cover spec keeps 0.1.0's ±10000, which bounds a banner's ring count.
162
+ for (const axis of ["cx", "cy"]) {
163
+ const value = spec.rings[axis];
164
+ if (ringProblems.some((p) => p.path === `rings.${axis}`) || typeof value !== "number")
165
+ continue;
166
+ if (value < -MAX_SIZE)
167
+ out.push({ path: `rings.${axis}`, message: `expected a number at least -${MAX_SIZE}, found ${value}` });
168
+ else if (value > MAX_SIZE)
169
+ out.push({ path: `rings.${axis}`, message: `expected a number at most ${MAX_SIZE}, found ${value}` });
170
+ }
171
+ }
158
172
  if (isPlainObject(spec.rings) && Object.hasOwn(spec.rings, "color"))
159
173
  out.push({ path: "rings.color", message: "unknown parameter: the ring colour comes from the background" });
174
+ if (isPlainObject(spec.rings) && Object.hasOwn(spec.rings, "count"))
175
+ out.push({ path: "rings.count", message: "unknown parameter: the ring count comes from the format" });
176
+ if (spec.format !== undefined && (typeof spec.format !== "string" || !FORMATS.includes(spec.format))) {
177
+ out.push({ path: "format", message: `expected one of ${FORMATS.join(", ")}` });
178
+ }
160
179
  if (!Array.isArray(spec.pieces))
161
180
  out.push({ path: "pieces", message: "missing or not an array" });
162
181
  else
@@ -186,6 +205,16 @@ export const validateCoverSpec = (spec) => {
186
205
  const reported = new Set(own.map((problem) => problem.path));
187
206
  out.push(...related.map((problem) => ({ path: `${at}.${problem.path}`, message: problem.message })).filter((problem) => !reported.has(problem.path)));
188
207
  }
208
+ // A valid entry is drawn once: an overflow is a spec problem at the entry, not a crash.
209
+ if (own.length === 0 && !(definition.relations?.(params) ?? []).length) {
210
+ try {
211
+ PIECES[piece](params);
212
+ }
213
+ catch (error) {
214
+ if (error instanceof RangeError && error.message.endsWith(": the drawing overflows"))
215
+ out.push({ path: at, message: "the drawing overflows" });
216
+ }
217
+ }
189
218
  });
190
219
  if (spec.custom !== undefined) {
191
220
  if (Array.isArray(spec.custom))
@@ -232,12 +261,25 @@ const resolveCustom = (node) => {
232
261
  attrs.stroke = "none";
233
262
  return el(node.tag, attrs, ...(node.children ?? []).map((child) => (typeof child === "string" ? child : resolveCustom(child))));
234
263
  };
235
- /** The cover's node tree. The spec must be valid (validateCoverSpec returned no problem). */
264
+ /** Rings a banner draws: out to the frame's farthest corner (spec cover-cli, "Banner rings reach the corners"). */
265
+ export const bannerRingCount = (cx, cy, radius = tokens.cover.ringRadius) => {
266
+ const { width, height } = tokens.banner;
267
+ const far = Math.max(...[[0, 0], [width, 0], [0, height], [width, height]].map(([x, y]) => Math.hypot(x - cx, y - cy)));
268
+ return Math.max(1, Math.ceil((far - radius) / tokens.cover.ringStep) + 1);
269
+ };
270
+ /** The cover's (or banner's) node tree. The spec must be valid (validateCoverSpec returned no problem). */
236
271
  export const coverTree = (spec) => {
237
- const { width, height } = tokens.cover;
272
+ const banner = spec.format === "banner";
273
+ const { width, height } = banner ? tokens.banner : tokens.cover;
274
+ // A banner's corners are rounded; a cover keeps today's square frame, attribute for attribute.
275
+ const corner = banner ? { rx: tokens.banner.radius } : {};
238
276
  const pair = tokens.coverBackground[spec.background];
239
277
  const drawnPieces = spec.pieces.map(({ piece, ...params }) => PIECES[piece](params));
240
278
  const ringPath = `coverBackground.${spec.background}.ring`;
279
+ const ringCount = banner ? { count: bannerRingCount(spec.rings.cx, spec.rings.cy, spec.rings.radius) } : {};
280
+ const frame = `url(#${spec.id}-frame)`;
281
+ const outlined = g({ stroke: tokens.color.ink, "stroke-width": tokens.outline.block, "stroke-linejoin": "round" }, ...drawnPieces.flatMap((d) => d.body), spec.custom ? resolveCustom(spec.custom) : null);
282
+ const labels = g({ "font-size": tokens.cover.labelSize, "font-weight": tokens.cover.labelWeight, fill: tokens.color.ink, "text-anchor": "middle" }, ...drawnPieces.flatMap((d) => d.text));
241
283
  return el("svg", {
242
284
  xmlns: "http://www.w3.org/2000/svg",
243
285
  width,
@@ -246,5 +288,7 @@ export const coverTree = (spec) => {
246
288
  role: "img",
247
289
  "aria-labelledby": `${spec.id}-title ${spec.id}-desc`,
248
290
  "font-family": tokens.font.sans,
249
- }, el("title", { id: `${spec.id}-title` }, spec.title), el("desc", { id: `${spec.id}-desc` }, spec.description), el("defs", {}, el("clipPath", { id: `${spec.id}-frame` }, el("rect", { width, height }))), el("rect", { width, height, fill: pair.fill }), g({ "clip-path": `url(#${spec.id}-frame)` }, ...rings({ ...spec.rings, color: ringPath }).body), g({ stroke: tokens.color.ink, "stroke-width": tokens.outline.block, "stroke-linejoin": "round" }, ...drawnPieces.flatMap((d) => d.body), spec.custom ? resolveCustom(spec.custom) : null), g({ "font-size": tokens.cover.labelSize, "font-weight": tokens.cover.labelWeight, fill: tokens.color.ink, "text-anchor": "middle" }, ...drawnPieces.flatMap((d) => d.text)));
291
+ }, el("title", { id: `${spec.id}-title` }, spec.title), el("desc", { id: `${spec.id}-desc` }, spec.description), el("defs", {}, el("clipPath", { id: `${spec.id}-frame` }, el("rect", { width, height, ...corner }))), el("rect", { width, height, ...corner, fill: pair.fill }), g({ "clip-path": frame }, ...rings({ ...spec.rings, color: ringPath, ...ringCount }).body),
292
+ // On a banner, pieces and labels are clipped too, so nothing pokes past a rounded corner.
293
+ ...(banner ? [g({ "clip-path": frame }, outlined, labels)] : [outlined, labels]));
250
294
  };
@@ -5,5 +5,5 @@ export { COLOUR_TOKENS, DATA_COLOUR, MAX_ITEMS, paint, MAX_SIZE, checkParams, co
5
5
  export { definePiece, type Piece } from "./piece.ts";
6
6
  export * from "./library.ts";
7
7
  export { EIP_ICONS, EIP_ICON_NAMES, EIP_ICON_HEIGHT, EIP_ICON_WIDTH, type EipIcon } from "./eip-icons.ts";
8
- export { SAFE_ID, backgroundNames, comparePaths, coverTree, validateCoverSpec, type CoverPiece, type CoverSpec, type CustomNode } from "./cover.ts";
8
+ export { FORMATS, SAFE_ID, backgroundNames, bannerRingCount, comparePaths, coverTree, validateCoverSpec, type CoverFormat, type CoverPiece, type CoverSpec, type CustomNode } from "./cover.ts";
9
9
  export { tokens, type Tokens } from "../../tokens/generated/tokens.ts";
@@ -10,5 +10,5 @@ export { COLOUR_TOKENS, DATA_COLOUR, MAX_ITEMS, paint, MAX_SIZE, checkParams, co
10
10
  export { definePiece } from "./piece.js";
11
11
  export * from "./library.js";
12
12
  export { EIP_ICONS, EIP_ICON_NAMES, EIP_ICON_HEIGHT, EIP_ICON_WIDTH } from "./eip-icons.js";
13
- export { SAFE_ID, backgroundNames, comparePaths, coverTree, validateCoverSpec } from "./cover.js";
13
+ export { FORMATS, SAFE_ID, backgroundNames, bannerRingCount, comparePaths, coverTree, validateCoverSpec } from "./cover.js";
14
14
  export { tokens } from "../../tokens/generated/tokens.js";
@@ -10,13 +10,16 @@ export type PillParams = {
10
10
  /** Pill label centred on (x, y), usually overlapping the top edge of what it names. */
11
11
  export declare const pill: import("./piece.ts").Piece<PillParams>;
12
12
  export declare const RING_COUNT = 14;
13
+ /** Most rings one call draws: enough for a banner's farthest corner from any centre a cover spec accepts (548). */
14
+ export declare const MAX_RINGS = 1000;
13
15
  export type RingsParams = {
14
16
  cx: number;
15
17
  cy: number;
16
18
  radius?: number;
17
19
  color?: string;
20
+ count?: number;
18
21
  };
19
- /** Concentric rings around (cx, cy): 14 rings, step and width from the cover tokens. */
22
+ /** Concentric rings around (cx, cy): `count` rings (14 by default), step and width from the cover tokens. */
20
23
  export declare const rings: import("./piece.ts").Piece<RingsParams>;
21
24
  export type SheetRow = {
22
25
  lead?: "none" | "checkbox" | "checked" | "question";
@@ -23,9 +23,11 @@ export const pill = definePiece("pill", { x: pos(), y: pos(), text: label(), fil
23
23
  });
24
24
  // ---------- background ----------
25
25
  export const RING_COUNT = 14;
26
- /** Concentric rings around (cx, cy): 14 rings, step and width from the cover tokens. */
27
- export const rings = definePiece("rings", { cx: pos(), cy: pos(), radius: size(), color: col() }, ({ cx, cy, radius = tokens.cover.ringRadius, color = "color.ring" }) => drawn([
28
- g({ fill: "none", stroke: colour(color, "color"), "stroke-width": tokens.cover.ringWidth }, ...Array.from({ length: RING_COUNT }, (_, i) => el("circle", { cx, cy, r: radius + i * tokens.cover.ringStep }))),
26
+ /** Most rings one call draws: enough for a banner's farthest corner from any centre a cover spec accepts (548). */
27
+ export const MAX_RINGS = 1000;
28
+ /** Concentric rings around (cx, cy): `count` rings (14 by default), step and width from the cover tokens. */
29
+ export const rings = definePiece("rings", { cx: pos(), cy: pos(), radius: size(), color: col(), count: count(1, MAX_RINGS) }, ({ cx, cy, radius = tokens.cover.ringRadius, color = "color.ring", count: rings = RING_COUNT }) => drawn([
30
+ g({ fill: "none", stroke: colour(color, "color"), "stroke-width": tokens.cover.ringWidth }, ...Array.from({ length: rings }, (_, i) => el("circle", { cx, cy, r: radius + i * tokens.cover.ringStep }))),
29
31
  ]));
30
32
  const rowSchema = {
31
33
  lead: { kind: "enum", values: ["none", "checkbox", "checked", "question"] },
@@ -61,7 +61,7 @@ export declare const assertParams: (piece: string, schema: Schema, params: Recor
61
61
  export declare const num: (extra?: Omit<Extract<ParamSpec, {
62
62
  kind: "number";
63
63
  }>, "kind">) => ParamSpec;
64
- /** Largest size or coordinate magnitude a piece accepts, far above any banner. */
64
+ /** Largest size a piece accepts, far above any banner. Positions and points have no bound. */
65
65
  export declare const MAX_SIZE = 10000;
66
66
  /** Most items in any list parameter (rows, lines, nodes, tiles). */
67
67
  export declare const MAX_ITEMS = 50;
@@ -69,6 +69,7 @@ export declare const MAX_ITEMS = 50;
69
69
  export declare const count: (min: number, max: number) => ParamSpec;
70
70
  /** A size: greater than 0 (or at least `min`, where fixed insets need room), at most MAX_SIZE. */
71
71
  export declare const size: (required?: boolean, min?: number) => ParamSpec;
72
+ /** A position: any finite number, because a map position has no maximum. */
72
73
  export declare const pos: () => ParamSpec;
73
74
  export declare const col: () => ParamSpec;
74
75
  /** SVG path data: commands, digits, signs, dots, commas and spaces only. */
@@ -86,8 +86,9 @@ const checkValue = (spec, value, path, out) => {
86
86
  return report(`expected true or false, found ${describe(value)}`);
87
87
  return;
88
88
  case "point":
89
- if (!Array.isArray(value) || value.length !== 2 || !value.every((n) => typeof n === "number" && Number.isFinite(n) && Math.abs(n) <= MAX_SIZE)) {
90
- return report(`expected a point [x, y] of finite numbers within ±${MAX_SIZE}, found ${describe(value)}`);
89
+ // Any finite number: a map position has no maximum (spec illustration-pieces, "Positions of any size").
90
+ if (!Array.isArray(value) || value.length !== 2 || !value.every((n) => typeof n === "number" && Number.isFinite(n))) {
91
+ return report(`expected a point [x, y] of finite numbers, found ${describe(value)}`);
91
92
  }
92
93
  return;
93
94
  case "array":
@@ -132,7 +133,7 @@ export const assertParams = (piece, schema, params) => {
132
133
  };
133
134
  // Shorthands for schemas.
134
135
  export const num = (extra = {}) => ({ kind: "number", ...extra });
135
- /** Largest size or coordinate magnitude a piece accepts, far above any banner. */
136
+ /** Largest size a piece accepts, far above any banner. Positions and points have no bound. */
136
137
  export const MAX_SIZE = 10000;
137
138
  /** Most items in any list parameter (rows, lines, nodes, tiles). */
138
139
  export const MAX_ITEMS = 50;
@@ -140,7 +141,8 @@ export const MAX_ITEMS = 50;
140
141
  export const count = (min, max) => ({ kind: "number", integer: true, min, max });
141
142
  /** A size: greater than 0 (or at least `min`, where fixed insets need room), at most MAX_SIZE. */
142
143
  export const size = (required = false, min) => min === undefined ? { kind: "number", min: 0, exclusiveMin: true, max: MAX_SIZE, required } : { kind: "number", min, max: MAX_SIZE, required };
143
- export const pos = () => ({ kind: "number", required: true, min: -MAX_SIZE, max: MAX_SIZE });
144
+ /** A position: any finite number, because a map position has no maximum. */
145
+ export const pos = () => ({ kind: "number", required: true });
144
146
  export const col = () => ({ kind: "color" });
145
147
  /** SVG path data: commands, digits, signs, dots, commas and spaces only. */
146
148
  export const PATH_DATA = /^[MmLlHhVvCcSsQqTtAaZz0-9eE.,+\-\s]+$/;
@@ -1,11 +1,28 @@
1
1
  import { assertParams } from "./params.js";
2
+ // A number the piece computed and would draw: finite, or the drawing overflows
3
+ // (spec illustration-pieces, "Drawing overflow"). Strings are the piece's own
4
+ // path data and transforms; caller path data (road.d, pipe.d) has its own check
5
+ // and only ever holds path characters, never the words Infinity or NaN.
6
+ const NON_FINITE = /Infinity|NaN/;
7
+ const overflows = (node) => {
8
+ if (typeof node === "string")
9
+ return false;
10
+ for (const value of Object.values(node.attrs)) {
11
+ if (typeof value === "number" ? !Number.isFinite(value) : NON_FINITE.test(value))
12
+ return true;
13
+ }
14
+ return node.children.some(overflows);
15
+ };
2
16
  export const definePiece = (name, schema, draw, relations) => {
3
17
  const piece = (params) => {
4
18
  assertParams(name, schema, params);
5
19
  const problems = relations?.(params) ?? [];
6
20
  if (problems.length > 0)
7
21
  throw new RangeError(`${name}: ${problems[0].path}: ${problems[0].message}`);
8
- return draw(params);
22
+ const drawn = draw(params);
23
+ if ([...drawn.body, ...drawn.text].some(overflows))
24
+ throw new RangeError(`${name}: the drawing overflows`);
25
+ return drawn;
9
26
  };
10
27
  return Object.assign(piece, { pieceName: name, schema, relations });
11
28
  };
@@ -1,4 +1,9 @@
1
1
  export declare const tokens: {
2
+ readonly banner: {
3
+ readonly height: 420;
4
+ readonly radius: 20;
5
+ readonly width: 1200;
6
+ };
2
7
  readonly color: {
3
8
  readonly backend: "#FF6B6B";
4
9
  readonly blocked: "#FF8A3D";
@@ -1,5 +1,10 @@
1
1
  // Generated from tokens/source.json by scripts/tokens.ts (npm run tokens). Do not edit by hand.
2
2
  export const tokens = {
3
+ "banner": {
4
+ "height": 420,
5
+ "radius": 20,
6
+ "width": 1200
7
+ },
3
8
  "color": {
4
9
  "backend": "#FF6B6B",
5
10
  "blocked": "#FF8A3D",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brunosouzas/design-system",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Design tokens and illustration pieces of brunosouzas.com: tokens as CSS, JSON and TypeScript, pieces that draw SVG (and React), and a cover command.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1,5 +1,8 @@
1
1
  /* Generated from tokens/source.json by scripts/tokens.ts (npm run tokens). Do not edit by hand. */
2
2
  :root {
3
+ --ds-banner-height: 420px;
4
+ --ds-banner-radius: 20px;
5
+ --ds-banner-width: 1200px;
3
6
  --ds-color-backend: #FF6B6B;
4
7
  --ds-color-blocked: #FF8A3D;
5
8
  --ds-color-caller: #8FB2FF;
@@ -1,4 +1,9 @@
1
1
  {
2
+ "banner": {
3
+ "height": 420,
4
+ "radius": 20,
5
+ "width": 1200
6
+ },
2
7
  "color": {
3
8
  "backend": "#FF6B6B",
4
9
  "blocked": "#FF8A3D",
@@ -1,6 +1,11 @@
1
1
  // Generated from tokens/source.json by scripts/tokens.ts (npm run tokens). Do not edit by hand.
2
2
 
3
3
  export const tokens = {
4
+ "banner": {
5
+ "height": 420,
6
+ "radius": 20,
7
+ "width": 1200
8
+ },
4
9
  "color": {
5
10
  "backend": "#FF6B6B",
6
11
  "blocked": "#FF8A3D",