@neta-art/cohub 11.0.0 → 11.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 +31 -5
- package/dist/board/editor/context.d.ts +1 -0
- package/dist/board/editor/context.js +1 -0
- package/dist/board/editor/creation.d.ts +2 -2
- package/dist/board/editor/creation.js +3 -3
- package/dist/board/editor/editor.d.ts +5 -4
- package/dist/board/editor/editor.js +8 -1
- package/dist/board/editor/index.d.ts +2 -2
- package/dist/board/editor/interaction.d.ts +12 -2
- package/dist/board/editor/interaction.js +50 -8
- package/dist/board/editor/selection-transform.d.ts +1 -1
- package/dist/board/editor/selection-transform.js +13 -2
- package/dist/board/editor/snapshots.d.ts +0 -2
- package/dist/board/editor/snapshots.js +4 -20
- package/dist/board/export/index.d.ts +2 -0
- package/dist/board/export/index.js +1 -0
- package/dist/board/export/scene.d.ts +2 -0
- package/dist/board/export/scene.js +8 -1
- package/dist/board/model/file-preview.d.ts +0 -1
- package/dist/board/model/file-preview.js +10 -1
- package/dist/board/model/image-key.js +1 -1
- package/dist/board/model/index.d.ts +8 -7
- package/dist/board/model/index.js +6 -5
- package/dist/board/model/items/create.d.ts +16 -3
- package/dist/board/model/items/create.js +125 -5
- package/dist/board/model/items/index.d.ts +2 -2
- package/dist/board/model/items/index.js +2 -2
- package/dist/board/model/media-playback.js +1 -1
- package/dist/board/model/overlay-placement.d.ts +25 -0
- package/dist/board/model/overlay-placement.js +35 -0
- package/dist/board/model/replay.d.ts +1 -1
- package/dist/board/model/replay.js +1 -0
- package/dist/board/model/script-hit.d.ts +20 -3
- package/dist/board/model/script-hit.js +81 -24
- package/dist/board/model/script-observers.d.ts +18 -0
- package/dist/board/model/script-observers.js +92 -0
- package/dist/board/model/script-scene.d.ts +1 -1
- package/dist/board/model/script-scene.js +35 -8
- package/dist/board/model/script.d.ts +51 -7
- package/dist/board/render/audio-waveform.d.ts +1 -1
- package/dist/board/render/audio-waveform.js +8 -5
- package/dist/board/render/board-background.js +5 -4
- package/dist/board/render/card-tag.d.ts +24 -0
- package/dist/board/render/card-tag.js +205 -0
- package/dist/board/render/index.d.ts +8 -5
- package/dist/board/render/index.js +8 -5
- package/dist/board/render/media-interaction.d.ts +2 -1
- package/dist/board/render/media-interaction.js +15 -7
- package/dist/board/render/palette.js +2 -2
- package/dist/board/render/renderers/arrow-card-renderer.js +20 -16
- package/dist/board/render/renderers/audio-card-renderer.d.ts +8 -1
- package/dist/board/render/renderers/audio-card-renderer.js +64 -60
- package/dist/board/render/renderers/base-card-renderer.d.ts +1 -26
- package/dist/board/render/renderers/base-card-renderer.js +6 -92
- package/dist/board/render/renderers/board-renderer-registry.d.ts +25 -2
- package/dist/board/render/renderers/board-renderer-registry.js +11 -4
- package/dist/board/render/renderers/custom-card-renderer.js +6 -8
- package/dist/board/render/renderers/effect-card-renderer.js +0 -5
- package/dist/board/render/renderers/file-card-renderer.d.ts +1 -11
- package/dist/board/render/renderers/file-card-renderer.js +43 -105
- package/dist/board/render/renderers/frame-card-renderer.js +14 -15
- package/dist/board/render/renderers/image-card-renderer.js +62 -67
- package/dist/board/render/renderers/media-key.d.ts +6 -0
- package/dist/board/render/renderers/media-key.js +39 -0
- package/dist/board/render/renderers/shape-card-renderer.js +6 -12
- package/dist/board/render/renderers/task-card-renderer.d.ts +1 -8
- package/dist/board/render/renderers/task-card-renderer.js +286 -111
- package/dist/board/render/renderers/unknown-card-renderer.js +17 -16
- package/dist/board/render/renderers/video-card-renderer.js +73 -80
- package/dist/board/render/script-host.d.ts +1 -1
- package/dist/board/render/script-host.js +53 -28
- package/dist/board/render/script-runtime.js +13 -3
- package/dist/board/render/script-texture.d.ts +11 -0
- package/dist/board/render/script-texture.js +33 -0
- package/dist/board/render/stroke.d.ts +1 -1
- package/dist/board/render/stroke.js +5 -4
- package/dist/board/render/style.d.ts +29 -0
- package/dist/board/render/style.js +54 -0
- package/dist/board/render/surface.d.ts +34 -0
- package/dist/board/render/surface.js +132 -0
- package/dist/board/render/text-fit.d.ts +8 -0
- package/dist/board/render/text-fit.js +60 -0
- package/dist/board/render/text-resolution.d.ts +2 -1
- package/dist/board/render/text-resolution.js +4 -1
- package/dist/board/stage/assets.js +1 -1
- package/dist/board/stage/index.d.ts +3 -2
- package/dist/board/stage/index.js +2 -1
- package/dist/board/stage/overlay.d.ts +41 -0
- package/dist/board/stage/overlay.js +182 -0
- package/dist/board/stage/scene.d.ts +4 -43
- package/dist/board/stage/scene.js +38 -130
- package/dist/board/stage/script-pointer.d.ts +1 -0
- package/dist/board/stage/script-pointer.js +8 -2
- package/dist/board/stage/stage.d.ts +13 -3
- package/dist/board/stage/stage.js +217 -53
- package/dist/chunks/environment.d.ts +1037 -8
- package/dist/chunks/environment.js +12 -4
- package/dist/chunks/http.d.ts +51 -2
- package/dist/chunks/http.js +10 -1
- package/dist/chunks/transport.js +1 -1
- package/dist/chunks/websocket.d.ts +1 -1
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +151 -139
- package/dist/protocol/dist/board-model.d.ts +36 -1
- package/dist/protocol/dist/board-model.js +14 -4
- package/dist/protocol/dist/board-task.d.ts +22 -0
- package/dist/{board/model/task.js → protocol/dist/board-task.js} +34 -7
- package/dist/protocol/dist/generation/blocks.d.ts +8 -0
- package/dist/{generation-blocks.js → protocol/dist/generation/blocks.js} +14 -15
- package/dist/protocol/dist/index.d.ts +5 -2
- package/dist/protocol/dist/task/index.d.ts +4 -0
- package/package.json +2 -1
- package/dist/board/model/task.d.ts +0 -11
- package/dist/types.d.ts +0 -36
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { BOARD_FONT_STACK, BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
|
-
import { featuredTaskArtifact } from "
|
|
2
|
+
import { featuredTaskArtifact } from "../../../protocol/dist/board-task.js";
|
|
3
|
+
import { fitTextToLines } from "../text-fit.js";
|
|
4
|
+
import { boardCardDetailed, syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
5
|
+
import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
|
|
3
6
|
import { drawAudioWaveform } from "../audio-waveform.js";
|
|
4
|
-
import {
|
|
7
|
+
import { cardElevation, containRect, drawCardSurface, traceCardOutline } from "../surface.js";
|
|
5
8
|
import { positionShell } from "./base-card-renderer.js";
|
|
6
9
|
import { drawFarPlate } from "./far-plate.js";
|
|
7
|
-
import {
|
|
8
|
-
import { Container, Graphics, Sprite, Text } from "pixi.js";
|
|
10
|
+
import { Container, FillGradient, Graphics, Sprite, Text } from "pixi.js";
|
|
9
11
|
//#region src/board/render/renderers/task-card-renderer.ts
|
|
10
|
-
const RADIUS = 4;
|
|
11
12
|
const PADDING = 12;
|
|
12
13
|
const META_HEIGHT = 28;
|
|
13
|
-
const TASK_CARD_FULL_DETAIL_ZOOM = .55;
|
|
14
14
|
const PLAY_BADGE_RADIUS = 15;
|
|
15
|
+
const SHIMMER_PERIOD_MS = 1600;
|
|
16
|
+
const SHIMMER_FRAME_MS = 33;
|
|
17
|
+
const REVEAL_MS = 180;
|
|
18
|
+
const SECOND = 1e3;
|
|
15
19
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
16
20
|
function previewKindFor(artifact) {
|
|
17
21
|
if (!artifact) return "empty";
|
|
@@ -19,54 +23,45 @@ function previewKindFor(artifact) {
|
|
|
19
23
|
if (artifact.type === "audio") return artifact.previewUrl ? "texture" : "waveform";
|
|
20
24
|
return artifact.textExcerpt ? "text" : "empty";
|
|
21
25
|
}
|
|
22
|
-
function
|
|
26
|
+
function liveStatus(item, context) {
|
|
27
|
+
const { snapshot } = item.props;
|
|
28
|
+
const live = snapshot.status === "completed" ? null : context.taskRun(item.props.taskRunId);
|
|
29
|
+
const liveStart = Date.parse(live?.startedAt ?? "");
|
|
30
|
+
const working = live?.status === "pending" || live?.status === "running";
|
|
31
|
+
const adopt = snapshot.status === "failed" ? working && liveStart > Date.parse(snapshot.updatedAt ?? "") : live?.status === "running" || live?.status === "pending" && snapshot.status === "pending";
|
|
32
|
+
const status = adopt && live ? live.status : snapshot.status;
|
|
33
|
+
const started = adopt ? liveStart : Date.parse(snapshot.startedAt ?? "");
|
|
34
|
+
return {
|
|
35
|
+
status,
|
|
36
|
+
startedAt: Number.isFinite(started) ? started : null
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function stateSurfaceFor(status, kind, hasTexture, previewFailed) {
|
|
23
40
|
if (kind === "texture" && !hasTexture) {
|
|
24
|
-
if (
|
|
41
|
+
if (status === "failed") return "failed";
|
|
25
42
|
return previewFailed ? "unavailable" : "media-loading";
|
|
26
43
|
}
|
|
27
44
|
if (kind !== "empty") return null;
|
|
28
|
-
if (
|
|
29
|
-
if (
|
|
30
|
-
if (
|
|
45
|
+
if (status === "failed") return "failed";
|
|
46
|
+
if (status === "running") return "generating";
|
|
47
|
+
if (status === "pending") return "queued";
|
|
31
48
|
return "empty";
|
|
32
49
|
}
|
|
33
|
-
function stateLabel(surface) {
|
|
50
|
+
function stateLabel(surface, context) {
|
|
34
51
|
switch (surface) {
|
|
35
|
-
case "generating": return
|
|
36
|
-
case "queued": return
|
|
37
|
-
case "failed": return
|
|
38
|
-
case "unavailable": return
|
|
39
|
-
case "empty": return
|
|
52
|
+
case "generating": return context.labels.generating;
|
|
53
|
+
case "queued": return context.labels.queued;
|
|
54
|
+
case "failed": return context.labels.failed;
|
|
55
|
+
case "unavailable": return context.labels.previewUnavailable;
|
|
56
|
+
case "empty": return context.labels.noPreview;
|
|
40
57
|
default: return "";
|
|
41
58
|
}
|
|
42
59
|
}
|
|
43
|
-
function statusColor(
|
|
44
|
-
if (
|
|
45
|
-
if (
|
|
60
|
+
function statusColor(status, context) {
|
|
61
|
+
if (status === "failed") return context.colors.rose.stroke;
|
|
62
|
+
if (status === "running") return context.colors.brand.stroke;
|
|
46
63
|
return context.colors.neutral.stroke;
|
|
47
64
|
}
|
|
48
|
-
function metadata(item) {
|
|
49
|
-
const { artifactCount, artifacts } = item.props.snapshot;
|
|
50
|
-
const extra = artifactCount > artifacts.length ? `${artifacts.length}/${artifactCount}` : artifactCount > 1 ? `+${artifactCount - 1}` : null;
|
|
51
|
-
return [item.props.snapshot.model, extra].filter(Boolean).join(" · ");
|
|
52
|
-
}
|
|
53
|
-
function containTaskPreviewRect(width, height, imageWidth, imageHeight) {
|
|
54
|
-
if (width <= 0 || height <= 0 || imageWidth <= 0 || imageHeight <= 0) return {
|
|
55
|
-
x: 0,
|
|
56
|
-
y: 0,
|
|
57
|
-
width: 0,
|
|
58
|
-
height: 0
|
|
59
|
-
};
|
|
60
|
-
const scale = Math.min(width / imageWidth, height / imageHeight);
|
|
61
|
-
const renderedWidth = imageWidth * scale;
|
|
62
|
-
const renderedHeight = imageHeight * scale;
|
|
63
|
-
return {
|
|
64
|
-
x: (width - renderedWidth) / 2,
|
|
65
|
-
y: (height - renderedHeight) / 2,
|
|
66
|
-
width: renderedWidth,
|
|
67
|
-
height: renderedHeight
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
65
|
function drawPlayBadge(graphics, rect, context) {
|
|
71
66
|
const radius = Math.min(PLAY_BADGE_RADIUS, Math.max(8, Math.min(rect.width, rect.height) * .16));
|
|
72
67
|
const cx = rect.x + rect.width / 2;
|
|
@@ -150,15 +145,116 @@ function drawFailedBadge(graphics, width, color, context) {
|
|
|
150
145
|
cap: "round"
|
|
151
146
|
});
|
|
152
147
|
}
|
|
148
|
+
const shimmerGradients = /* @__PURE__ */ new Map();
|
|
149
|
+
function shimmerGradient(color) {
|
|
150
|
+
let gradient = shimmerGradients.get(color);
|
|
151
|
+
if (!gradient) {
|
|
152
|
+
const rgb = `${color >> 16 & 255}, ${color >> 8 & 255}, ${color & 255}`;
|
|
153
|
+
gradient = new FillGradient({
|
|
154
|
+
type: "linear",
|
|
155
|
+
start: {
|
|
156
|
+
x: 0,
|
|
157
|
+
y: 0
|
|
158
|
+
},
|
|
159
|
+
end: {
|
|
160
|
+
x: 1,
|
|
161
|
+
y: 0
|
|
162
|
+
},
|
|
163
|
+
textureSpace: "local",
|
|
164
|
+
colorStops: [
|
|
165
|
+
{
|
|
166
|
+
offset: 0,
|
|
167
|
+
color: `rgba(${rgb}, 0)`
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
offset: .5,
|
|
171
|
+
color: `rgba(${rgb}, 0.07)`
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
offset: 1,
|
|
175
|
+
color: `rgba(${rgb}, 0)`
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
});
|
|
179
|
+
shimmerGradients.set(color, gradient);
|
|
180
|
+
}
|
|
181
|
+
return gradient;
|
|
182
|
+
}
|
|
183
|
+
function drawShimmerBand(graphics, width, height, color) {
|
|
184
|
+
const band = Math.max(48, width * .45);
|
|
185
|
+
graphics.clear().rect(-band, 0, band, height).fill(shimmerGradient(color));
|
|
186
|
+
}
|
|
187
|
+
const MOSAIC_FRAME_MS = 160;
|
|
188
|
+
const MOSAIC_CELL = 8;
|
|
189
|
+
function drawMosaic(graphics, width, height, color, frame) {
|
|
190
|
+
const columns = Math.max(1, Math.floor(width / MOSAIC_CELL));
|
|
191
|
+
const rows = Math.max(1, Math.floor(height / MOSAIC_CELL));
|
|
192
|
+
const left = (width - columns * MOSAIC_CELL) / 2;
|
|
193
|
+
const top = (height - rows * MOSAIC_CELL) / 2;
|
|
194
|
+
graphics.clear();
|
|
195
|
+
for (const [threshold, alpha] of [[.08, .16], [.02, .3]]) {
|
|
196
|
+
for (let row = 0; row < rows; row += 1) for (let column = 0; column < columns; column += 1) {
|
|
197
|
+
let hash = Math.imul(column + 1, 2654435761) ^ Math.imul(row + 1, 2246822507) ^ Math.imul(frame + 1, 3266489909);
|
|
198
|
+
hash ^= hash >>> 15;
|
|
199
|
+
hash = Math.imul(hash, 739982445);
|
|
200
|
+
hash ^= hash >>> 12;
|
|
201
|
+
if ((hash >>> 0) / 4294967295 < threshold) graphics.rect(left + column * MOSAIC_CELL + 1, top + row * MOSAIC_CELL + 1, 6, 6);
|
|
202
|
+
}
|
|
203
|
+
graphics.fill({
|
|
204
|
+
color,
|
|
205
|
+
alpha
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function advance(parts, clock) {
|
|
210
|
+
const { motion } = parts;
|
|
211
|
+
let next = null;
|
|
212
|
+
if (motion.mosaic) {
|
|
213
|
+
const frame = Math.floor(clock / MOSAIC_FRAME_MS);
|
|
214
|
+
if (frame !== motion.mosaic.step) {
|
|
215
|
+
motion.mosaic.step = frame;
|
|
216
|
+
drawMosaic(parts.shimmer, motion.width, motion.mosaic.height, motion.mosaic.color, frame);
|
|
217
|
+
}
|
|
218
|
+
next = MOSAIC_FRAME_MS - clock % MOSAIC_FRAME_MS;
|
|
219
|
+
} else if (motion.shimmer) {
|
|
220
|
+
const travel = motion.width + parts.shimmer.width;
|
|
221
|
+
parts.shimmer.x = clock % SHIMMER_PERIOD_MS / SHIMMER_PERIOD_MS * travel;
|
|
222
|
+
next = SHIMMER_FRAME_MS;
|
|
223
|
+
}
|
|
224
|
+
if (motion.startedAt !== null) {
|
|
225
|
+
const elapsedMs = Date.now() - motion.startedAt;
|
|
226
|
+
const elapsed = formatBoardDuration(elapsedMs);
|
|
227
|
+
if (elapsed !== motion.elapsed) {
|
|
228
|
+
motion.elapsed = elapsed;
|
|
229
|
+
parts.body.text = `${motion.label} · ${elapsed}`;
|
|
230
|
+
}
|
|
231
|
+
const untilNextSecond = SECOND - Math.max(0, elapsedMs) % SECOND;
|
|
232
|
+
next = next === null ? untilNextSecond : Math.min(next, untilNextSecond);
|
|
233
|
+
}
|
|
234
|
+
if (motion.revealFrom !== null) {
|
|
235
|
+
const progress = Math.min(1, (clock - motion.revealFrom) / REVEAL_MS);
|
|
236
|
+
parts.preview.alpha = progress * (2 - progress);
|
|
237
|
+
if (progress >= 1) motion.revealFrom = null;
|
|
238
|
+
else next = 0;
|
|
239
|
+
}
|
|
240
|
+
return next;
|
|
241
|
+
}
|
|
153
242
|
function sync(container, item, context) {
|
|
154
243
|
const parts = partsByContainer.get(container);
|
|
155
244
|
if (!parts) return;
|
|
156
245
|
positionShell(parts.root, item);
|
|
157
246
|
const { width, height } = item.frame;
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
const full = context.zoom
|
|
161
|
-
const
|
|
247
|
+
const { snapshot } = item.props;
|
|
248
|
+
const { status, startedAt } = liveStatus(item, context);
|
|
249
|
+
const full = boardCardDetailed(context.zoom);
|
|
250
|
+
const elevation = cardElevation(context, item.id);
|
|
251
|
+
syncCardTag(parts.tag, {
|
|
252
|
+
glyph: "task",
|
|
253
|
+
text: snapshot.title,
|
|
254
|
+
width
|
|
255
|
+
}, context);
|
|
256
|
+
const working = status === "pending" || status === "running";
|
|
257
|
+
const color = statusColor(status, context);
|
|
162
258
|
const key = context.assetKey(item);
|
|
163
259
|
if (key !== parts.assetKey) {
|
|
164
260
|
if (parts.assetKey) context.releaseTexture(parts.assetKey);
|
|
@@ -167,56 +263,100 @@ function sync(container, item, context) {
|
|
|
167
263
|
}
|
|
168
264
|
const texture = key ? context.getTexture(key) : null;
|
|
169
265
|
const previewFailed = Boolean(key && !texture && context.hasError(key));
|
|
170
|
-
const artifact = featuredTaskArtifact(
|
|
266
|
+
const artifact = featuredTaskArtifact(snapshot.artifacts);
|
|
171
267
|
const kind = previewKindFor(artifact);
|
|
172
|
-
const surface = stateSurfaceFor(
|
|
268
|
+
const surface = stateSurfaceFor(status, kind, Boolean(texture), previewFailed);
|
|
173
269
|
const frame = {
|
|
174
270
|
x: 1,
|
|
175
271
|
y: 1,
|
|
176
272
|
width: Math.max(1, width - 2),
|
|
177
273
|
height: Math.max(1, height - 2)
|
|
178
274
|
};
|
|
179
|
-
const metaText = artifact ?
|
|
275
|
+
const metaText = artifact || working ? snapshot.model ?? "" : "";
|
|
180
276
|
const showMeta = full && Boolean(metaText);
|
|
181
|
-
const failedWithOutput =
|
|
277
|
+
const failedWithOutput = status === "failed" && kind !== "empty";
|
|
278
|
+
const count = artifact && snapshot.artifactCount > 1 ? String(snapshot.artifactCount) : "";
|
|
279
|
+
const showBadge = full && Boolean(count);
|
|
280
|
+
const label = stateLabel(surface, context);
|
|
281
|
+
const counting = full && working && startedAt !== null && surface !== null;
|
|
282
|
+
const elapsed = counting ? formatBoardDuration(Date.now() - startedAt) : "";
|
|
283
|
+
const detailText = !full || !surface ? "" : status === "failed" ? snapshot.errorExcerpt ?? "" : working ? snapshot.promptExcerpt ?? "" : "";
|
|
284
|
+
const textArtifact = kind === "text" && artifact?.type === "text";
|
|
285
|
+
const bodyText = textArtifact ? artifact.textExcerpt : counting ? `${label} · ${elapsed}` : label;
|
|
182
286
|
syncTextResolution(parts.body, parts, context.zoom);
|
|
287
|
+
syncTextResolution(parts.detail, parts, context.zoom);
|
|
183
288
|
syncTextResolution(parts.meta, parts, context.zoom);
|
|
289
|
+
syncTextResolution(parts.badge, parts, context.zoom);
|
|
290
|
+
const textSig = [
|
|
291
|
+
counting ? label : bodyText,
|
|
292
|
+
detailText,
|
|
293
|
+
metaText,
|
|
294
|
+
count,
|
|
295
|
+
kind,
|
|
296
|
+
surface,
|
|
297
|
+
full,
|
|
298
|
+
width,
|
|
299
|
+
height,
|
|
300
|
+
color,
|
|
301
|
+
context.palette.text,
|
|
302
|
+
context.palette.muted,
|
|
303
|
+
context.style.font
|
|
304
|
+
].join("|");
|
|
305
|
+
if (textSig !== parts.textSig) {
|
|
306
|
+
parts.textSig = textSig;
|
|
307
|
+
parts.body.style.fontFamily = context.style.font;
|
|
308
|
+
parts.detail.style.fontFamily = context.style.font;
|
|
309
|
+
const wrap = Math.max(24, width - 24);
|
|
310
|
+
parts.body.style.fill = surface === "failed" ? color : context.palette.text;
|
|
311
|
+
parts.body.anchor.set(textArtifact ? 0 : .5, 0);
|
|
312
|
+
fitTextToLines(parts.body, bodyText, textArtifact ? Math.max(1, Math.floor((height - 24 - (showMeta ? META_HEIGHT : 0)) / 16)) : 1, wrap);
|
|
313
|
+
parts.detail.style.fill = context.palette.muted;
|
|
314
|
+
fitTextToLines(parts.detail, detailText, height - 24 > 120 ? 2 : 1, Math.min(wrap, 360));
|
|
315
|
+
parts.meta.style.fill = context.palette.text;
|
|
316
|
+
fitTextToLines(parts.meta, metaText, 1, wrap);
|
|
317
|
+
parts.badge.style.fill = context.palette.text;
|
|
318
|
+
if (parts.badge.text !== count) parts.badge.text = count;
|
|
319
|
+
}
|
|
320
|
+
const badgeWidth = Math.max(22, parts.badge.width + 12);
|
|
184
321
|
const visualSig = [
|
|
185
322
|
width,
|
|
186
323
|
height,
|
|
187
|
-
selected,
|
|
188
|
-
hovered,
|
|
189
324
|
full,
|
|
325
|
+
elevation,
|
|
190
326
|
color,
|
|
191
327
|
kind,
|
|
192
328
|
surface,
|
|
193
329
|
showMeta,
|
|
330
|
+
showBadge && badgeWidth,
|
|
194
331
|
failedWithOutput,
|
|
195
332
|
artifact?.type ?? "none",
|
|
196
333
|
artifact?.id ?? "none",
|
|
197
334
|
item.props.taskRunId,
|
|
198
335
|
texture ? `${texture.width}x${texture.height}` : "none",
|
|
199
|
-
context.
|
|
200
|
-
context.palette.hover,
|
|
201
|
-
context.palette.border,
|
|
202
|
-
context.palette.bg
|
|
336
|
+
context.themeKey
|
|
203
337
|
].join("|");
|
|
204
338
|
if (visualSig !== parts.visualSig) {
|
|
205
339
|
parts.visualSig = visualSig;
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
340
|
+
const rect = {
|
|
341
|
+
x: 0,
|
|
342
|
+
y: 0,
|
|
343
|
+
width,
|
|
344
|
+
height
|
|
345
|
+
};
|
|
346
|
+
drawCardSurface(parts.plate.clear(), rect, context.style, {
|
|
347
|
+
fill: context.palette.surface,
|
|
348
|
+
border: context.palette.border,
|
|
349
|
+
borderAlpha: .82,
|
|
350
|
+
elevation
|
|
213
351
|
});
|
|
214
|
-
parts.clip.clear()
|
|
352
|
+
traceCardOutline(parts.clip.clear(), rect, context.style, -1).fill({ color: 16777215 });
|
|
215
353
|
parts.previewBg.clear().rect(frame.x, frame.y, frame.width, frame.height).fill({
|
|
216
354
|
color: context.palette.hover,
|
|
217
355
|
alpha: .5
|
|
218
356
|
});
|
|
219
357
|
parts.previewMask.clear().rect(frame.x, frame.y, frame.width, frame.height).fill({ color: 16777215 });
|
|
358
|
+
if (context.style.progress === "shimmer") drawShimmerBand(parts.shimmer, frame.width, frame.height, context.palette.text);
|
|
359
|
+
parts.shimmer.position.set(context.style.progress === "shimmer" ? 0 : frame.x, frame.y);
|
|
220
360
|
parts.previewArt.clear();
|
|
221
361
|
if (kind === "waveform") {
|
|
222
362
|
const bottomInset = showMeta ? META_HEIGHT : 0;
|
|
@@ -229,47 +369,58 @@ function sync(container, item, context) {
|
|
|
229
369
|
}
|
|
230
370
|
if (full && (artifact?.type === "audio" || artifact?.type === "video" && texture)) drawPlayBadge(parts.previewArt, frame, context);
|
|
231
371
|
if (surface) {
|
|
232
|
-
const markY = frame.y + frame.height / 2 - (full &&
|
|
372
|
+
const markY = frame.y + frame.height / 2 - (full && label ? 18 : 0);
|
|
233
373
|
drawStateMark(parts.previewArt, surface, frame.x + frame.width / 2, markY, surface === "failed" ? color : context.colors.neutral.stroke);
|
|
234
374
|
}
|
|
235
375
|
if (showMeta) parts.previewArt.rect(frame.x, frame.y + frame.height - META_HEIGHT, frame.width, META_HEIGHT).fill({
|
|
236
376
|
color: context.palette.bg,
|
|
237
377
|
alpha: .68
|
|
238
378
|
});
|
|
379
|
+
if (showBadge) parts.previewArt.roundRect(width - badgeWidth - 8, 8, badgeWidth, 20, 10).fill({
|
|
380
|
+
color: context.palette.bg,
|
|
381
|
+
alpha: .72
|
|
382
|
+
});
|
|
239
383
|
if (failedWithOutput) drawFailedBadge(parts.previewArt, width, color, context);
|
|
240
384
|
}
|
|
241
|
-
|
|
242
|
-
|
|
385
|
+
const showPreview = kind === "texture" && Boolean(texture);
|
|
386
|
+
const revealKey = showPreview ? `${artifact?.id}:${texture?.uid}` : null;
|
|
387
|
+
const sameCard = parts.motion.itemId === item.id;
|
|
388
|
+
parts.motion.itemId = item.id;
|
|
389
|
+
if (revealKey !== parts.motion.revealKey || !sameCard) {
|
|
390
|
+
const appearing = sameCard && parts.motion.revealKey === null && revealKey !== null;
|
|
391
|
+
parts.motion.revealKey = revealKey;
|
|
392
|
+
parts.motion.revealFrom = appearing && !context.reducedMotion ? performance.now() : null;
|
|
393
|
+
parts.preview.alpha = parts.motion.revealFrom === null ? 1 : 0;
|
|
394
|
+
}
|
|
395
|
+
parts.preview.visible = showPreview;
|
|
396
|
+
if (showPreview && texture) {
|
|
243
397
|
if (parts.preview.texture !== texture) parts.preview.texture = texture;
|
|
244
|
-
const fitted =
|
|
398
|
+
const fitted = containRect(frame.width, frame.height, texture.width, texture.height);
|
|
245
399
|
parts.preview.position.set(frame.x + fitted.x, frame.y + fitted.y);
|
|
246
400
|
parts.preview.width = fitted.width;
|
|
247
401
|
parts.preview.height = fitted.height;
|
|
248
402
|
}
|
|
249
|
-
const bodyText = kind === "text" && artifact?.type === "text" ? artifact.textExcerpt : stateLabel(surface);
|
|
250
|
-
const textSig = [
|
|
251
|
-
bodyText,
|
|
252
|
-
metaText,
|
|
253
|
-
kind,
|
|
254
|
-
surface,
|
|
255
|
-
full,
|
|
256
|
-
width,
|
|
257
|
-
height,
|
|
258
|
-
context.palette.text,
|
|
259
|
-
context.palette.muted
|
|
260
|
-
].join("|");
|
|
261
|
-
if (textSig !== parts.textSig) {
|
|
262
|
-
parts.textSig = textSig;
|
|
263
|
-
parts.body.style.fill = surface === "failed" ? color : context.palette.text;
|
|
264
|
-
fitTextToLines(parts.body, bodyText, kind === "text" ? Math.max(1, Math.floor((height - 24 - (showMeta ? META_HEIGHT : 0)) / 16)) : 1, Math.max(24, width - 24));
|
|
265
|
-
parts.meta.style.fill = context.palette.text;
|
|
266
|
-
fitTextToLines(parts.meta, metaText, 1, Math.max(24, width - 24));
|
|
267
|
-
}
|
|
268
403
|
parts.body.visible = full && Boolean(bodyText);
|
|
404
|
+
parts.detail.visible = full && Boolean(detailText);
|
|
269
405
|
parts.meta.visible = showMeta;
|
|
270
|
-
|
|
271
|
-
|
|
406
|
+
parts.badge.visible = showBadge;
|
|
407
|
+
if (textArtifact) parts.body.position.set(PADDING, PADDING);
|
|
408
|
+
else parts.body.position.set(width / 2, height / 2 + 2);
|
|
409
|
+
parts.detail.position.set(width / 2, height / 2 + 2 + parts.body.height + 4);
|
|
272
410
|
parts.meta.position.set(PADDING, height - META_HEIGHT + 7);
|
|
411
|
+
parts.badge.position.set(width - 8 - badgeWidth / 2, 18);
|
|
412
|
+
parts.motion.width = frame.width;
|
|
413
|
+
parts.motion.shimmer = full && working && kind !== "texture" && !context.reducedMotion;
|
|
414
|
+
const mosaic = parts.motion.shimmer && context.style.progress === "mosaic";
|
|
415
|
+
parts.motion.mosaic = mosaic ? {
|
|
416
|
+
color: context.palette.brand,
|
|
417
|
+
height: frame.height,
|
|
418
|
+
step: -1
|
|
419
|
+
} : null;
|
|
420
|
+
parts.shimmer.visible = parts.motion.shimmer;
|
|
421
|
+
parts.motion.startedAt = counting ? startedAt : null;
|
|
422
|
+
parts.motion.label = label;
|
|
423
|
+
parts.motion.elapsed = elapsed;
|
|
273
424
|
}
|
|
274
425
|
const taskCardRenderer = {
|
|
275
426
|
id: "task-card",
|
|
@@ -281,49 +432,64 @@ const taskCardRenderer = {
|
|
|
281
432
|
const previewBg = new Graphics();
|
|
282
433
|
const preview = new Sprite();
|
|
283
434
|
const previewMask = new Graphics();
|
|
435
|
+
const shimmer = new Graphics();
|
|
284
436
|
const previewArt = new Graphics();
|
|
285
437
|
const resolution = textResolutionForZoom(context.zoom);
|
|
286
|
-
const
|
|
438
|
+
const text = (fontFamily, fontSize, fontWeight) => new Text({
|
|
287
439
|
text: "",
|
|
288
440
|
style: {
|
|
289
|
-
fontFamily
|
|
290
|
-
fontSize
|
|
291
|
-
fontWeight
|
|
292
|
-
wordWrap: true,
|
|
293
|
-
breakWords: true
|
|
294
|
-
},
|
|
295
|
-
resolution,
|
|
296
|
-
roundPixels: true
|
|
297
|
-
});
|
|
298
|
-
const meta = new Text({
|
|
299
|
-
text: "",
|
|
300
|
-
style: {
|
|
301
|
-
fontFamily: BOARD_MONO_FONT_STACK,
|
|
302
|
-
fontSize: 10,
|
|
303
|
-
fontWeight: "500",
|
|
441
|
+
fontFamily,
|
|
442
|
+
fontSize,
|
|
443
|
+
fontWeight,
|
|
304
444
|
wordWrap: true,
|
|
305
445
|
breakWords: true
|
|
306
446
|
},
|
|
307
447
|
resolution,
|
|
308
448
|
roundPixels: true
|
|
309
449
|
});
|
|
450
|
+
const body = text(BOARD_FONT_STACK, 11.5, "500");
|
|
451
|
+
const detail = text(BOARD_FONT_STACK, 10.5, "400");
|
|
452
|
+
const meta = text(BOARD_MONO_FONT_STACK, 10, "500");
|
|
453
|
+
const badge = text(BOARD_MONO_FONT_STACK, 10, "500");
|
|
454
|
+
badge.style.wordWrap = false;
|
|
455
|
+
badge.anchor.set(.5);
|
|
456
|
+
detail.anchor.set(.5, 0);
|
|
457
|
+
detail.style.align = "center";
|
|
310
458
|
preview.mask = previewMask;
|
|
311
|
-
|
|
312
|
-
|
|
459
|
+
const content = new Container();
|
|
460
|
+
content.mask = clip;
|
|
461
|
+
content.addChild(previewBg, shimmer, preview, previewMask, previewArt, body, detail, meta, badge);
|
|
462
|
+
const tag = createCardTag();
|
|
463
|
+
root.addChild(plate, content, clip, tag.root);
|
|
313
464
|
partsByContainer.set(root, {
|
|
314
465
|
root,
|
|
466
|
+
tag,
|
|
315
467
|
plate,
|
|
316
468
|
clip,
|
|
317
469
|
previewBg,
|
|
318
470
|
preview,
|
|
319
471
|
previewMask,
|
|
472
|
+
shimmer,
|
|
320
473
|
previewArt,
|
|
474
|
+
badge,
|
|
321
475
|
body,
|
|
476
|
+
detail,
|
|
322
477
|
meta,
|
|
323
478
|
assetKey: null,
|
|
324
479
|
visualSig: "",
|
|
325
480
|
textSig: "",
|
|
326
|
-
resolution
|
|
481
|
+
resolution,
|
|
482
|
+
motion: {
|
|
483
|
+
itemId: "",
|
|
484
|
+
width: 0,
|
|
485
|
+
shimmer: false,
|
|
486
|
+
mosaic: null,
|
|
487
|
+
startedAt: null,
|
|
488
|
+
label: "",
|
|
489
|
+
elapsed: "",
|
|
490
|
+
revealFrom: null,
|
|
491
|
+
revealKey: null
|
|
492
|
+
}
|
|
327
493
|
});
|
|
328
494
|
if (item.type === "task") sync(root, item, context);
|
|
329
495
|
return root;
|
|
@@ -331,14 +497,23 @@ const taskCardRenderer = {
|
|
|
331
497
|
update: (container, item, context) => {
|
|
332
498
|
if (item.type === "task") sync(container, item, context);
|
|
333
499
|
},
|
|
500
|
+
tick: (container, clock) => {
|
|
501
|
+
const parts = partsByContainer.get(container);
|
|
502
|
+
return parts ? advance(parts, clock) : null;
|
|
503
|
+
},
|
|
504
|
+
zoom: (container, zoom) => {
|
|
505
|
+
const tag = partsByContainer.get(container)?.tag;
|
|
506
|
+
if (tag) zoomCardTag(tag, zoom);
|
|
507
|
+
},
|
|
334
508
|
renderFar: (graphics, item, context) => {
|
|
335
509
|
if (item.type !== "task") return;
|
|
336
|
-
const
|
|
510
|
+
const { status } = liveStatus(item, context);
|
|
511
|
+
const active = status === "failed" || status === "running" || status === "pending";
|
|
337
512
|
drawFarPlate(graphics, item.frame, {
|
|
338
513
|
fill: context.palette.surface,
|
|
339
514
|
fillAlpha: .82,
|
|
340
515
|
...active ? {
|
|
341
|
-
accent: statusColor(
|
|
516
|
+
accent: statusColor(status, context),
|
|
342
517
|
accentAlpha: .9
|
|
343
518
|
} : {}
|
|
344
519
|
});
|
|
@@ -351,4 +526,4 @@ const taskCardRenderer = {
|
|
|
351
526
|
}
|
|
352
527
|
};
|
|
353
528
|
//#endregion
|
|
354
|
-
export {
|
|
529
|
+
export { taskCardRenderer };
|
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
import { BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
2
|
import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
3
|
+
import { cardElevation, drawCardSurface, traceCardOutline } from "../surface.js";
|
|
3
4
|
import { positionShell } from "./base-card-renderer.js";
|
|
4
5
|
import { drawFarPlate } from "./far-plate.js";
|
|
5
6
|
import { Container, Graphics, Text } from "pixi.js";
|
|
6
7
|
//#region src/board/render/renderers/unknown-card-renderer.ts
|
|
7
|
-
const RADIUS = 10;
|
|
8
8
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
9
9
|
function sync(container, item, context) {
|
|
10
10
|
const parts = partsByContainer.get(container);
|
|
11
11
|
if (!parts) return;
|
|
12
12
|
positionShell(parts.root, item);
|
|
13
13
|
const { width, height } = item.frame;
|
|
14
|
-
const selected = context.selectedIds.has(item.id);
|
|
15
14
|
const realType = item.type;
|
|
16
15
|
syncTextResolution(parts.label, parts, context.zoom);
|
|
16
|
+
const elevation = cardElevation(context, item.id);
|
|
17
17
|
const visualSig = [
|
|
18
18
|
width,
|
|
19
19
|
height,
|
|
20
|
-
|
|
21
|
-
context.
|
|
22
|
-
context.palette.brand,
|
|
23
|
-
context.palette.border,
|
|
24
|
-
context.palette.muted
|
|
20
|
+
elevation,
|
|
21
|
+
context.themeKey
|
|
25
22
|
].join("|");
|
|
26
23
|
if (visualSig !== parts.visualSig) {
|
|
27
24
|
parts.visualSig = visualSig;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
const rect = {
|
|
26
|
+
x: 0,
|
|
27
|
+
y: 0,
|
|
28
|
+
width,
|
|
29
|
+
height
|
|
30
|
+
};
|
|
31
|
+
drawCardSurface(parts.box.clear(), rect, context.style, {
|
|
32
|
+
fill: context.palette.surface,
|
|
33
|
+
fillAlpha: .7,
|
|
34
|
+
border: context.palette.border,
|
|
35
|
+
borderAlpha: .8,
|
|
36
|
+
elevation
|
|
36
37
|
});
|
|
37
|
-
parts.box
|
|
38
|
+
traceCardOutline(parts.box, rect, context.style, -6).stroke({
|
|
38
39
|
color: context.palette.muted,
|
|
39
40
|
width: 1,
|
|
40
41
|
alpha: .4
|