@celestia-island/hikari 0.55.142 → 0.55.143
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
CHANGED
|
@@ -48,6 +48,37 @@
|
|
|
48
48
|
border-radius: var(--radius-sm, 4px);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// Rate segment (the model-group capsule's `×N` tail, 2026-10-11): takes
|
|
52
|
+
// the inline-end rounding and provides the seam's divider from its own
|
|
53
|
+
// inline-start border; a success tint keeps it readable as a modifier,
|
|
54
|
+
// not a second name. With a rate present the NAME segment becomes a
|
|
55
|
+
// middle segment — square inline-end edge too (the join geometry below).
|
|
56
|
+
.s-model-tag-group[data-rate] .hk-badge.s-model-tag-name {
|
|
57
|
+
border-start-end-radius: 0;
|
|
58
|
+
border-end-end-radius: 0;
|
|
59
|
+
// The rate badge provides the seam's divider from its own
|
|
60
|
+
// inline-start border — the name's inline-end border must drop or
|
|
61
|
+
// the seam stacks ~2px (the num/name seam is 1px).
|
|
62
|
+
border-inline-end: none;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Tagless + rate (the pill starts bare before the roster refines the
|
|
66
|
+
// id): the name is the FIRST child — its leading corners keep the
|
|
67
|
+
// capsule's rounding (only the :only-child escape covered it before).
|
|
68
|
+
.s-model-tag-group[data-rate] .hk-badge.s-model-tag-name:first-child {
|
|
69
|
+
border-start-start-radius: var(--radius-sm, 4px);
|
|
70
|
+
border-end-start-radius: var(--radius-sm, 4px);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.s-model-tag-group .hk-badge.s-model-tag-rate {
|
|
74
|
+
border-start-start-radius: 0;
|
|
75
|
+
border-end-start-radius: 0;
|
|
76
|
+
border-start-end-radius: var(--radius-sm, 4px);
|
|
77
|
+
border-end-end-radius: var(--radius-sm, 4px);
|
|
78
|
+
border-inline-start-color: rgb(var(--color-muted) / 35%);
|
|
79
|
+
flex-shrink: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
51
82
|
.s-model-tag-name-text {
|
|
52
83
|
display: block;
|
|
53
84
|
overflow: hidden;
|
|
@@ -126,4 +126,30 @@ describe("HkModelTag", () => {
|
|
|
126
126
|
c.querySelector(".s-model-tag-group")?.getAttribute("data-expanded"),
|
|
127
127
|
).toBeNull();
|
|
128
128
|
});
|
|
129
|
+
|
|
130
|
+
it("renders the optional rate tail as the third joined segment", () => {
|
|
131
|
+
const c = mount(tagNode({ model: "gpt-5.5#2", rate: 1.5 }));
|
|
132
|
+
const group = c.querySelector(".s-model-tag-group");
|
|
133
|
+
expect(group?.hasAttribute("data-rate")).toBe(true);
|
|
134
|
+
expect(group?.querySelector(".s-model-tag-rate")?.textContent?.trim()).toBe("×1.5");
|
|
135
|
+
// The segments read in order: #2, name, rate.
|
|
136
|
+
expect(group?.textContent?.trim()).toBe("#2gpt-5.5×1.5");
|
|
137
|
+
|
|
138
|
+
// Trailing zeros trimmed, one decimal at most.
|
|
139
|
+
const whole = mount(tagNode({ model: "gpt-5.5#2", rate: 2 }));
|
|
140
|
+
expect(
|
|
141
|
+
whole.querySelector(".s-model-tag-rate")?.textContent?.trim(),
|
|
142
|
+
).toBe("×2");
|
|
143
|
+
const tenth = mount(tagNode({ model: "gpt-5.5#2", rate: 0.1 }));
|
|
144
|
+
expect(
|
|
145
|
+
tenth.querySelector(".s-model-tag-rate")?.textContent?.trim(),
|
|
146
|
+
).toBe("×0.1");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("keeps the classic two-part pill untouched without a rate", () => {
|
|
150
|
+
const c = mount(tagNode({ model: "gpt-5.5#2" }));
|
|
151
|
+
const group = c.querySelector(".s-model-tag-group");
|
|
152
|
+
expect(group?.getAttribute("data-rate")).toBeNull();
|
|
153
|
+
expect(group?.querySelector(".s-model-tag-rate")).toBeNull();
|
|
154
|
+
});
|
|
129
155
|
});
|
|
@@ -23,6 +23,10 @@ const ModelPill = defineComponent({
|
|
|
23
23
|
model: { type: String, required: true },
|
|
24
24
|
/** Render the name without truncation (used inside the hover card). */
|
|
25
25
|
expanded: { type: Boolean, default: false },
|
|
26
|
+
/** Optional third segment — the billing rate tail (`×1.5`), as the
|
|
27
|
+
* model-group capsule's multiplier (2026-10-11 direction). Absent
|
|
28
|
+
* keeps the classic two-part pill untouched. */
|
|
29
|
+
rate: { type: Number, default: undefined },
|
|
26
30
|
},
|
|
27
31
|
setup(props) {
|
|
28
32
|
// Split inside the render closure: capturing `splitModelId(props.model)`
|
|
@@ -32,10 +36,19 @@ const ModelPill = defineComponent({
|
|
|
32
36
|
// stale, untagged pill.
|
|
33
37
|
return () => {
|
|
34
38
|
const { base, tag } = splitModelId(props.model);
|
|
39
|
+
// ×1.5 / ×2 / ×0.1 — trailing zeros trimmed, one decimal at most
|
|
40
|
+
// (the editor offers tenths; hundredths would crowd the pill).
|
|
41
|
+
// Number.isFinite guards the catalog edge: a NaN/Infinity leaking
|
|
42
|
+
// in would otherwise render "×NaN" (R1 F3).
|
|
43
|
+
const rateText =
|
|
44
|
+
props.rate != null && Number.isFinite(props.rate)
|
|
45
|
+
? `×${Number(props.rate.toFixed(1)).toString()}`
|
|
46
|
+
: null;
|
|
35
47
|
return (
|
|
36
48
|
<span
|
|
37
49
|
class="s-model-tag-group"
|
|
38
50
|
data-expanded={props.expanded || undefined}
|
|
51
|
+
data-rate={rateText != null || undefined}
|
|
39
52
|
>
|
|
40
53
|
{tag && (
|
|
41
54
|
<HBadge variant="primary" size="sm" mono pill={false} class="s-model-tag-num">
|
|
@@ -45,6 +58,11 @@ const ModelPill = defineComponent({
|
|
|
45
58
|
<HBadge variant="muted" size="sm" mono pill={false} class="s-model-tag-name">
|
|
46
59
|
<span class="s-model-tag-name-text">{base}</span>
|
|
47
60
|
</HBadge>
|
|
61
|
+
{rateText != null && (
|
|
62
|
+
<HBadge variant="success" size="sm" mono pill={false} class="s-model-tag-rate">
|
|
63
|
+
{rateText}
|
|
64
|
+
</HBadge>
|
|
65
|
+
)}
|
|
48
66
|
</span>
|
|
49
67
|
);
|
|
50
68
|
};
|
|
@@ -57,6 +75,8 @@ const ModelCard = defineComponent({
|
|
|
57
75
|
props: {
|
|
58
76
|
model: { type: String, required: true },
|
|
59
77
|
meta: { type: Object as PropType<HModelMeta | undefined>, default: undefined },
|
|
78
|
+
/** Billing-rate tail passthrough (see ModelPill). */
|
|
79
|
+
rate: { type: Number, default: undefined },
|
|
60
80
|
currency: { type: String, default: "$" },
|
|
61
81
|
},
|
|
62
82
|
setup(props) {
|
|
@@ -99,7 +119,7 @@ const ModelCard = defineComponent({
|
|
|
99
119
|
return (
|
|
100
120
|
<div class="s-model-card">
|
|
101
121
|
<div class="s-model-card-title">
|
|
102
|
-
<ModelPill model={props.model} expanded />
|
|
122
|
+
<ModelPill model={props.model} expanded rate={props.rate} />
|
|
103
123
|
</div>
|
|
104
124
|
{rows.length > 0 && (
|
|
105
125
|
<div class="s-model-card-stats">
|
|
@@ -149,6 +169,8 @@ export const HkModelTag = defineComponent({
|
|
|
149
169
|
/** Per-instance catalog override. */
|
|
150
170
|
catalog: { type: Object as PropType<HModelCatalog | undefined>, default: undefined },
|
|
151
171
|
currency: { type: String, default: "$" },
|
|
172
|
+
/** Optional billing-rate tail on the pill (`×1.5`); see ModelPill. */
|
|
173
|
+
rate: { type: Number, default: undefined },
|
|
152
174
|
},
|
|
153
175
|
setup(props) {
|
|
154
176
|
const anchorRef = ref<HTMLElement | null>(null);
|
|
@@ -175,7 +197,7 @@ export const HkModelTag = defineComponent({
|
|
|
175
197
|
onMouseenter={onEnter}
|
|
176
198
|
onMouseleave={onLeave}
|
|
177
199
|
>
|
|
178
|
-
<ModelPill model={props.model} />
|
|
200
|
+
<ModelPill model={props.model} rate={props.rate} />
|
|
179
201
|
<HPopover
|
|
180
202
|
modelValue={open.value}
|
|
181
203
|
onUpdate:modelValue={(v: boolean) => { open.value = v; }}
|