@shipload/item-renderer 0.2.3 → 1.0.0-beta1

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.
Files changed (89) hide show
  1. package/package.json +47 -49
  2. package/src/assets/stardust-base64.ts +1 -1
  3. package/src/errors.ts +14 -14
  4. package/src/fonts/index.ts +24 -24
  5. package/src/fonts/load-bun.ts +12 -12
  6. package/src/index.ts +31 -31
  7. package/src/links.ts +13 -13
  8. package/src/meta.ts +26 -26
  9. package/src/payload/base64url.ts +21 -21
  10. package/src/payload/codec.ts +19 -19
  11. package/src/primitives/category-icon.ts +88 -86
  12. package/src/primitives/compact-row.ts +32 -32
  13. package/src/primitives/divider.ts +14 -14
  14. package/src/primitives/icon-hex.ts +36 -36
  15. package/src/primitives/module-slot.ts +131 -131
  16. package/src/primitives/panel.ts +18 -18
  17. package/src/primitives/quantity-badge.ts +32 -32
  18. package/src/primitives/span-paragraph.ts +56 -56
  19. package/src/primitives/stat-bar.ts +72 -72
  20. package/src/primitives/svg.ts +16 -16
  21. package/src/primitives/text.ts +33 -33
  22. package/src/primitives/wrap.ts +19 -19
  23. package/src/render.ts +20 -20
  24. package/src/templates/_shared.ts +5 -5
  25. package/src/templates/component.ts +124 -124
  26. package/src/templates/index.ts +23 -23
  27. package/src/templates/item-cell.ts +84 -84
  28. package/src/templates/module.ts +182 -181
  29. package/src/templates/packed-entity.ts +22 -22
  30. package/src/templates/resource.ts +136 -134
  31. package/src/templates/ship-panel.ts +122 -118
  32. package/src/templates/social-card.ts +36 -36
  33. package/src/tokens/colors.ts +42 -42
  34. package/src/tokens/index.ts +6 -6
  35. package/src/tokens/spacing.ts +9 -9
  36. package/src/tokens/typography.ts +18 -18
  37. package/.claude/settings.local.json +0 -6
  38. package/.github/workflows/ci.yml +0 -14
  39. package/.gitignore +0 -6
  40. package/Makefile +0 -50
  41. package/biome.json +0 -18
  42. package/bun.lock +0 -123
  43. package/scripts/check-bundle-size.ts +0 -37
  44. package/scripts/copy-fonts.ts +0 -41
  45. package/scripts/preview.ts +0 -41
  46. package/test/__image_snapshots__/.gitkeep +0 -0
  47. package/test/__image_snapshots__/component-hull-plates.diff.png +0 -0
  48. package/test/__image_snapshots__/component-hull-plates.png +0 -0
  49. package/test/__image_snapshots__/module-engine-t1.diff.png +0 -0
  50. package/test/__image_snapshots__/module-engine-t1.png +0 -0
  51. package/test/__image_snapshots__/module-storage-t1.diff.png +0 -0
  52. package/test/__image_snapshots__/module-storage-t1.png +0 -0
  53. package/test/__image_snapshots__/packed-entity-ship-t1-only-engine.diff.png +0 -0
  54. package/test/__image_snapshots__/packed-entity-ship-t1-only-engine.png +0 -0
  55. package/test/__image_snapshots__/packed-entity-ship-t1-two-modules.diff.png +0 -0
  56. package/test/__image_snapshots__/packed-entity-ship-t1-two-modules.png +0 -0
  57. package/test/__image_snapshots__/resource-ore-t1.diff.png +0 -0
  58. package/test/__image_snapshots__/resource-ore-t1.png +0 -0
  59. package/test/__snapshots__/templates-component.test.ts.snap +0 -5
  60. package/test/__snapshots__/templates-item-cell.test.ts.snap +0 -9
  61. package/test/__snapshots__/templates-module.test.ts.snap +0 -17
  62. package/test/__snapshots__/templates-packed-entity.test.ts.snap +0 -5
  63. package/test/__snapshots__/templates-resource.test.ts.snap +0 -7
  64. package/test/base64url.test.ts +0 -33
  65. package/test/codec.test.ts +0 -34
  66. package/test/errors.test.ts +0 -24
  67. package/test/fixtures/cargo-items.ts +0 -122
  68. package/test/fonts.test.ts +0 -28
  69. package/test/links-meta.test.ts +0 -43
  70. package/test/pixel.test.ts +0 -69
  71. package/test/primitives-category-icon.test.ts +0 -86
  72. package/test/primitives-compact-row.test.ts +0 -44
  73. package/test/primitives-domain.test.ts +0 -83
  74. package/test/primitives-layout.test.ts +0 -56
  75. package/test/primitives-module-slot.test.ts +0 -88
  76. package/test/render.test.ts +0 -43
  77. package/test/sanity.test.ts +0 -6
  78. package/test/sdk-link.test.ts +0 -19
  79. package/test/snapshots/.gitkeep +0 -0
  80. package/test/svg.test.ts +0 -30
  81. package/test/templates-component.test.ts +0 -36
  82. package/test/templates-dispatch.test.ts +0 -35
  83. package/test/templates-item-cell.test.ts +0 -94
  84. package/test/templates-module.test.ts +0 -63
  85. package/test/templates-packed-entity.test.ts +0 -47
  86. package/test/templates-resource.test.ts +0 -71
  87. package/test/templates-ship-panel.test.ts +0 -91
  88. package/test/tokens.test.ts +0 -34
  89. package/tsconfig.json +0 -20
