@shipload/item-renderer 1.0.0-next.5 → 1.0.0-next.51
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/package.json +2 -2
- package/src/index.ts +81 -8
- package/src/links.ts +11 -8
- package/src/meta.ts +1 -1
- package/src/payload/codec.ts +24 -2
- package/src/primitives/component-icon.ts +229 -0
- package/src/primitives/entity-icon.ts +170 -0
- package/src/primitives/module-icon.ts +297 -0
- package/src/primitives/module-slot.ts +4 -4
- package/src/primitives/quantity-badge.ts +15 -5
- package/src/primitives/resource-icon.ts +242 -0
- package/src/primitives/span-paragraph.ts +1 -1
- package/src/primitives/stat-bar.ts +17 -1
- package/src/primitives/stat-stars.ts +36 -0
- package/src/primitives/station-entity-icon.ts +261 -0
- package/src/primitives/text.ts +27 -1
- package/src/render.ts +12 -7
- package/src/templates/_shared.ts +113 -2
- package/src/templates/component.ts +41 -61
- package/src/templates/index.ts +2 -1
- package/src/templates/item-cell.ts +147 -38
- package/src/templates/module.ts +63 -145
- package/src/templates/packed-entity.ts +25 -5
- package/src/templates/resource.ts +40 -68
- package/src/templates/ship-panel.ts +99 -85
- package/src/tokens/colors.ts +13 -13
- package/test/fixtures/cargo-items.ts +10 -3
- package/src/primitives/category-icon.ts +0 -110
- package/src/primitives/compact-row.ts +0 -38
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
import type {TextSpan} from '@shipload/sdk'
|
|
2
|
+
import {formatLocation, formatMassScaled} from '@shipload/sdk'
|
|
2
3
|
import {panel} from '../primitives/panel.ts'
|
|
3
4
|
import {iconHex} from '../primitives/icon-hex.ts'
|
|
4
|
-
import {
|
|
5
|
-
import {divider} from '../primitives/divider.ts'
|
|
5
|
+
import {entityIcon, entityIconSlugForName} from '../primitives/entity-icon.ts'
|
|
6
6
|
import {moduleSlot} from '../primitives/module-slot.ts'
|
|
7
7
|
import {quantityBadge} from '../primitives/quantity-badge.ts'
|
|
8
8
|
import {wrapText} from '../primitives/wrap.ts'
|
|
9
9
|
import {tokens} from '../tokens/index.ts'
|
|
10
|
+
import {
|
|
11
|
+
tierBorder,
|
|
12
|
+
metaRowBlock,
|
|
13
|
+
titleParts,
|
|
14
|
+
capabilityColor,
|
|
15
|
+
BADGE_Y,
|
|
16
|
+
HEADER_H,
|
|
17
|
+
ICON_Y,
|
|
18
|
+
BOTTOM_PAD,
|
|
19
|
+
} from './_shared.ts'
|
|
20
|
+
|
|
21
|
+
const HULL_MASS_LABELS = new Set(['mass', 'capacity'])
|
|
22
|
+
|
|
23
|
+
const ENTITY_COLOR = tokens.colors.brand.cyan
|
|
10
24
|
|
|
11
25
|
export interface ShipPanelSlot {
|
|
12
26
|
name?: string
|
|
13
27
|
installed: boolean
|
|
28
|
+
capability?: string
|
|
14
29
|
description?: string | TextSpan[]
|
|
15
30
|
}
|
|
16
31
|
|
|
@@ -18,22 +33,35 @@ export interface ShipPanelProps {
|
|
|
18
33
|
name: string
|
|
19
34
|
tier: number
|
|
20
35
|
quantity?: number
|
|
36
|
+
location?: {x: number; y: number}
|
|
21
37
|
attributes: {capability: string; attributes: {label: string; value: number}[]}[]
|
|
22
38
|
slots: ShipPanelSlot[]
|
|
23
39
|
}
|
|
24
40
|
|
|
25
|
-
function
|
|
26
|
-
return
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
function tierBorder(tier: number): string {
|
|
30
|
-
return tokens.colors.tier[tier] ?? tokens.colors.surface.panelBorder
|
|
41
|
+
function formatHullValue(label: string, value: number): string {
|
|
42
|
+
return HULL_MASS_LABELS.has(label.toLowerCase())
|
|
43
|
+
? formatMassScaled(value)
|
|
44
|
+
: value.toLocaleString('en-US')
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
const MODULE_LABEL_PREFIX = (capability: string) => `${capability}: `
|
|
34
48
|
|
|
35
|
-
function
|
|
36
|
-
|
|
49
|
+
function fallbackEntityCode(name: string): string {
|
|
50
|
+
const words = name
|
|
51
|
+
.replace(/\s+T\d+\s*$/i, '')
|
|
52
|
+
.trim()
|
|
53
|
+
.split(/\s+/)
|
|
54
|
+
.filter(Boolean)
|
|
55
|
+
if (words.length >= 2)
|
|
56
|
+
return words
|
|
57
|
+
.map((word) => word[0])
|
|
58
|
+
.join('')
|
|
59
|
+
.slice(0, 2)
|
|
60
|
+
.toUpperCase()
|
|
61
|
+
return (words[0] ?? 'EN').slice(0, 2).toUpperCase().padEnd(2, 'N')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function lineCountFor(slot: ShipPanelSlot): number {
|
|
37
65
|
const desc = slot.description
|
|
38
66
|
const plain =
|
|
39
67
|
typeof desc === 'string'
|
|
@@ -41,12 +69,25 @@ function rowHeightFor(slot: ShipPanelSlot): number {
|
|
|
41
69
|
: Array.isArray(desc)
|
|
42
70
|
? desc.map((s) => s.text).join('')
|
|
43
71
|
: ''
|
|
44
|
-
if (plain.length === 0) return
|
|
45
|
-
const combined = MODULE_LABEL_PREFIX(slot.name ?? 'Module') + plain
|
|
46
|
-
|
|
72
|
+
if (plain.length === 0) return 0
|
|
73
|
+
const combined = MODULE_LABEL_PREFIX(slot.capability ?? slot.name ?? 'Module') + plain
|
|
74
|
+
return Math.max(1, wrapText({value: combined, charsPerLine: 36}).length)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function rowHeightFor(slot: ShipPanelSlot): number {
|
|
78
|
+
if (!slot.installed) return 24
|
|
79
|
+
const lineCount = lineCountFor(slot)
|
|
80
|
+
if (lineCount === 0) return 24
|
|
47
81
|
return 10 + lineCount * 14
|
|
48
82
|
}
|
|
49
83
|
|
|
84
|
+
function contentBottomOffsetFor(slot: ShipPanelSlot): number {
|
|
85
|
+
if (!slot.installed) return 14
|
|
86
|
+
const lineCount = lineCountFor(slot)
|
|
87
|
+
if (lineCount === 0) return 14
|
|
88
|
+
return 9 + (lineCount - 1) * 14 + 5
|
|
89
|
+
}
|
|
90
|
+
|
|
50
91
|
export function renderShipPanel(props: ShipPanelProps): string {
|
|
51
92
|
const w = tokens.spacing.panelWidth
|
|
52
93
|
const pad = tokens.spacing.panelPadding
|
|
@@ -54,91 +95,64 @@ export function renderShipPanel(props: ShipPanelProps): string {
|
|
|
54
95
|
const quantity = props.quantity ?? 0
|
|
55
96
|
|
|
56
97
|
const hullGroup = props.attributes?.find((g) => g.capability.toLowerCase() === 'hull')
|
|
57
|
-
const
|
|
98
|
+
const hullAttrs = (hullGroup?.attributes ?? []).map((a) => ({
|
|
99
|
+
label: a.label,
|
|
100
|
+
value: formatHullValue(a.label, a.value),
|
|
101
|
+
}))
|
|
102
|
+
const metaRows = props.location
|
|
103
|
+
? [{label: 'Location', value: formatLocation(props.location)}, ...hullAttrs]
|
|
104
|
+
: hullAttrs
|
|
58
105
|
|
|
59
|
-
const headerH = 48
|
|
60
|
-
const hullHeaderH = 20
|
|
61
|
-
const hullRowH = 22
|
|
62
106
|
const sectionGap = 12
|
|
63
|
-
const rowHeights = props.slots.map(rowHeightFor)
|
|
64
|
-
const modulesHeight = rowHeights.reduce((a, b) => a + b, 0)
|
|
65
|
-
const height =
|
|
66
|
-
headerH + hullHeaderH + hullRows.length * hullRowH + sectionGap + modulesHeight + pad
|
|
67
107
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
const icon = iconHex({
|
|
71
|
-
x: pad,
|
|
72
|
-
y: pad + 4,
|
|
73
|
-
color: tokens.colors.text.accent,
|
|
74
|
-
code: 'SH',
|
|
75
|
-
})
|
|
108
|
+
const metaYStart = pad + HEADER_H
|
|
109
|
+
const {svg: metaSvg, height: metaH} = metaRowBlock(pad, metaYStart, innerW, metaRows)
|
|
76
110
|
|
|
77
|
-
const
|
|
78
|
-
x: pad + 34,
|
|
79
|
-
y: pad + 22,
|
|
80
|
-
value: props.name,
|
|
81
|
-
size: tokens.typography.sizes.title,
|
|
82
|
-
weight: 700,
|
|
83
|
-
family: tokens.typography.display,
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
const badge = quantityBadge({x: w - pad, y: pad, quantity})
|
|
87
|
-
|
|
88
|
-
const hullHeader = text({
|
|
89
|
-
x: pad,
|
|
90
|
-
y: pad + headerH,
|
|
91
|
-
value: 'HULL',
|
|
92
|
-
size: tokens.typography.sizes.subtitle,
|
|
93
|
-
weight: 700,
|
|
94
|
-
color: tokens.colors.text.secondary,
|
|
95
|
-
letterSpacing: 1,
|
|
96
|
-
})
|
|
111
|
+
const slotsYStart = metaYStart + metaH + sectionGap
|
|
97
112
|
|
|
98
|
-
let y =
|
|
99
|
-
let hullSvg = ''
|
|
100
|
-
for (const row of hullRows) {
|
|
101
|
-
hullSvg +=
|
|
102
|
-
text({
|
|
103
|
-
x: pad,
|
|
104
|
-
y: y + 12,
|
|
105
|
-
value: row.label,
|
|
106
|
-
size: tokens.typography.sizes.body,
|
|
107
|
-
color: tokens.colors.text.secondary,
|
|
108
|
-
}) +
|
|
109
|
-
text({
|
|
110
|
-
x: w - pad,
|
|
111
|
-
y: y + 12,
|
|
112
|
-
value: formatNumber(row.value),
|
|
113
|
-
size: tokens.typography.sizes.body,
|
|
114
|
-
weight: 700,
|
|
115
|
-
anchor: 'end',
|
|
116
|
-
}) +
|
|
117
|
-
divider({
|
|
118
|
-
x: pad,
|
|
119
|
-
y: y + hullRowH - 4,
|
|
120
|
-
width: innerW,
|
|
121
|
-
color: tokens.colors.surface.panelBorderBright,
|
|
122
|
-
})
|
|
123
|
-
y += hullRowH
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
y += sectionGap
|
|
113
|
+
let y = slotsYStart
|
|
127
114
|
let modulesSvg = ''
|
|
128
|
-
|
|
129
|
-
|
|
115
|
+
let lastContentBottom = slotsYStart
|
|
116
|
+
props.slots.forEach((slot, i) => {
|
|
117
|
+
const accentColor = slot.installed
|
|
118
|
+
? capabilityColor(slot.capability ?? slot.name ?? 'Module')
|
|
119
|
+
: ENTITY_COLOR
|
|
130
120
|
modulesSvg += moduleSlot({
|
|
131
121
|
x: pad,
|
|
132
122
|
y,
|
|
133
123
|
width: innerW,
|
|
134
124
|
installed: slot.installed,
|
|
135
|
-
capability: slot.name,
|
|
125
|
+
capability: slot.capability ?? slot.name,
|
|
136
126
|
description: slot.description,
|
|
137
|
-
accentColor
|
|
127
|
+
accentColor,
|
|
138
128
|
})
|
|
139
|
-
y
|
|
140
|
-
|
|
129
|
+
lastContentBottom = y + contentBottomOffsetFor(slot)
|
|
130
|
+
if (i < props.slots.length - 1) y += rowHeightFor(slot)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const height = lastContentBottom + BOTTOM_PAD
|
|
134
|
+
|
|
135
|
+
const chrome = panel({width: w, height, borderColor: tierBorder(props.tier)})
|
|
136
|
+
|
|
137
|
+
const entitySlug = entityIconSlugForName(props.name)
|
|
138
|
+
const icon = entitySlug
|
|
139
|
+
? entityIcon(entitySlug, {x: pad, y: pad + ICON_Y - 2, size: 28})
|
|
140
|
+
: iconHex({
|
|
141
|
+
x: pad,
|
|
142
|
+
y: pad + ICON_Y,
|
|
143
|
+
color: ENTITY_COLOR,
|
|
144
|
+
code: fallbackEntityCode(props.name),
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const name = titleParts(pad + 34, pad + 22, props.name, props.tier)
|
|
148
|
+
|
|
149
|
+
const badge = quantityBadge({
|
|
150
|
+
x: w - pad,
|
|
151
|
+
y: pad + BADGE_Y,
|
|
152
|
+
quantity,
|
|
153
|
+
tone: ENTITY_COLOR,
|
|
154
|
+
})
|
|
141
155
|
|
|
142
|
-
const inner = `${chrome}${icon}${name}${badge}${
|
|
156
|
+
const inner = `${chrome}${icon}${name}${badge}${metaSvg}${modulesSvg}`
|
|
143
157
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${height}" viewBox="0 0 ${w} ${height}">${inner}</svg>`
|
|
144
158
|
}
|
package/src/tokens/colors.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {tierColors} from '@shipload/sdk'
|
|
1
|
+
import {categoryColors, tierColors} from '@shipload/sdk'
|
|
2
2
|
|
|
3
3
|
export const colors = {
|
|
4
4
|
surface: {
|
|
@@ -10,7 +10,7 @@ export const colors = {
|
|
|
10
10
|
text: {
|
|
11
11
|
primary: '#e6e8ec',
|
|
12
12
|
secondary: '#8f98a8',
|
|
13
|
-
muted: '#
|
|
13
|
+
muted: '#7c8698',
|
|
14
14
|
accent: '#f4c96b',
|
|
15
15
|
},
|
|
16
16
|
brand: {
|
|
@@ -18,25 +18,25 @@ export const colors = {
|
|
|
18
18
|
teal: '#2fd6d1',
|
|
19
19
|
cyan: '#6cb9ff',
|
|
20
20
|
},
|
|
21
|
-
category:
|
|
22
|
-
ore: '#C26D3F',
|
|
23
|
-
crystal: '#4ADBFF',
|
|
24
|
-
gas: '#B8E4A0',
|
|
25
|
-
regolith: '#C4A57B',
|
|
26
|
-
biomass: '#5A8B3E',
|
|
27
|
-
},
|
|
21
|
+
category: categoryColors,
|
|
28
22
|
tier: tierColors,
|
|
29
23
|
accent: {
|
|
30
|
-
component: '#
|
|
24
|
+
component: '#7E93C4',
|
|
31
25
|
},
|
|
32
26
|
capability: {
|
|
33
27
|
engine: '#4a8abf',
|
|
34
28
|
generator: '#22c55e',
|
|
29
|
+
reactor: '#22c55e',
|
|
35
30
|
gatherer: '#f59e0b',
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
'limpet bay': '#f59e0b',
|
|
32
|
+
loading: '#eab308',
|
|
33
|
+
'shuttle bay': '#eab308',
|
|
34
|
+
crafting: '#a855f7',
|
|
35
|
+
fabricator: '#a855f7',
|
|
38
36
|
storage: '#14b8a6',
|
|
39
|
-
|
|
37
|
+
'cargo hold': '#14b8a6',
|
|
38
|
+
hauling: '#f97316',
|
|
39
|
+
'tractor beam': '#f97316',
|
|
40
40
|
},
|
|
41
41
|
} as const
|
|
42
42
|
|
|
@@ -9,6 +9,7 @@ export const ITEM_LOADER_T1 = 10103
|
|
|
9
9
|
export const ITEM_MANUFACTURING_T1 = 10104
|
|
10
10
|
export const ITEM_STORAGE_T1 = 10105
|
|
11
11
|
export const ITEM_HAULER_T1 = 10106
|
|
12
|
+
export const ITEM_CONTAINER_T1_PACKED = 10200
|
|
12
13
|
export const ITEM_SHIP_T1_PACKED = 10201
|
|
13
14
|
|
|
14
15
|
export const MODULE_ENGINE = 1
|
|
@@ -49,7 +50,7 @@ export function cargoShipT1Packed(opts?: {
|
|
|
49
50
|
})
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
export const
|
|
53
|
+
export const ITEM_PLATE = 10001
|
|
53
54
|
|
|
54
55
|
export const FIXTURES = {
|
|
55
56
|
oreT1: cargoOreT1('0x123456789ABCDEF'),
|
|
@@ -61,8 +62,8 @@ export const FIXTURES = {
|
|
|
61
62
|
stats: '0xDEADBEEF1234',
|
|
62
63
|
modules: [],
|
|
63
64
|
}),
|
|
64
|
-
|
|
65
|
-
item_id:
|
|
65
|
+
plate: ServerContract.Types.cargo_item.from({
|
|
66
|
+
item_id: ITEM_PLATE,
|
|
66
67
|
quantity: 1,
|
|
67
68
|
stats: '0x7FFF',
|
|
68
69
|
modules: [],
|
|
@@ -115,6 +116,12 @@ export const FIXTURES = {
|
|
|
115
116
|
stats: '0',
|
|
116
117
|
modules: [],
|
|
117
118
|
}),
|
|
119
|
+
containerT1: ServerContract.Types.cargo_item.from({
|
|
120
|
+
item_id: ITEM_CONTAINER_T1_PACKED,
|
|
121
|
+
quantity: 1,
|
|
122
|
+
stats: '0',
|
|
123
|
+
modules: [],
|
|
124
|
+
}),
|
|
118
125
|
shipT1TwoModules: cargoShipT1Packed(),
|
|
119
126
|
shipT1OnlyEngine: cargoShipT1Packed({onlyEngine: true}),
|
|
120
127
|
} as const
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import type {CategoryIconShape} from '@shipload/sdk'
|
|
2
|
-
import {el} from './svg.ts'
|
|
3
|
-
|
|
4
|
-
export interface CategoryIconPathOpts {
|
|
5
|
-
shape: CategoryIconShape
|
|
6
|
-
cx: number
|
|
7
|
-
cy: number
|
|
8
|
-
size: number
|
|
9
|
-
color: string
|
|
10
|
-
strokeWidth?: number
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface CategoryIconSvgOpts {
|
|
14
|
-
size?: number
|
|
15
|
-
color?: string
|
|
16
|
-
strokeWidth?: number
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function hexPoints(cx: number, cy: number, r: number): string {
|
|
20
|
-
const pts: string[] = []
|
|
21
|
-
for (let i = 0; i < 6; i++) {
|
|
22
|
-
const angle = (Math.PI / 3) * i - Math.PI / 2
|
|
23
|
-
pts.push(
|
|
24
|
-
`${(cx + r * Math.cos(angle)).toFixed(2)},${(cy + r * Math.sin(angle)).toFixed(2)}`
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
return pts.join(' ')
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function diamondPoints(cx: number, cy: number, r: number): string {
|
|
31
|
-
return [
|
|
32
|
-
`${cx.toFixed(2)},${(cy - r).toFixed(2)}`,
|
|
33
|
-
`${(cx + r).toFixed(2)},${cy.toFixed(2)}`,
|
|
34
|
-
`${cx.toFixed(2)},${(cy + r).toFixed(2)}`,
|
|
35
|
-
`${(cx - r).toFixed(2)},${cy.toFixed(2)}`,
|
|
36
|
-
].join(' ')
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function starPoints(cx: number, cy: number, r: number): string {
|
|
40
|
-
const inner = r * 0.45
|
|
41
|
-
const pts: string[] = []
|
|
42
|
-
for (let i = 0; i < 10; i++) {
|
|
43
|
-
const angle = (Math.PI / 5) * i - Math.PI / 2
|
|
44
|
-
const radius = i % 2 === 0 ? r : inner
|
|
45
|
-
pts.push(
|
|
46
|
-
`${(cx + radius * Math.cos(angle)).toFixed(2)},${(cy + radius * Math.sin(angle)).toFixed(2)}`
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
return pts.join(' ')
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function categoryIconPath({
|
|
53
|
-
shape,
|
|
54
|
-
cx,
|
|
55
|
-
cy,
|
|
56
|
-
size,
|
|
57
|
-
color,
|
|
58
|
-
strokeWidth,
|
|
59
|
-
}: CategoryIconPathOpts): string {
|
|
60
|
-
const r = size / 2
|
|
61
|
-
const stroked = strokeWidth && strokeWidth > 0
|
|
62
|
-
const shapeAttrs = stroked
|
|
63
|
-
? {
|
|
64
|
-
fill: 'none',
|
|
65
|
-
stroke: color,
|
|
66
|
-
'stroke-width': strokeWidth,
|
|
67
|
-
'stroke-linejoin': 'round' as const,
|
|
68
|
-
}
|
|
69
|
-
: {fill: color}
|
|
70
|
-
switch (shape) {
|
|
71
|
-
case 'hex':
|
|
72
|
-
return el('polygon', {points: hexPoints(cx, cy, r), ...shapeAttrs})
|
|
73
|
-
case 'diamond':
|
|
74
|
-
return el('polygon', {points: diamondPoints(cx, cy, r), ...shapeAttrs})
|
|
75
|
-
case 'star':
|
|
76
|
-
return el('polygon', {points: starPoints(cx, cy, r), ...shapeAttrs})
|
|
77
|
-
case 'circle':
|
|
78
|
-
return el('circle', {cx, cy, r, ...shapeAttrs})
|
|
79
|
-
case 'square':
|
|
80
|
-
return el('rect', {x: cx - r, y: cy - r, width: size, height: size, ...shapeAttrs})
|
|
81
|
-
}
|
|
82
|
-
const _exhaustive: never = shape
|
|
83
|
-
throw new Error(`Unknown CategoryIconShape: ${String(_exhaustive)}`)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function categoryIconSvg(shape: CategoryIconShape, opts: CategoryIconSvgOpts = {}): string {
|
|
87
|
-
const size = opts.size ?? 16
|
|
88
|
-
const color = opts.color ?? '#ffffff'
|
|
89
|
-
const cx = size / 2
|
|
90
|
-
const cy = size / 2
|
|
91
|
-
const iconSize = size * 0.85
|
|
92
|
-
const inner = categoryIconPath({
|
|
93
|
-
shape,
|
|
94
|
-
cx,
|
|
95
|
-
cy,
|
|
96
|
-
size: iconSize,
|
|
97
|
-
color,
|
|
98
|
-
strokeWidth: opts.strokeWidth,
|
|
99
|
-
})
|
|
100
|
-
return el(
|
|
101
|
-
'svg',
|
|
102
|
-
{
|
|
103
|
-
xmlns: 'http://www.w3.org/2000/svg',
|
|
104
|
-
width: size,
|
|
105
|
-
height: size,
|
|
106
|
-
viewBox: `0 0 ${size} ${size}`,
|
|
107
|
-
},
|
|
108
|
-
inner
|
|
109
|
-
)
|
|
110
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import {text} from './text.ts'
|
|
2
|
-
import {tokens} from '../tokens/index.ts'
|
|
3
|
-
|
|
4
|
-
export interface CompactRowProps {
|
|
5
|
-
x: number
|
|
6
|
-
y: number
|
|
7
|
-
width: number
|
|
8
|
-
label: string
|
|
9
|
-
value: string
|
|
10
|
-
labelColor?: string
|
|
11
|
-
valueColor?: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function compactRow(p: CompactRowProps): string {
|
|
15
|
-
const labelColor = p.labelColor ?? tokens.colors.text.secondary
|
|
16
|
-
const valueColor = p.valueColor ?? tokens.colors.text.primary
|
|
17
|
-
return (
|
|
18
|
-
text({
|
|
19
|
-
x: p.x,
|
|
20
|
-
y: p.y,
|
|
21
|
-
value: p.label,
|
|
22
|
-
size: 11,
|
|
23
|
-
weight: 500,
|
|
24
|
-
family: tokens.typography.sans,
|
|
25
|
-
color: labelColor,
|
|
26
|
-
}) +
|
|
27
|
-
text({
|
|
28
|
-
x: p.x + p.width,
|
|
29
|
-
y: p.y,
|
|
30
|
-
value: p.value,
|
|
31
|
-
size: 11,
|
|
32
|
-
weight: 700,
|
|
33
|
-
family: tokens.typography.sans,
|
|
34
|
-
color: valueColor,
|
|
35
|
-
anchor: 'end',
|
|
36
|
-
})
|
|
37
|
-
)
|
|
38
|
-
}
|