@justai/cuts 0.104.0 → 0.105.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/package.json +1 -1
- package/src/Catalogue.astro +39 -5
package/package.json
CHANGED
package/src/Catalogue.astro
CHANGED
|
@@ -49,7 +49,15 @@ interface Props {
|
|
|
49
49
|
/** Layer one. Empty is valid and correct for an apex with nothing seeded yet. */
|
|
50
50
|
seed?: CatalogueEntry[];
|
|
51
51
|
/** The curated sequence, keyed by host — read by the runtime sort. */
|
|
52
|
-
order
|
|
52
|
+
/** queries: order prop · curated order · data-order · the grid is not sorted · order type
|
|
53
|
+
*
|
|
54
|
+
* THE CURATED SEQUENCE, AS A LIST OF HOSTS — which is what the runtime sort reads, and what this
|
|
55
|
+
* type said until 2026-08-05. It was declared `Record<string, number>` while the script parsed it
|
|
56
|
+
* as `string[]`; app.zone happened to pass an array so nothing ever disagreed out loud, and
|
|
57
|
+
* pin.games passed `{}` for "no order" and took the whole runtime append down with it. A type that
|
|
58
|
+
* describes something other than what the consumer reads is worse than no type: it invites the one
|
|
59
|
+
* value that will break. */
|
|
60
|
+
order?: readonly string[];
|
|
53
61
|
/** A shelf label per host: a card has one line to earn a tap, and a bio clamps. Keyed by host. */
|
|
54
62
|
taglines?: Record<string, string>;
|
|
55
63
|
/** Localized category names. The English key stays the stable filter value. */
|
|
@@ -78,7 +86,7 @@ interface Props {
|
|
|
78
86
|
}
|
|
79
87
|
const {
|
|
80
88
|
lang, kind, apexHost,
|
|
81
|
-
seed = [], order =
|
|
89
|
+
seed = [], order = [], taglines = {}, catLabels = {}, entries = {},
|
|
82
90
|
locales, strings,
|
|
83
91
|
} = Astro.props;
|
|
84
92
|
|
|
@@ -539,8 +547,15 @@ const isNew = (added: string): boolean => { const t0 = Date.parse(added || "");
|
|
|
539
547
|
// the registry — and an identifier that only matches one route fails silently on the other. A card
|
|
540
548
|
// that fails to match reads as unlisted and jumps to the top, which is the worst possible failure
|
|
541
549
|
// for an ordering bug: it looks deliberate. The host is what both routes agree on.
|
|
550
|
+
// Anything that is not a list means "no curated order" — never an exception. This parsed a
|
|
551
|
+
// `{}` once and `{}.map is not a function` killed everything after it, including the event
|
|
552
|
+
// that tells the filter new cards exist: the shelf showed a card AND "the first games are on
|
|
553
|
+
// their way" underneath it.
|
|
542
554
|
const orderList: string[] = (() => {
|
|
543
|
-
try {
|
|
555
|
+
try {
|
|
556
|
+
const parsed = JSON.parse(grid.dataset.order || "[]");
|
|
557
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
558
|
+
} catch { return []; }
|
|
544
559
|
})();
|
|
545
560
|
const rank = new Map(orderList.map((h, i) => [h, i]));
|
|
546
561
|
const UNLISTED = -1;
|
|
@@ -559,9 +574,28 @@ const isNew = (added: string): boolean => { const t0 = Date.parse(added || "");
|
|
|
559
574
|
return x.added < y.added ? 1 : -1;
|
|
560
575
|
})
|
|
561
576
|
.forEach(({ el }) => grid.appendChild(el));
|
|
562
|
-
|
|
577
|
+
// queries: the empty message shows under a card · zone:cards never fired · the filter did not
|
|
578
|
+
// see the new cards · silent catch
|
|
579
|
+
//
|
|
580
|
+
// IN A `finally`, BECAUSE EVERYTHING ABOVE IT IS ORNAMENT AND THIS IS NOT. Once cards are in
|
|
581
|
+
// the DOM, the filter has to be told — it owns which of them are visible and whether the
|
|
582
|
+
// "nothing here" line is showing. Sorting them is a nicety; leaving the page claiming to be
|
|
583
|
+
// empty while a card sits above the claim is a defect a visitor sees.
|
|
584
|
+
//
|
|
585
|
+
// It sat at the end of a promise chain ending in `.catch(() => {})`, so one TypeError in the
|
|
586
|
+
// sort silenced it with nothing logged anywhere. That combination — a throw between the work
|
|
587
|
+
// and its announcement, and a catch that says nothing — is how a page ends up confidently
|
|
588
|
+
// wrong. The `finally` fixes the ordering; the catch below now says what it swallowed.
|
|
589
|
+
})
|
|
590
|
+
.catch((err) => {
|
|
591
|
+
// Never fatal — a storefront must render without the registry. But it must not be SILENT:
|
|
592
|
+
// the seed and the build-time layer are already on the page, and a swallowed error here is
|
|
593
|
+
// the difference between "no new personas today" and "the append is broken".
|
|
594
|
+
console.warn("[catalogue] runtime append failed", err);
|
|
563
595
|
})
|
|
564
|
-
.
|
|
596
|
+
.finally(() => {
|
|
597
|
+
document.dispatchEvent(new Event("zone:cards")); // cards are in — let the filter catch them
|
|
598
|
+
});
|
|
565
599
|
})();
|
|
566
600
|
</script>
|
|
567
601
|
|