@@ -1,24 +1,24 @@
1
- import { el } from "./svg.ts";
2
- import { tokens } from "../tokens/index.ts";
1
+ import {el} from './svg.ts'
2
+ import {tokens} from '../tokens/index.ts'
3
3
 
4
4
  export interface PanelProps {
5
- width: number;
6
- height: number;
7
- borderColor?: string;
5
+ width: number
6
+ height: number
7
+ borderColor?: string
8
8
  }
9
9
 
10
10
  export function panel(props: PanelProps): string {
11
- const { width, height, borderColor } = props;
12
- const r = tokens.spacing.cornerRadius;
13
- return el("rect", {
14
- x: 0.5,
15
- y: 0.5,
16
- width: width - 1,
17
- height: height - 1,
18
- rx: r,
19
- ry: r,
20
- fill: tokens.colors.surface.panel,
21
- stroke: borderColor ?? tokens.colors.surface.panelBorder,
22
- "stroke-width": 1,
23
- });
11
+ const {width, height, borderColor} = props
12
+ const r = tokens.spacing.cornerRadius
13
+ return el('rect', {
14
+ x: 0.5,
15
+ y: 0.5,
16
+ width: width - 1,
17
+ height: height - 1,
18
+ rx: r,
19
+ ry: r,
20
+ fill: tokens.colors.surface.panel,
21
+ stroke: borderColor ?? tokens.colors.surface.panelBorder,
22
+ 'stroke-width': 1,
23
+ })
24
24
  }
@@ -1,37 +1,37 @@
1
- import { el } from "./svg.ts";
2
- import { text } from "./text.ts";
3
- import { tokens } from "../tokens/index.ts";
1
+ import {el} from './svg.ts'
2
+ import {text} from './text.ts'
3
+ import {tokens} from '../tokens/index.ts'
4
4
 
5
5
  export interface QuantityBadgeProps {
6
- x: number;
7
- y: number;
8
- quantity: number;
6
+ x: number
7
+ y: number
8
+ quantity: number
9
9
  }
10
10
 
