@shipload/item-renderer 1.0.0-next.24 → 1.0.0-next.26
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 +1 -1
- package/src/templates/item-cell.ts +81 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipload/item-renderer",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.26",
|
|
4
4
|
"description": "Deterministic SVG rendering for Shipload items",
|
|
5
5
|
"homepage": "https://github.com/shipload/toolkit/tree/master/packages/item-renderer",
|
|
6
6
|
"repository": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"fonts:copy": "bun run scripts/copy-fonts.ts"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@shipload/sdk": "^1.0.0-next.
|
|
48
|
+
"@shipload/sdk": "^1.0.0-next.26",
|
|
49
49
|
"@wharfkit/antelope": "1.2.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -42,7 +42,7 @@ export {
|
|
|
42
42
|
export type {ResourceIconInlineOpts, ResourceIconSvgOpts} from './primitives/resource-icon.ts'
|
|
43
43
|
|
|
44
44
|
// Item cell templates
|
|
45
|
-
export {renderItemCell, itemCellGroup} from './templates/item-cell.ts'
|
|
45
|
+
export {renderItemCell, itemCellGroup, abbreviateQuantity} from './templates/item-cell.ts'
|
|
46
46
|
export type {ItemCellProps, ItemCellGroupProps} from './templates/item-cell.ts'
|
|
47
47
|
|
|
48
48
|
// Social card template (1200x630 OG image)
|
|
@@ -9,6 +9,24 @@ export interface ItemCellProps {
|
|
|
9
9
|
resolved: ResolvedItem
|
|
10
10
|
quantity?: number
|
|
11
11
|
size?: number
|
|
12
|
+
quantityColor?: string
|
|
13
|
+
quantityPrefix?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function abbreviateQuantity(n: number): string {
|
|
17
|
+
const abs = Math.abs(n)
|
|
18
|
+
if (abs < 1000) return String(n)
|
|
19
|
+
const units = [
|
|
20
|
+
{v: 1e9, s: 'b'},
|
|
21
|
+
{v: 1e6, s: 'm'},
|
|
22
|
+
{v: 1e3, s: 'k'},
|
|
23
|
+
]
|
|
24
|
+
for (const u of units) {
|
|
25
|
+
if (abs >= u.v) {
|
|
26
|
+
return (n / u.v).toFixed(1).replace(/\.0$/, '') + u.s
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return String(n)
|
|
12
30
|
}
|
|
13
31
|
|
|
14
32
|
export interface ItemCellGroupProps extends ItemCellProps {
|
|
@@ -34,32 +52,47 @@ function cellInner(props: ItemCellProps): string {
|
|
|
34
52
|
'stroke-width': 1.5,
|
|
35
53
|
})
|
|
36
54
|
|
|
55
|
+
const qty = props.quantity ?? 0
|
|
56
|
+
const showQuantity = props.quantityPrefix ? qty >= 1 : qty > 1
|
|
57
|
+
|
|
37
58
|
let content = ''
|
|
38
59
|
if (props.resolved.abbreviation) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
content = showQuantity
|
|
61
|
+
? text({
|
|
62
|
+
x: cx,
|
|
63
|
+
y: size * 0.45,
|
|
64
|
+
value: props.resolved.abbreviation,
|
|
65
|
+
size: Math.round(size * 0.28),
|
|
66
|
+
weight: 700,
|
|
67
|
+
anchor: 'middle',
|
|
68
|
+
color: tokens.colors.text.primary,
|
|
69
|
+
family: tokens.typography.display,
|
|
70
|
+
})
|
|
71
|
+
: text({
|
|
72
|
+
x: cx,
|
|
73
|
+
y: height / 2,
|
|
74
|
+
value: props.resolved.abbreviation,
|
|
75
|
+
size: Math.round(size * 0.36),
|
|
76
|
+
weight: 700,
|
|
77
|
+
anchor: 'middle',
|
|
78
|
+
dominantBaseline: 'central',
|
|
79
|
+
color: tokens.colors.text.primary,
|
|
80
|
+
family: tokens.typography.display,
|
|
81
|
+
})
|
|
50
82
|
} else if (props.resolved.category) {
|
|
51
|
-
const iconSize = Math.round(size * 0.66)
|
|
83
|
+
const iconSize = Math.round(size * (showQuantity ? 0.66 : 0.84))
|
|
84
|
+
const iconY = showQuantity ? Math.round(size * 0.12) : Math.round(height / 2 - iconSize / 2)
|
|
52
85
|
content = resourceIcon(props.resolved.category, {
|
|
53
86
|
x: (size - iconSize) / 2,
|
|
54
|
-
y:
|
|
87
|
+
y: iconY,
|
|
55
88
|
size: iconSize,
|
|
56
89
|
})
|
|
57
90
|
} else if (props.resolved.icon) {
|
|
58
91
|
content = text({
|
|
59
92
|
x: cx,
|
|
60
|
-
y: size * 0.4,
|
|
93
|
+
y: showQuantity ? size * 0.4 : height / 2,
|
|
61
94
|
value: props.resolved.icon,
|
|
62
|
-
size: Math.round(size * 0.44),
|
|
95
|
+
size: Math.round(size * (showQuantity ? 0.44 : 0.56)),
|
|
63
96
|
weight: 400,
|
|
64
97
|
anchor: 'middle',
|
|
65
98
|
dominantBaseline: 'central',
|
|
@@ -67,21 +100,41 @@ function cellInner(props: ItemCellProps): string {
|
|
|
67
100
|
})
|
|
68
101
|
}
|
|
69
102
|
|
|
70
|
-
const qty = props.quantity ?? 0
|
|
71
103
|
let quantityText = ''
|
|
72
|
-
if (
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
104
|
+
if (showQuantity) {
|
|
105
|
+
const label = (props.quantityPrefix ?? '') + abbreviateQuantity(qty)
|
|
106
|
+
const fontSize = Math.max(8, Math.round(size * 0.2))
|
|
107
|
+
const charW = fontSize * 0.6
|
|
108
|
+
const padX = Math.max(2, Math.round(fontSize * 0.34))
|
|
109
|
+
const padY = Math.max(1, Math.round(fontSize * 0.18))
|
|
110
|
+
const margin = Math.max(2, Math.round(size * 0.06))
|
|
111
|
+
const plateW = Math.round(label.length * charW) + padX * 2
|
|
112
|
+
const plateH = fontSize + padY * 2
|
|
113
|
+
const plateRight = size - margin
|
|
114
|
+
const plateBottom = height - margin
|
|
115
|
+
const plate = el('rect', {
|
|
116
|
+
x: plateRight - plateW,
|
|
117
|
+
y: plateBottom - plateH,
|
|
118
|
+
width: plateW,
|
|
119
|
+
height: plateH,
|
|
120
|
+
rx: Math.round(plateH / 2),
|
|
121
|
+
ry: Math.round(plateH / 2),
|
|
122
|
+
fill: '#050c24',
|
|
123
|
+
'fill-opacity': 0.82,
|
|
84
124
|
})
|
|
125
|
+
quantityText =
|
|
126
|
+
plate +
|
|
127
|
+
text({
|
|
128
|
+
x: plateRight - padX,
|
|
129
|
+
y: plateBottom - plateH / 2,
|
|
130
|
+
value: label,
|
|
131
|
+
size: fontSize,
|
|
132
|
+
weight: 700,
|
|
133
|
+
anchor: 'end',
|
|
134
|
+
dominantBaseline: 'central',
|
|
135
|
+
color: props.quantityColor ?? tokens.colors.text.primary,
|
|
136
|
+
family: tokens.typography.mono,
|
|
137
|
+
})
|
|
85
138
|
}
|
|
86
139
|
|
|
87
140
|
return border + content + quantityText
|