11
- export function quantityBadge({ x, y, quantity }: QuantityBadgeProps): string {
12
- if (quantity <= 1) return "";
13
- const label = `×${quantity}`;
14
- const w = label.length * 7 + 12;
15
- const h = tokens.spacing.quantityBadgeHeight;
16
- return (
17
- el("rect", {
18
- x: x - w,
19
- y,
20
- width: w,
21
- height: h,
22
- rx: h / 2,
23
- ry: h / 2,
24
- fill: tokens.colors.text.accent,
25
- }) +
26
- text({
27
- x: x - w / 2,
28
- y: y + h / 2 + 4,
29
- value: label,
30
- size: tokens.typography.sizes.label,
31
- weight: 700,
32
- family: tokens.typography.mono,
33
- color: tokens.colors.surface.background,
34
- anchor: "middle",
35
- })
36
- );
11
+ export function quantityBadge({x, y, quantity}: QuantityBadgeProps): string {
12
+ if (quantity <= 1) return ''
13
+ const label = `×${quantity}`
14
+ const w = label.length * 7 + 12
15
+ const h = tokens.spacing.quantityBadgeHeight
16
+ return (
17
+ el('rect', {
18
+ x: x - w,
19
+ y,
20
+ width: w,
21
+ height: h,
22
+ rx: h / 2,
23
+ ry: h / 2,
24
+ fill: tokens.colors.text.accent,
25
+ }) +
26
+ text({
27
+ x: x - w / 2,
28
+ y: y + h / 2 + 4,
29
+ value: label,
30
+ size: tokens.typography.sizes.label,
31
+ weight: 700,
32
+ family: tokens.typography.mono,
33
+ color: tokens.colors.surface.background,
34
+ anchor: 'middle',
35
+ })
36
+ )
37
37
  }
@@ -1,70 +1,70 @@
1
- import { wrapText } from "./wrap.ts";
2
- import { escapeXml as escapeAttr } from "./svg.ts";
3
- import { tokens } from "../tokens/index.ts";
4
- import type { TextSpan } from "@shipload/sdk";
1
+ import {wrapText} from './wrap.ts'
2
+ import {escapeXml as escapeAttr} from './svg.ts'
3
+ import {tokens} from '../tokens/index.ts'
4
+ import type {TextSpan} from '@shipload/sdk'
5
5
 
6
6
  export interface SpanParagraphProps {
7
- x: number;
8
- y: number;
9
- spans: TextSpan[];
10
- charsPerLine?: number;
11
- lineHeight?: number;
12
- bodyColor?: string;
13
- highlightColor?: string;
14
- fontSize?: number;
7
+ x: number
8
+ y: number
9
+ spans: TextSpan[]
10
+ charsPerLine?: number
11
+ lineHeight?: number
12
+ bodyColor?: string
13
+ highlightColor?: string
14
+ fontSize?: number
15
15
  }
16
16
 
17
17
  function escapeXml(s: string): string {
18
- return s
19
- .replace(/&/g, "&amp;")
20
- .replace(/</g, "&lt;")
21
- .replace(/>/g, "&gt;")
22
- .replace(/"/g, "&quot;");
18
+ return s
19
+ .replace(/&/g, '&amp;')
20
+ .replace(/</g, '&lt;')
21
+ .replace(/>/g, '&gt;')
22
+ .replace(/"/g, '&quot;')
23
23
  }
24
24
 
25
25
  function sliceSpans(spans: TextSpan[], start: number, end: number): TextSpan[] {
26
- const out: TextSpan[] = [];
27
- let cursor = 0;
28
- for (const span of spans) {
29
- const spanStart = cursor;
30
- const spanEnd = cursor + span.text.length;
31
- cursor = spanEnd;
32
- if (spanEnd <= start || spanStart >= end) continue;
33
- const sliceStart = Math.max(0, start - spanStart);
34
- const sliceEnd = span.text.length - Math.max(0, spanEnd - end);
35
- const txt = span.text.slice(sliceStart, sliceEnd);
36
- if (txt.length === 0) continue;
37
- out.push(span.highlight ? { text: txt, highlight: true } : { text: txt });
38
- }
39
- return out;
26
+ const out: TextSpan[] = []
27
+ let cursor = 0
28
+ for (const span of spans) {
29
+ const spanStart = cursor
30
+ const spanEnd = cursor + span.text.length
31
+ cursor = spanEnd
32
+ if (spanEnd <= start || spanStart >= end) continue
33
+ const sliceStart = Math.max(0, start - spanStart)
34
+ const sliceEnd = span.text.length - Math.max(0, spanEnd - end)
35
+ const txt = span.text.slice(sliceStart, sliceEnd)
36
+ if (txt.length === 0) continue
37
+ out.push(span.highlight ? {text: txt, highlight: true} : {text: txt})
38
+ }
39
+ return out
40
40
  }
41
41
 
42
- export function spanParagraph(props: SpanParagraphProps): { svg: string; lineCount: number } {
43
- const chars = props.charsPerLine ?? 36;
44
- const lh = props.lineHeight ?? 14;
45
- const bodyColor = props.bodyColor ?? tokens.colors.text.secondary;
46
- const highlightColor = props.highlightColor ?? tokens.colors.text.accent;
47
- const size = props.fontSize ?? tokens.typography.sizes.body;
42
+ export function spanParagraph(props: SpanParagraphProps): {svg: string; lineCount: number} {
43
+ const chars = props.charsPerLine ?? 36
44
+ const lh = props.lineHeight ?? 14
45
+ const bodyColor = props.bodyColor ?? tokens.colors.text.secondary
46
+ const highlightColor = props.highlightColor ?? tokens.colors.text.accent
47
+ const size = props.fontSize ?? tokens.typography.sizes.body
48
48
 
49
- const plain = props.spans.map((s) => s.text).join("");
50
- const lines = wrapText({ value: plain, charsPerLine: chars });
49
+ const plain = props.spans.map((s) => s.text).join('')
50
+ const lines = wrapText({value: plain, charsPerLine: chars})
51
51
 
52
- let charOffset = 0;
53
- const out = lines
54
- .map((line, i) => {
55
- const lineStart = charOffset;
56
- const lineEnd = lineStart + line.length;
57
- charOffset = lineEnd + 1;
58
- const lineSpans = sliceSpans(props.spans, lineStart, lineEnd);
59
- const y = props.y + i * lh;
60
- const tspans = lineSpans
61
- .map((s) => {
62
- const fill = s.highlight ? highlightColor : bodyColor;
63
- return `<tspan fill="${fill}">${escapeXml(s.text)}</tspan>`;
52
+ let charOffset = 0
53
+ const out = lines
54
+ .map((line, i) => {
55
+ const lineStart = charOffset
56
+ const lineEnd = lineStart + line.length
57
+ charOffset = lineEnd + 1
58
+ const lineSpans = sliceSpans(props.spans, lineStart, lineEnd)
59
+ const y = props.y + i * lh
60
+ const tspans = lineSpans
61
+ .map((s) => {
62
+ const fill = s.highlight ? highlightColor : bodyColor
63
+ return `<tspan fill="${fill}">${escapeXml(s.text)}</tspan>`
64
+ })
65
+ .join('')
66
+ return `<text x="${props.x}" y="${y}" font-family="${escapeAttr(tokens.typography.sans)}" font-size="${size}">${tspans}</text>`
64
67
  })
65
- .join("");
66
- return `<text x="${props.x}" y="${y}" font-family="${escapeAttr(tokens.typography.sans)}" font-size="${size}">${tspans}</text>`;
67
- })
68
- .join("");
69
- return { svg: out, lineCount: lines.length };
68
+ .join('')
69
+ return {svg: out, lineCount: lines.length}
70
70
  }
@@ -1,85 +1,85 @@
1
- import { el } from "./svg.ts";
2
- import { text } from "./text.ts";
3
- import { tokens } from "../tokens/index.ts";
1
+ import {el} from './svg.ts'
2
+ import {text} from './text.ts'
3
+ import {tokens} from '../tokens/index.ts'
4
4
 
5
5
  export interface StatBarProps {
6
- x: number;
7
- y: number;
8
- width: number;
9
- label: string;
10
- abbreviation: string;
11
- value: number | null; // 0..1023, or null for ranges mode (no value text, no fill)
12
- color: string;
13
- inverted?: boolean;
6
+ x: number
7
+ y: number
8
+ width: number
9
+ label: string
10
+ abbreviation: string
11
+ value: number | null // 0..1023, or null for ranges mode (no value text, no fill)
12
+ color: string
13
+ inverted?: boolean
14
14
  }
15
15
 
16
16
  export function statBar({
17
- x,
18
- y,
19
- width,
20
- label,
21
- abbreviation,
22
- value,
23
- color,
24
- inverted,
25
- }: StatBarProps): string {
26
- const h = tokens.spacing.statBarHeight;
27
-
28
- let labelOut =
29
- text({
30
- x,
31
- y: y - 6,
32
- value: abbreviation,
33
- size: tokens.typography.sizes.label,
34
- weight: 700,
35
- family: tokens.typography.mono,
36
- color,
37
- }) +
38
- text({
39
- x: x + 22,
40
- y: y - 6,
41
- value: label,
42
- size: tokens.typography.sizes.stat,
43
- weight: 400,
44
- color: tokens.colors.text.primary,
45
- });
46
-
47
- const track = el("rect", {
48
17
  x,
49
18
  y,
50
19
  width,
51
- height: h,
52
- rx: h / 2,
53
- ry: h / 2,
54
- fill: tokens.colors.surface.panelBorder,
55
- });
20
+ label,
21
+ abbreviation,
22
+ value,
23
+ color,
24
+ inverted,
25
+ }: StatBarProps): string {
26
+ const h = tokens.spacing.statBarHeight
27
+
28
+ let labelOut =
29
+ text({
30
+ x,
31
+ y: y - 6,
32
+ value: abbreviation,
33
+ size: tokens.typography.sizes.label,
34
+ weight: 700,
35
+ family: tokens.typography.mono,
36
+ color,
37
+ }) +
38
+ text({
39
+ x: x + 22,
40
+ y: y - 6,
41
+ value: label,
42
+ size: tokens.typography.sizes.stat,
43
+ weight: 400,
44
+ color: tokens.colors.text.primary,
45
+ })
46
+
47
+ const track = el('rect', {
48
+ x,
49
+ y,
50
+ width,
51
+ height: h,
52
+ rx: h / 2,
53
+ ry: h / 2,
54
+ fill: tokens.colors.surface.panelBorder,
55
+ })
56
56
 
57
- if (value !== null) {
58
- const clamped = Math.max(0, Math.min(1023, value));
59
- const displayFraction = inverted ? 1 - clamped / 1023 : clamped / 1023;
60
- const filled = Math.floor(width * displayFraction);
57
+ if (value !== null) {
58
+ const clamped = Math.max(0, Math.min(1023, value))
59
+ const displayFraction = inverted ? 1 - clamped / 1023 : clamped / 1023
60
+ const filled = Math.floor(width * displayFraction)
61
61
 
62
- labelOut += text({
63
- x: x + width,
64
- y: y - 6,
65
- value: String(clamped),
66
- size: tokens.typography.sizes.statValue,
67
- weight: 700,
68
- color,
69
- anchor: "end",
70
- });
62
+ labelOut += text({
63
+ x: x + width,
64
+ y: y - 6,
65
+ value: String(clamped),
66
+ size: tokens.typography.sizes.statValue,
67
+ weight: 700,
68
+ color,
69
+ anchor: 'end',
70
+ })
71
71
 
72
- const bar = el("rect", {
73
- x,
74
- y,
75
- width: filled,
76
- height: h,
77
- rx: h / 2,
78
- ry: h / 2,
79
- fill: color,
80
- });
81
- return labelOut + track + bar;
82
- }
72
+ const bar = el('rect', {
73
+ x,
74
+ y,
75
+ width: filled,
76
+ height: h,
77
+ rx: h / 2,
78
+ ry: h / 2,
79
+ fill: color,
80
+ })
81
+ return labelOut + track + bar
82
+ }
83
83
 
84
- return labelOut + track;
84
+ return labelOut + track
85
85
  }
@@ -1,25 +1,25 @@
1
1
  export function escapeXml(input: string): string {
2
- return input
3
- .replaceAll("&", "&amp;")
4
- .replaceAll("<", "&lt;")
5
- .replaceAll(">", "&gt;")
6
- .replaceAll('"', "&quot;")
7
- .replaceAll("'", "&apos;");
2
+ return input
3
+ .replaceAll('&', '&amp;')
4
+ .replaceAll('<', '&lt;')
5
+ .replaceAll('>', '&gt;')
6
+ .replaceAll('"', '&quot;')
7
+ .replaceAll("'", '&apos;')
8
8
  }
9
9
 
10
- export type AttrValue = string | number | null | undefined;
10
+ export type AttrValue = string | number | null | undefined
11
11
 
12
12
  export function attr(attrs: Record<string, AttrValue>): string {
13
- let out = "";
14
- for (const [k, v] of Object.entries(attrs)) {
15
- if (v === undefined || v === null) continue;
16
- const value = typeof v === "number" ? String(v) : escapeXml(v);
17
- out += ` ${k}="${value}"`;
18
- }
19
- return out;
13
+ let out = ''
14
+ for (const [k, v] of Object.entries(attrs)) {
15
+ if (v === undefined || v === null) continue
16
+ const value = typeof v === 'number' ? String(v) : escapeXml(v)
17
+ out += ` ${k}="${value}"`
18
+ }
19
+ return out
20
20
  }
21
21
 
22
22
  export function el(tag: string, attrs: Record<string, AttrValue>, children?: string): string {
23
- if (children === undefined) return `<${tag}${attr(attrs)}/>`;
24
- return `<${tag}${attr(attrs)}>${children}</${tag}>`;
23
+ if (children === undefined) return `<${tag}${attr(attrs)}/>`
24
+ return `<${tag}${attr(attrs)}>${children}</${tag}>`
25
25
  }
@@ -1,42 +1,42 @@
1
- import { el } from "./svg.ts";
2
- import { tokens } from "../tokens/index.ts";
1
+ import {el} from './svg.ts'
2
+ import {tokens} from '../tokens/index.ts'
3
3
 
4
4
  export interface TextProps {
5
- x: number;
6
- y: number;
7
- value: string;
8
- size?: number;
9
- weight?: 400 | 600 | 700 | 500;
10
- family?: string;
11
- color?: string;
12
- anchor?: "start" | "middle" | "end";
13
- letterSpacing?: number;
14
- dominantBaseline?: "auto" | "middle" | "central" | "hanging" | "text-top" | "text-bottom";
5
+ x: number
6
+ y: number
7
+ value: string
8
+ size?: number
9
+ weight?: 400 | 600 | 700 | 500
10
+ family?: string
11
+ color?: string
12
+ anchor?: 'start' | 'middle' | 'end'
13
+ letterSpacing?: number
14
+ dominantBaseline?: 'auto' | 'middle' | 'central' | 'hanging' | 'text-top' | 'text-bottom'
15
15
  }
16
16
 
17
17
  export function text(props: TextProps): string {
18
- return el(
19
- "text",
20
- {
21
- x: props.x,
22
- y: props.y,
23
- "font-family": props.family ?? tokens.typography.sans,
24
- "font-size": props.size ?? tokens.typography.sizes.body,
25
- "font-weight": props.weight ?? 400,
26
- fill: props.color ?? tokens.colors.text.primary,
27
- "text-anchor": props.anchor,
28
- "letter-spacing": props.letterSpacing,
29
- "dominant-baseline": props.dominantBaseline,
30
- },
31
- escapeValue(props.value),
32
- );
18
+ return el(
19
+ 'text',
20
+ {
21
+ x: props.x,
22
+ y: props.y,
23
+ 'font-family': props.family ?? tokens.typography.sans,
24
+ 'font-size': props.size ?? tokens.typography.sizes.body,
25
+ 'font-weight': props.weight ?? 400,
26
+ fill: props.color ?? tokens.colors.text.primary,
27
+ 'text-anchor': props.anchor,
28
+ 'letter-spacing': props.letterSpacing,
29
+ 'dominant-baseline': props.dominantBaseline,
30
+ },
31
+ escapeValue(props.value)
32
+ )
33
33
  }
34
34
 
35
35
  function escapeValue(v: string): string {
36
- return v
37
- .replaceAll("&", "&amp;")
38
- .replaceAll("<", "&lt;")
39
- .replaceAll(">", "&gt;")
40
- .replaceAll('"', "&quot;")
41
- .replaceAll("'", "&apos;");
36
+ return v
37
+ .replaceAll('&', '&amp;')
38
+ .replaceAll('<', '&lt;')
39
+ .replaceAll('>', '&gt;')
40
+ .replaceAll('"', '&quot;')
41
+ .replaceAll("'", '&apos;')
42
42
  }
@@ -1,24 +1,24 @@
1
1
  export interface WrapProps {
2
- value: string;
3
- charsPerLine: number;
2
+ value: string
3
+ charsPerLine: number
4
4
  }
5
5
 
6
- export function wrapText({ value, charsPerLine }: WrapProps): string[] {
7
- const words = value.split(/\s+/).filter((w) => w.length > 0);
8
- const lines: string[] = [];
9
- let current = "";
10
- for (const word of words) {
11
- if (current.length === 0) {
12
- current = word;
13
- continue;
6
+ export function wrapText({value, charsPerLine}: WrapProps): string[] {
7
+ const words = value.split(/\s+/).filter((w) => w.length > 0)
8
+ const lines: string[] = []
9
+ let current = ''
10
+ for (const word of words) {
11
+ if (current.length === 0) {
12
+ current = word
13
+ continue
14
+ }
15
+ if (current.length + 1 + word.length <= charsPerLine) {
16
+ current += ` ${word}`
17
+ } else {
18
+ lines.push(current)
19
+ current = word
20
+ }
14
21
  }
15
- if (current.length + 1 + word.length <= charsPerLine) {
16
- current += ` ${word}`;
17
- } else {
18
- lines.push(current);
19
- current = word;
20
- }
21
- }
22
- if (current.length > 0) lines.push(current);
23
- return lines;
22
+ if (current.length > 0) lines.push(current)
23
+ return lines
24
24
  }
package/src/render.ts CHANGED
@@ -1,29 +1,29 @@
1
- import { resolveItem, type ResolvedItem } from "@shipload/sdk";
2
- import type { CargoItem } from "./payload/codec.ts";
3
- import { decodePayload } from "./payload/codec.ts";
4
- import { renderByType } from "./templates/index.ts";
5
- import { UnknownItemError } from "./errors.ts";
1
+ import {resolveItem, type ResolvedItem} from '@shipload/sdk'
2
+ import type {CargoItem} from './payload/codec.ts'
3
+ import {decodePayload} from './payload/codec.ts'
4
+ import {renderByType} from './templates/index.ts'
5
+ import {UnknownItemError} from './errors.ts'
6
6
 
7
7
  export interface RenderOptions {
8
- width?: number;
9
- theme?: "dark" | "light";
8
+ width?: number
9
+ theme?: 'dark' | 'light'
10
10
  }
11
11
 
12
12
  export function renderItem(item: CargoItem, resolved: ResolvedItem, _opts?: RenderOptions): string {
13
- return renderByType(item, resolved);
13
+ return renderByType(item, resolved)
14
14
  }
15
15
 
16
16
  export async function renderFromPayload(
17
- payload: string,
18
- opts?: RenderOptions,
19
- ): Promise<{ svg: string; item: ResolvedItem }> {
20
- const cargoItem = decodePayload(payload);
21
- let resolved: ResolvedItem;
22
- try {
23
- resolved = resolveItem(cargoItem.item_id, cargoItem.stats, cargoItem.modules);
24
- } catch {
25
- throw new UnknownItemError(Number(BigInt(cargoItem.item_id.toString())));
26
- }
27
- const svg = renderItem(cargoItem, resolved, opts);
28
- return { svg, item: resolved };
17
+ payload: string,
18
+ opts?: RenderOptions
19
+ ): Promise<{svg: string; item: ResolvedItem}> {
20
+ const cargoItem = decodePayload(payload)
21
+ let resolved: ResolvedItem
22
+ try {
23
+ resolved = resolveItem(cargoItem.item_id, cargoItem.stats, cargoItem.modules)
24
+ } catch {
25
+ throw new UnknownItemError(Number(BigInt(cargoItem.item_id.toString())))
26
+ }
27
+ const svg = renderItem(cargoItem, resolved, opts)
28
+ return {svg, item: resolved}
29
29
  }
@@ -1,14 +1,14 @@
1
- import { tokens } from "../tokens/index.ts";
1
+ import {tokens} from '../tokens/index.ts'
2
2
 
3
3
  export function formatMass(n: number): string {
4
- return n.toLocaleString("en-US");
4
+ return n.toLocaleString('en-US')
5
5
  }
6
6
 
7
7
  export function tierBorder(tier: number): string {
8
- return tokens.colors.tier[tier] ?? tokens.colors.surface.panelBorder;
8
+ return tokens.colors.tier[tier] ?? tokens.colors.surface.panelBorder
9
9
  }
10
10
 
11
11
  export function shortCode(itemId: number): string {
12
- const str = itemId.toString(10);
13
- return str.slice(-2).padStart(2, "0");
12
+ const str = itemId.toString(10)
13
+ return str.slice(-2).padStart(2, '0')
14
14
  }