@proveanything/smartlinks-utils-ui 0.4.2 → 0.6.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/dist/{chunk-76Y4UTYQ.js → chunk-WB775Z2I.js} +66 -60
- package/dist/chunk-WB775Z2I.js.map +1 -0
- package/dist/components/RecordsAdmin/index.d.ts +133 -86
- package/dist/components/RecordsAdmin/index.js +266 -226
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/records-JWS6LKJ2.js +3 -0
- package/dist/{records-AUJWCB7Q.js.map → records-JWS6LKJ2.js.map} +1 -1
- package/package.json +6 -6
- package/dist/chunk-76Y4UTYQ.js.map +0 -1
- package/dist/records-AUJWCB7Q.js +0 -3
|
@@ -2,8 +2,8 @@ import { styleInject } from '../../chunk-HXJLROC2.js';
|
|
|
2
2
|
import { FacetRuleEditor } from '../../chunk-JMCV6FOW.js';
|
|
3
3
|
import { useFacets } from '../../chunk-4LHF5JB7.js';
|
|
4
4
|
import { cn } from '../../chunk-L7FQ52F5.js';
|
|
5
|
-
import { listRecords,
|
|
6
|
-
export { bulkDelete, bulkUpsert,
|
|
5
|
+
import { listRecords, parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, updateRecord, upsertRecord, removeRecord } from '../../chunk-WB775Z2I.js';
|
|
6
|
+
export { bulkDelete, bulkUpsert, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-WB775Z2I.js';
|
|
7
7
|
import { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext, createElement } from 'react';
|
|
8
8
|
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Rows3, List, ChevronRight, Eraser, ClipboardPaste, Box, X, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, Search, CornerDownLeft, Circle, AlertCircle, Undo2, Save, Target, Settings2 } from 'lucide-react';
|
|
9
9
|
import { useQueryClient, useInfiniteQuery, useQuery } from '@tanstack/react-query';
|
|
@@ -138,7 +138,7 @@ var ALL_ITEM_VIEWS = ["table", "cards", "gallery"];
|
|
|
138
138
|
|
|
139
139
|
// src/components/RecordsAdmin/types/deepLink.ts
|
|
140
140
|
var DEFAULT_DEEP_LINK_PARAM_NAMES = {
|
|
141
|
-
|
|
141
|
+
recordId: "recordId",
|
|
142
142
|
scope: "scope",
|
|
143
143
|
view: "view"
|
|
144
144
|
};
|
|
@@ -150,11 +150,7 @@ var KIND_KEYS = {
|
|
|
150
150
|
variant: "variantId",
|
|
151
151
|
batch: "batchId",
|
|
152
152
|
proof: "proofId",
|
|
153
|
-
collection: "collectionId"
|
|
154
|
-
// `rule` records carry an opaque id under the `rule:` prefix; we expose
|
|
155
|
-
// the id via `productId`-equivalent slot to keep ParsedRef flat. Resolved
|
|
156
|
-
// refs use the `ruleId` field (added below) so callers can disambiguate.
|
|
157
|
-
rule: "ruleId"
|
|
153
|
+
collection: "collectionId"
|
|
158
154
|
};
|
|
159
155
|
var parseRef = (raw) => {
|
|
160
156
|
const parsed = { kind: "collection", raw };
|
|
@@ -174,11 +170,9 @@ var parseRef = (raw) => {
|
|
|
174
170
|
} else {
|
|
175
171
|
parsed.facetId = id;
|
|
176
172
|
}
|
|
177
|
-
} else if (k === "item") {
|
|
178
|
-
parsed.itemId = id;
|
|
179
|
-
continue;
|
|
180
173
|
} else if (k in KIND_KEYS) {
|
|
181
|
-
|
|
174
|
+
const slot = KIND_KEYS[k];
|
|
175
|
+
parsed[slot] = id;
|
|
182
176
|
}
|
|
183
177
|
if (k !== "collection") kind = k;
|
|
184
178
|
}
|
|
@@ -194,7 +188,6 @@ var buildRef = (a) => {
|
|
|
194
188
|
if (a.variantId) parts.push(`variant:${a.variantId}`);
|
|
195
189
|
if (a.batchId) parts.push(`batch:${a.batchId}`);
|
|
196
190
|
if (a.proofId) parts.push(`proof:${a.proofId}`);
|
|
197
|
-
if (a.itemId) parts.push(`item:${a.itemId}`);
|
|
198
191
|
return parts.join("/");
|
|
199
192
|
};
|
|
200
193
|
var resolutionChain = (target, supportedScopes) => {
|
|
@@ -216,35 +209,26 @@ var resolutionChain = (target, supportedScopes) => {
|
|
|
216
209
|
}
|
|
217
210
|
return Array.from(new Set(chain));
|
|
218
211
|
};
|
|
219
|
-
var splitItemRef = (raw) => {
|
|
220
|
-
if (!raw) return { scopeRef: "" };
|
|
221
|
-
const segs = raw.split("/").filter(Boolean);
|
|
222
|
-
const last = segs[segs.length - 1];
|
|
223
|
-
if (last && last.startsWith("item:")) {
|
|
224
|
-
return { scopeRef: segs.slice(0, -1).join("/"), itemId: last.slice("item:".length) };
|
|
225
|
-
}
|
|
226
|
-
return { scopeRef: raw };
|
|
227
|
-
};
|
|
228
|
-
var buildItemRef = (scopeRef, itemId) => {
|
|
229
|
-
return scopeRef ? `${scopeRef}/item:${itemId}` : `item:${itemId}`;
|
|
230
|
-
};
|
|
231
212
|
var defaultClassify = (r) => {
|
|
232
213
|
if (!r.data) return "empty";
|
|
233
214
|
const keys = Object.keys(r.data);
|
|
234
215
|
if (keys.length === 0) return "empty";
|
|
235
216
|
return "configured";
|
|
236
217
|
};
|
|
237
|
-
var matchesScope = (kind, rec,
|
|
238
|
-
const hasRule = !!rec.facetRule
|
|
218
|
+
var matchesScope = (kind, rec, _p) => {
|
|
219
|
+
const hasRule = !!rec.facetRule;
|
|
239
220
|
if (kind === "rule") return hasRule;
|
|
240
221
|
if (hasRule) return false;
|
|
222
|
+
const productId = rec.productId ?? void 0;
|
|
223
|
+
const variantId = rec.variantId ?? void 0;
|
|
224
|
+
const batchId = rec.batchId ?? void 0;
|
|
225
|
+
const proofId = rec.proofId ?? void 0;
|
|
241
226
|
if (kind === "collection") {
|
|
242
|
-
return !
|
|
227
|
+
return !productId && !variantId && !batchId && !proofId;
|
|
243
228
|
}
|
|
244
|
-
if (kind === "product") return !!
|
|
245
|
-
if (kind === "
|
|
246
|
-
if (kind === "
|
|
247
|
-
if (kind === "batch") return !!p.batchId;
|
|
229
|
+
if (kind === "product") return !!productId && !variantId && !batchId;
|
|
230
|
+
if (kind === "variant") return !!variantId;
|
|
231
|
+
if (kind === "batch") return !!batchId;
|
|
248
232
|
return false;
|
|
249
233
|
};
|
|
250
234
|
var matchesContext = (p, ctx) => {
|
|
@@ -256,10 +240,22 @@ var matchesContext = (p, ctx) => {
|
|
|
256
240
|
};
|
|
257
241
|
var toSummary = (rec) => {
|
|
258
242
|
const ref = rec.ref ?? "";
|
|
259
|
-
const
|
|
243
|
+
const productId = rec.productId ?? void 0;
|
|
244
|
+
const variantId = rec.variantId ?? void 0;
|
|
245
|
+
const batchId = rec.batchId ?? void 0;
|
|
246
|
+
const proofId = rec.proofId ?? void 0;
|
|
247
|
+
const scope = {
|
|
248
|
+
kind: batchId ? "batch" : variantId ? "variant" : productId ? "product" : "collection",
|
|
249
|
+
raw: ref,
|
|
250
|
+
productId,
|
|
251
|
+
variantId,
|
|
252
|
+
batchId,
|
|
253
|
+
proofId
|
|
254
|
+
};
|
|
260
255
|
const facetRule = rec.facetRule ?? null;
|
|
256
|
+
if (facetRule) scope.kind = "rule";
|
|
261
257
|
const ruleLabel = facetRule && facetRule.all && facetRule.all.length > 0 ? facetRule.all.length === 1 ? "Rule \xB7 1 facet" : `Rule \xB7 ${facetRule.all.length} facets` : null;
|
|
262
|
-
const fallbackLabel = scope.batchId ?? scope.variantId ?? scope.productId ??
|
|
258
|
+
const fallbackLabel = scope.batchId ?? scope.variantId ?? scope.productId ?? ruleLabel ?? (ref || "Global record");
|
|
263
259
|
return {
|
|
264
260
|
id: rec.id,
|
|
265
261
|
ref,
|
|
@@ -365,57 +361,65 @@ var useRecordList = (args) => {
|
|
|
365
361
|
|
|
366
362
|
// src/components/RecordsAdmin/data/resolveRecord.ts
|
|
367
363
|
var resolveRecord = async (args) => {
|
|
368
|
-
if (args.target.kind === "rule" && args.target.raw) {
|
|
369
|
-
const rec = await getRecordByRef(args.ctx, args.target.raw).catch(() => null);
|
|
370
|
-
if (!rec) return { data: null, source: "empty" };
|
|
371
|
-
const recFacetRule = rec.facetRule ?? null;
|
|
372
|
-
return {
|
|
373
|
-
data: rec.data,
|
|
374
|
-
source: "self",
|
|
375
|
-
sourceRef: rec.ref ?? args.target.raw,
|
|
376
|
-
facetRule: recFacetRule
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
364
|
const target = parsedRefToTarget(args.target);
|
|
380
365
|
const editingScope = parsedRefToScope(args.target);
|
|
381
366
|
const result = await matchRecords(args.ctx, target, { strategy: "all" }).catch(() => null);
|
|
382
|
-
const
|
|
367
|
+
const entries = result?.data ?? [];
|
|
383
368
|
console.info("[RecordsAdmin/resolveRecord]", {
|
|
384
369
|
editingScope,
|
|
385
370
|
target,
|
|
386
|
-
matchCount:
|
|
387
|
-
|
|
388
|
-
|
|
371
|
+
matchCount: entries.length,
|
|
372
|
+
winnerAnchors: entries[0] && {
|
|
373
|
+
productId: entries[0].productId,
|
|
374
|
+
variantId: entries[0].variantId,
|
|
375
|
+
batchId: entries[0].batchId,
|
|
376
|
+
proofId: entries[0].proofId
|
|
377
|
+
},
|
|
378
|
+
winnerRef: entries[0]?.ref
|
|
389
379
|
});
|
|
390
|
-
if (
|
|
380
|
+
if (entries.length === 0) {
|
|
391
381
|
return { data: null, source: "empty" };
|
|
392
382
|
}
|
|
393
|
-
const
|
|
394
|
-
const
|
|
395
|
-
|
|
383
|
+
const winner = entries[0];
|
|
384
|
+
const winnerIsSelf = scopesEqual(
|
|
385
|
+
{
|
|
386
|
+
productId: winner.productId,
|
|
387
|
+
variantId: winner.variantId,
|
|
388
|
+
batchId: winner.batchId,
|
|
389
|
+
proofId: winner.proofId
|
|
390
|
+
},
|
|
391
|
+
editingScope
|
|
392
|
+
);
|
|
396
393
|
console.info("[RecordsAdmin/resolveRecord] classification", {
|
|
397
394
|
winnerIsSelf,
|
|
398
|
-
|
|
395
|
+
winnerAnchors: {
|
|
396
|
+
productId: winner.productId,
|
|
397
|
+
variantId: winner.variantId,
|
|
398
|
+
batchId: winner.batchId,
|
|
399
|
+
proofId: winner.proofId
|
|
400
|
+
},
|
|
399
401
|
editingScope
|
|
400
402
|
});
|
|
401
403
|
if (winnerIsSelf) {
|
|
402
|
-
const parent =
|
|
404
|
+
const parent = entries[1];
|
|
403
405
|
return {
|
|
404
406
|
data: winner.data,
|
|
405
407
|
source: "self",
|
|
406
408
|
sourceRef: winner.ref ?? void 0,
|
|
409
|
+
recordId: winner.id,
|
|
407
410
|
parentValue: args.withParent && parent ? parent.data : void 0,
|
|
408
|
-
matchedAt:
|
|
409
|
-
matchedRule:
|
|
411
|
+
matchedAt: winner.matchedAt,
|
|
412
|
+
matchedRule: winner.matchedRule
|
|
410
413
|
};
|
|
411
414
|
}
|
|
412
415
|
return {
|
|
413
416
|
data: winner.data,
|
|
414
417
|
source: "inherited",
|
|
415
418
|
sourceRef: winner.ref ?? void 0,
|
|
419
|
+
recordId: winner.id,
|
|
416
420
|
parentValue: args.withParent ? winner.data : void 0,
|
|
417
|
-
matchedAt:
|
|
418
|
-
matchedRule:
|
|
421
|
+
matchedAt: winner.matchedAt,
|
|
422
|
+
matchedRule: winner.matchedRule
|
|
419
423
|
};
|
|
420
424
|
};
|
|
421
425
|
|
|
@@ -433,7 +437,7 @@ var resolvedRecordQueryKey = (args) => [
|
|
|
433
437
|
args.facetId ?? null,
|
|
434
438
|
args.facetValue ?? null,
|
|
435
439
|
args.proofId ?? null,
|
|
436
|
-
args.
|
|
440
|
+
args.recordId ?? null,
|
|
437
441
|
args.withParent ?? true
|
|
438
442
|
];
|
|
439
443
|
function useResolvedRecord(args) {
|
|
@@ -448,7 +452,7 @@ function useResolvedRecord(args) {
|
|
|
448
452
|
facetId,
|
|
449
453
|
facetValue,
|
|
450
454
|
proofId,
|
|
451
|
-
|
|
455
|
+
recordId,
|
|
452
456
|
supportedScopes = DEFAULT_SCOPES,
|
|
453
457
|
enabled = true,
|
|
454
458
|
withParent = true
|
|
@@ -464,19 +468,35 @@ function useResolvedRecord(args) {
|
|
|
464
468
|
facetId,
|
|
465
469
|
facetValue,
|
|
466
470
|
proofId,
|
|
467
|
-
|
|
471
|
+
recordId,
|
|
468
472
|
withParent
|
|
469
473
|
}),
|
|
470
474
|
enabled: enabled && !!collectionId && !!appId,
|
|
471
475
|
staleTime: 15e3,
|
|
472
476
|
queryFn: async () => {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
477
|
+
if (recordId) {
|
|
478
|
+
const rec = await getRecordById({ SL, collectionId, appId, recordType }, recordId);
|
|
479
|
+
if (!rec) return { data: null, source: "empty" };
|
|
480
|
+
const recFacetRule = rec.facetRule ?? null;
|
|
481
|
+
return {
|
|
482
|
+
data: rec.data,
|
|
483
|
+
source: "self",
|
|
484
|
+
sourceRef: rec.ref ?? void 0,
|
|
485
|
+
recordId: rec.id,
|
|
486
|
+
facetRule: recFacetRule
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const target = {
|
|
490
|
+
kind: batchId ? "batch" : variantId ? "variant" : productId ? "product" : facetId ? "facet" : "collection",
|
|
491
|
+
raw: "",
|
|
492
|
+
collectionId,
|
|
493
|
+
productId,
|
|
494
|
+
variantId,
|
|
495
|
+
batchId,
|
|
496
|
+
facetId,
|
|
497
|
+
facetValue,
|
|
498
|
+
proofId
|
|
499
|
+
};
|
|
480
500
|
return resolveRecord({
|
|
481
501
|
ctx: { SL, collectionId, appId, recordType },
|
|
482
502
|
target,
|
|
@@ -527,8 +547,8 @@ function useRulePreview(args) {
|
|
|
527
547
|
})
|
|
528
548
|
});
|
|
529
549
|
return {
|
|
530
|
-
totalMatches: query.data?.
|
|
531
|
-
sampleProductIds: query.data?.
|
|
550
|
+
totalMatches: query.data?.total ?? null,
|
|
551
|
+
sampleProductIds: (query.data?.matchingProducts ?? []).map((p) => p.productId),
|
|
532
552
|
isLoading: query.isFetching,
|
|
533
553
|
isStale: rule !== debouncedRule,
|
|
534
554
|
error: query.error ?? null
|
|
@@ -594,7 +614,10 @@ function useRecordEditor(args) {
|
|
|
594
614
|
}, [scope.raw, resolved.source, resolved.sourceRef]);
|
|
595
615
|
const isDirty = !isEqual(value, savedSnapshot) || !isEqual(facetRule, savedFacetRule);
|
|
596
616
|
const save = useCallback(async () => {
|
|
597
|
-
|
|
617
|
+
const anchors = parsedRefToScope(scope);
|
|
618
|
+
const hasAnchors = !!(anchors.productId || anchors.variantId || anchors.batchId || anchors.proofId);
|
|
619
|
+
const hasRule = !!(facetRule && facetRule.all && facetRule.all.length > 0);
|
|
620
|
+
if (!hasAnchors && !hasRule && !scope.raw) return;
|
|
598
621
|
const previousSnapshot = savedSnapshot;
|
|
599
622
|
const previousRuleSnapshot = savedFacetRule;
|
|
600
623
|
resolved.source;
|
|
@@ -608,7 +631,7 @@ function useRecordEditor(args) {
|
|
|
608
631
|
facetId: scope.facetId,
|
|
609
632
|
facetValue: scope.facetValue,
|
|
610
633
|
proofId: scope.proofId,
|
|
611
|
-
|
|
634
|
+
recordId: resolved.recordId,
|
|
612
635
|
withParent: true
|
|
613
636
|
});
|
|
614
637
|
const previousCache = queryClient.getQueryData(cacheKey);
|
|
@@ -621,15 +644,26 @@ function useRecordEditor(args) {
|
|
|
621
644
|
data: value,
|
|
622
645
|
source: "self",
|
|
623
646
|
sourceRef: scope.raw,
|
|
647
|
+
recordId: resolved.recordId,
|
|
624
648
|
parentValue: previousCache?.parentValue ?? resolved.parentValue
|
|
625
649
|
});
|
|
626
650
|
try {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
651
|
+
if (resolved.recordId && resolved.source === "self") {
|
|
652
|
+
await updateRecord(ctx, resolved.recordId, {
|
|
653
|
+
data: value,
|
|
654
|
+
facetRule
|
|
655
|
+
});
|
|
656
|
+
} else {
|
|
657
|
+
await upsertRecord(ctx, {
|
|
658
|
+
// External ref only when the underlying scope already carries
|
|
659
|
+
// one (e.g. rule:{id} for an existing rule record). Empty for
|
|
660
|
+
// anchor-only writes — server addresses by anchors.
|
|
661
|
+
ref: scope.kind === "rule" && scope.raw ? scope.raw : void 0,
|
|
662
|
+
scope: anchors,
|
|
663
|
+
data: value,
|
|
664
|
+
facetRule
|
|
665
|
+
});
|
|
666
|
+
}
|
|
633
667
|
onSaved?.();
|
|
634
668
|
} catch (err) {
|
|
635
669
|
setSavedSnapshot(previousSnapshot);
|
|
@@ -646,16 +680,17 @@ function useRecordEditor(args) {
|
|
|
646
680
|
} finally {
|
|
647
681
|
setIsSaving(false);
|
|
648
682
|
}
|
|
649
|
-
}, [scope.raw, value, savedSnapshot, facetRule, savedFacetRule, resolved.source, resolved.parentValue]);
|
|
683
|
+
}, [scope.raw, value, savedSnapshot, facetRule, savedFacetRule, resolved.source, resolved.parentValue, resolved.recordId]);
|
|
650
684
|
const reset = useCallback(() => {
|
|
651
685
|
setValue(savedSnapshot);
|
|
652
686
|
setFacetRule(savedFacetRule);
|
|
653
687
|
}, [savedSnapshot, savedFacetRule]);
|
|
654
688
|
const remove = useCallback(async () => {
|
|
655
|
-
if (resolved.source !== "self"
|
|
656
|
-
|
|
689
|
+
if (resolved.source !== "self") return;
|
|
690
|
+
if (!resolved.recordId) return;
|
|
691
|
+
await removeRecord(ctx, resolved.recordId);
|
|
657
692
|
onDeleted?.();
|
|
658
|
-
}, [resolved.source,
|
|
693
|
+
}, [resolved.source, resolved.recordId]);
|
|
659
694
|
const effectiveSource = optimisticSource ?? resolved.source;
|
|
660
695
|
const isRuleScope = scope.kind === "rule";
|
|
661
696
|
const ruleValid = !isRuleScope || isFacetRuleValid(facetRule);
|
|
@@ -1649,9 +1684,11 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
|
1649
1684
|
};
|
|
1650
1685
|
var RecordList = ({
|
|
1651
1686
|
items,
|
|
1652
|
-
|
|
1687
|
+
selectedId,
|
|
1688
|
+
selectedAnchorKey,
|
|
1653
1689
|
onSelect,
|
|
1654
|
-
|
|
1690
|
+
dirtyId,
|
|
1691
|
+
dirtyAnchorKey,
|
|
1655
1692
|
presentation = "list",
|
|
1656
1693
|
renderListRow,
|
|
1657
1694
|
groupBy,
|
|
@@ -1659,10 +1696,14 @@ var RecordList = ({
|
|
|
1659
1696
|
}) => {
|
|
1660
1697
|
const buildCtx = (item) => {
|
|
1661
1698
|
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
1699
|
+
const idMatch = selectedId != null && item.id != null && item.id === selectedId;
|
|
1700
|
+
const anchorMatch = selectedAnchorKey != null && item.ref === selectedAnchorKey;
|
|
1701
|
+
const dirtyIdMatch = dirtyId != null && item.id != null && item.id === dirtyId;
|
|
1702
|
+
const dirtyAnchorMatch = dirtyAnchorKey != null && item.ref === dirtyAnchorKey;
|
|
1662
1703
|
return {
|
|
1663
|
-
selected:
|
|
1704
|
+
selected: idMatch || anchorMatch,
|
|
1664
1705
|
onSelect: () => onSelect(item),
|
|
1665
|
-
isDirty:
|
|
1706
|
+
isDirty: dirtyIdMatch || dirtyAnchorMatch,
|
|
1666
1707
|
...cb ?? {}
|
|
1667
1708
|
};
|
|
1668
1709
|
};
|
|
@@ -1684,7 +1725,7 @@ var RecordList = ({
|
|
|
1684
1725
|
const compact = presentation === "compact";
|
|
1685
1726
|
return /* @__PURE__ */ jsx("ul", { children: rows.map((item) => {
|
|
1686
1727
|
const ctx = buildCtx(item);
|
|
1687
|
-
return /* @__PURE__ */ jsx("li", { children: renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }) }, item.ref);
|
|
1728
|
+
return /* @__PURE__ */ jsx("li", { children: renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }) }, item.id ?? item.ref);
|
|
1688
1729
|
}) });
|
|
1689
1730
|
};
|
|
1690
1731
|
if (groups) {
|
|
@@ -2048,12 +2089,18 @@ function useItemViewPref(args) {
|
|
|
2048
2089
|
var QK_BASE2 = ["records-admin", "collection-items"];
|
|
2049
2090
|
var defaultToSummary = (rec, base) => {
|
|
2050
2091
|
const data = rec.data;
|
|
2092
|
+
const display = data?.display ?? void 0;
|
|
2051
2093
|
if (!data) return base;
|
|
2052
|
-
const label = data.title ?? data.name ?? data.label ?? data.question ?? base.label;
|
|
2053
|
-
const subtitle = data.subtitle ?? data.summary ?? data.description ?? base.subtitle;
|
|
2054
|
-
const thumbnail = data.thumbnail ?? data.image ?? data.cover ?? base.thumbnail;
|
|
2094
|
+
const label = data.title ?? display?.title ?? data.name ?? data.label ?? data.question ?? data.slug ?? base.label;
|
|
2095
|
+
const subtitle = data.subtitle ?? data.summary ?? display?.description ?? data.description ?? base.subtitle;
|
|
2096
|
+
const thumbnail = data.thumbnail ?? data.image ?? data.cover ?? data.home_image_url ?? base.thumbnail;
|
|
2055
2097
|
return { ...base, label, subtitle, thumbnail };
|
|
2056
2098
|
};
|
|
2099
|
+
var recordMatchesScope = (rec, scope) => {
|
|
2100
|
+
const facetRule = rec.facetRule ?? null;
|
|
2101
|
+
if (facetRule) return false;
|
|
2102
|
+
return (rec.productId ?? void 0) === scope.productId && (rec.variantId ?? void 0) === scope.variantId && (rec.batchId ?? void 0) === scope.batchId && (rec.proofId ?? void 0) === scope.proofId;
|
|
2103
|
+
};
|
|
2057
2104
|
function useCollectionItems(args) {
|
|
2058
2105
|
const {
|
|
2059
2106
|
ctx,
|
|
@@ -2064,7 +2111,6 @@ function useCollectionItems(args) {
|
|
|
2064
2111
|
} = args;
|
|
2065
2112
|
const queryClient = useQueryClient();
|
|
2066
2113
|
const scopeRef = scope?.raw ?? "";
|
|
2067
|
-
const refPrefix = scopeRef ? `${scopeRef}/item:` : "item:";
|
|
2068
2114
|
const queryKey = useMemo(
|
|
2069
2115
|
() => [...QK_BASE2, ctx.collectionId, ctx.appId, ctx.recordType, scopeRef],
|
|
2070
2116
|
[ctx.collectionId, ctx.appId, ctx.recordType, scopeRef]
|
|
@@ -2077,8 +2123,7 @@ function useCollectionItems(args) {
|
|
|
2077
2123
|
const offset = pageParam;
|
|
2078
2124
|
const { data, total, hasMore } = await listRecords(ctx, {
|
|
2079
2125
|
limit: pageSize,
|
|
2080
|
-
offset
|
|
2081
|
-
refPrefix
|
|
2126
|
+
offset
|
|
2082
2127
|
});
|
|
2083
2128
|
return { data, total, hasMore, nextOffset: offset + data.length };
|
|
2084
2129
|
},
|
|
@@ -2086,25 +2131,26 @@ function useCollectionItems(args) {
|
|
|
2086
2131
|
staleTime: 15e3
|
|
2087
2132
|
});
|
|
2088
2133
|
const items = useMemo(() => {
|
|
2134
|
+
if (!scope) return [];
|
|
2089
2135
|
const all = query.data?.pages.flatMap((p) => p.data) ?? [];
|
|
2090
|
-
|
|
2136
|
+
const relevant = all.filter((rec) => recordMatchesScope(rec, scope));
|
|
2137
|
+
return relevant.map((rec) => {
|
|
2091
2138
|
const ref = rec.ref ?? "";
|
|
2092
2139
|
const parsed = parseRef(ref);
|
|
2093
|
-
const
|
|
2094
|
-
if (!itemId) return null;
|
|
2140
|
+
const stableItemId = rec.id;
|
|
2095
2141
|
const base = {
|
|
2096
2142
|
id: rec.id,
|
|
2097
2143
|
ref,
|
|
2098
2144
|
scope: parsed,
|
|
2099
2145
|
data: rec.data ?? null,
|
|
2100
2146
|
status: rec.data ? "configured" : "empty",
|
|
2101
|
-
label:
|
|
2147
|
+
label: stableItemId,
|
|
2102
2148
|
updatedAt: rec.updatedAt,
|
|
2103
|
-
itemId
|
|
2149
|
+
itemId: stableItemId
|
|
2104
2150
|
};
|
|
2105
2151
|
return toSummary2(rec, base);
|
|
2106
2152
|
}).filter((x) => x !== null);
|
|
2107
|
-
}, [query.data, toSummary2]);
|
|
2153
|
+
}, [query.data, toSummary2, scope]);
|
|
2108
2154
|
const refetch = useCallback(() => {
|
|
2109
2155
|
queryClient.invalidateQueries({ queryKey });
|
|
2110
2156
|
}, [queryClient, queryKey]);
|
|
@@ -2146,7 +2192,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2146
2192
|
if (typeof window === "undefined") return {};
|
|
2147
2193
|
const params = new URLSearchParams(getQueryString(window.location));
|
|
2148
2194
|
return {
|
|
2149
|
-
|
|
2195
|
+
recordId: params.get(paramNames.recordId),
|
|
2150
2196
|
scope: params.get(paramNames.scope),
|
|
2151
2197
|
view: params.get(paramNames.view)
|
|
2152
2198
|
};
|
|
@@ -2158,7 +2204,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2158
2204
|
if (value == null || value === "") params.delete(key);
|
|
2159
2205
|
else params.set(key, value);
|
|
2160
2206
|
};
|
|
2161
|
-
if ("
|
|
2207
|
+
if ("recordId" in partial) apply(paramNames.recordId, partial.recordId);
|
|
2162
2208
|
if ("scope" in partial) apply(paramNames.scope, partial.scope);
|
|
2163
2209
|
if ("view" in partial) apply(paramNames.view, partial.view);
|
|
2164
2210
|
const nextUrl = buildUrl(window.location, params.toString());
|
|
@@ -2178,7 +2224,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2178
2224
|
});
|
|
2179
2225
|
|
|
2180
2226
|
// src/components/RecordsAdmin/hooks/useDeepLinkState.ts
|
|
2181
|
-
var SMART_PUSH = ["
|
|
2227
|
+
var SMART_PUSH = ["record.open", "record.close", "scope"];
|
|
2182
2228
|
var classify = (mode, kind) => {
|
|
2183
2229
|
if (mode === "push") return "push";
|
|
2184
2230
|
if (mode === "replace") return "replace";
|
|
@@ -3831,19 +3877,10 @@ var downloadBlob = (blob, filename) => {
|
|
|
3831
3877
|
styleInject(':root {\n --ra-status-own: var(--ra-emerald, 142 71% 45%);\n --ra-status-shared: var(--ra-amber, 38 92% 50%);\n --ra-status-missing: var(--muted-foreground, 220 9% 46%);\n --ra-accent: var(--primary, 222 47% 11%);\n --ra-surface: var(--card, 0 0% 100%);\n --ra-border: var(--border, 220 13% 91%);\n --ra-text: var(--foreground, 222 47% 11%);\n --ra-muted: var(--muted, 220 14% 96%);\n --ra-muted-text: var(--muted-foreground, 220 9% 46%);\n --ra-radius: var(--radius, 0.625rem);\n --ra-dot-size: 0.5rem;\n --ra-page-bg: var(--background, 220 14% 98%);\n --ra-card-shadow: 0 1px 2px hsl(var(--ra-accent) / 0.04), 0 4px 12px hsl(var(--ra-accent) / 0.05);\n --ra-card-shadow-hover: 0 2px 4px hsl(var(--ra-accent) / 0.06), 0 8px 24px hsl(var(--ra-accent) / 0.08);\n --ra-row-hover: hsl(var(--ra-accent) / 0.05);\n --ra-row-active-bg: hsl(var(--ra-accent) / 0.10);\n --ra-row-active-bd: hsl(var(--ra-accent) / 0.45);\n --ra-focus-ring: hsl(var(--ra-accent) / 0.35);\n --ra-font-display: var(--font-display, var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif));\n --ra-font-ui: var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);\n --ra-title-weight: 600;\n --ra-display-weight: 700;\n --ra-info: var(--ra-blue, 214 95% 55%);\n --ra-success: var(--ra-emerald, 142 71% 45%);\n --ra-warning: var(--ra-amber, 38 92% 50%);\n --ra-danger: var(--destructive, 0 72% 51%);\n}\n:root {\n --sl-control-bg: var(--muted, 220 14% 96%);\n --sl-control-fg: var(--muted-foreground, 220 9% 40%);\n --sl-control-border: var(--border, 220 13% 88%);\n --sl-control-active-bg: var(--primary, 222 47% 11%);\n --sl-control-active-fg: var(--primary-foreground, 0 0% 100%);\n --sl-control-active-bd: var(--primary, 222 47% 11%);\n --sl-control-hover-bg: var(--sl-control-active-bg, 222 47% 11%);\n --sl-control-hover-fg: var(--foreground, 222 47% 11%);\n --sl-control-focus-ring: var(--sl-control-active-bg, 222 47% 11%);\n --sl-control-radius: var(--radius, 0.5rem);\n --sl-control-weight: 500;\n --sl-control-active-weight: 600;\n}\n.ra-status-dot {\n display: inline-block;\n width: var(--ra-dot-size);\n height: var(--ra-dot-size);\n border-radius: 9999px;\n flex-shrink: 0;\n}\n.ra-status-own {\n background: hsl(var(--ra-status-own));\n}\n.ra-status-shared {\n background: hsl(var(--ra-status-shared));\n}\n.ra-status-missing {\n background: hsl(var(--ra-status-missing) / 0.4);\n border: 1px solid hsl(var(--ra-status-missing) / 0.6);\n}\n.ra-row-active {\n background: var(--ra-row-active-bg);\n border-color: var(--ra-row-active-bd) !important;\n}\n');
|
|
3832
3878
|
|
|
3833
3879
|
// src/components/RecordsAdmin/shell/shell.css
|
|
3834
|
-
styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-header-stats--titled {\n flex-direction: column;\n align-items: stretch;\n padding: 0.4rem 0.55rem;\n gap: 0.3rem;\n}\n.ra-shell .ra-header-stats .ra-stats-items {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n}\n.ra-shell .ra-header-stats .ra-stats-heading {\n display: flex;\n align-items: center;\n gap: 0.35rem;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon {\n display: inline-flex;\n align-items: center;\n color: hsl(var(--ra-text));\n opacity: 0.75;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon > svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--sl-control-bg));\n border-radius: var(--sl-control-radius);\n border: 1px solid hsl(var(--sl-control-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--sl-control-radius) - 2px);\n font-size: 0.78rem;\n font-weight: var(--sl-control-weight);\n color: hsl(var(--sl-control-fg));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--sl-control-hover-bg) / 0.10);\n color: hsl(var(--sl-control-hover-fg));\n}\n.ra-shell .ra-tab:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px hsl(var(--sl-control-focus-ring) / 0.45);\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--sl-control-active-bg));\n color: hsl(var(--sl-control-active-fg));\n border-color: hsl(var(--sl-control-active-bd));\n font-weight: var(--sl-control-active-weight);\n box-shadow: 0 1px 2px hsl(var(--sl-control-active-bg) / 0.25);\n}\n.ra-shell .ra-tab[aria-selected=true]:hover {\n background: hsl(var(--sl-control-active-bg) / 0.92);\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--sl-control-active-fg) / 0.20);\n color: hsl(var(--sl-control-active-fg));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--sl-control-fg) / 0.15);\n color: hsl(var(--sl-control-fg));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n text-align: left;\n padding: 0.45rem 0.75rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-compact {\n padding-block: 0.3rem;\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.8125rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.6875rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.05rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-rule-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.2rem;\n margin-top: 0.2rem;\n}\n.ra-shell .ra-rule-chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n border-radius: 999px;\n font-size: 0.625rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.20);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-rule-chip-more {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell[data-density=compact] .ra-row-rule-chips {\n margin-top: 0.15rem;\n gap: 0.15rem;\n}\n.ra-shell[data-density=compact] .ra-rule-chip {\n font-size: 0.6rem;\n padding: 0.02rem 0.35rem;\n}\n.ra-shell .ra-rule-filters {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n}\n.ra-shell .ra-rule-filters-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n.ra-shell .ra-rule-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.65rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n transition:\n background .12s ease,\n color .12s ease,\n border-color .12s ease;\n max-width: 100%;\n}\n.ra-shell .ra-rule-filter-chip:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n border-color: hsl(var(--ra-accent) / 0.25);\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip[data-tone=complexity][data-active=true] {\n background: hsl(var(--ra-info) / 0.15);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 9rem;\n}\n.ra-shell .ra-rule-filter-chip-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.1rem;\n height: 1rem;\n padding: 0 0.3rem;\n border-radius: 999px;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n font-size: 0.6rem;\n font-weight: 600;\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] .ra-rule-filter-chip-count {\n background: hsl(var(--ra-accent) / 0.18);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-rule-filter-clear {\n align-self: flex-start;\n background: transparent;\n border: 0;\n padding: 0;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n cursor: pointer;\n text-decoration: underline;\n text-decoration-style: dotted;\n}\n.ra-shell .ra-rule-filter-clear:hover {\n color: hsl(var(--ra-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.3rem;\n gap: 0.45rem;\n}\n.ra-shell[data-density=compact] .ra-row-title {\n font-size: 0.78125rem;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n margin-bottom: 1rem;\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 60;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n.ra-confirm-root {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n}\n.ra-confirm-root .ra-confirm-backdrop {\n position: absolute;\n inset: 0;\n background: hsl(0 0% 0% / 0.45);\n backdrop-filter: blur(2px);\n animation: ra-confirm-fade .12s ease-out;\n}\n.ra-confirm-root .ra-confirm-card {\n position: relative;\n width: min(440px, 100%);\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: 0 1px 2px hsl(0 0% 0% / 0.08), 0 24px 48px -12px hsl(0 0% 0% / 0.32);\n padding: 1.25rem;\n animation: ra-confirm-pop .14s ease-out;\n}\n.ra-confirm-root .ra-confirm-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 0.5rem;\n}\n.ra-confirm-root .ra-confirm-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 999px;\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.12);\n color: hsl(var(--ra-warning, 38 92% 50%));\n}\n.ra-confirm-root .ra-confirm-title {\n font-family: var(--ra-font-display);\n font-weight: 600;\n font-size: 1rem;\n margin: 0;\n}\n.ra-confirm-root .ra-confirm-body {\n font-size: 0.875rem;\n color: hsl(var(--ra-muted-text));\n margin: 0 0 1.1rem;\n line-height: 1.45;\n}\n.ra-confirm-root .ra-confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.ra-confirm-root .ra-confirm-btn {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.45rem 0.85rem;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease;\n}\n.ra-confirm-root .ra-confirm-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-confirm-root .ra-confirm-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-confirm-root .ra-confirm-btn-ghost:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-confirm-root .ra-confirm-btn-danger {\n background: transparent;\n color: hsl(var(--ra-danger, 0 72% 51%));\n border-color: hsl(var(--ra-danger, 0 72% 51%) / 0.45);\n}\n.ra-confirm-root .ra-confirm-btn-danger:hover {\n background: hsl(var(--ra-danger, 0 72% 51%) / 0.08);\n border-color: hsl(var(--ra-danger, 0 72% 51%));\n}\n.ra-confirm-root .ra-confirm-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-confirm-root .ra-confirm-btn-primary:hover {\n filter: brightness(0.95);\n}\n@keyframes ra-confirm-fade {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes ra-confirm-pop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ra-shell .ra-unsaved-banner {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 0.75rem;\n border: 1px solid hsl(var(--ra-warning, 38 92% 50%) / 0.35);\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.08);\n border-radius: var(--ra-radius);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n animation: ra-unsaved-slide .14s ease-out;\n}\n.ra-shell .ra-unsaved-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-warning, 38 92% 50%));\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ra-shell .ra-unsaved-context {\n color: hsl(var(--ra-muted-text));\n font-weight: 400;\n}\n.ra-shell .ra-unsaved-error {\n color: hsl(var(--ra-danger, 0 72% 51%));\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-weight: 500;\n}\n.ra-shell .ra-unsaved-actions {\n display: inline-flex;\n gap: 0.4rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.3rem 0.6rem;\n font-size: 0.75rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease,\n opacity .12s ease;\n}\n.ra-shell .ra-unsaved-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ra-shell .ra-unsaved-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-shell .ra-unsaved-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell .ra-unsaved-btn-ghost:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-unsaved-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-unsaved-btn-primary:hover:not(:disabled) {\n filter: brightness(0.95);\n}\n@keyframes ra-unsaved-slide {\n from {\n opacity: 0;\n transform: translateY(-3px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ra-shell .ra-clipboard-toast {\n position: fixed;\n bottom: 1.25rem;\n left: 50%;\n transform: translateX(-50%);\n z-index: 90;\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n max-width: min(28rem, calc(100vw - 2rem));\n padding: 0.55rem 0.85rem;\n border-radius: 999px;\n background: hsl(var(--ra-text));\n color: hsl(var(--ra-surface));\n font-size: 0.75rem;\n line-height: 1;\n box-shadow: 0 8px 24px -10px hsl(0 0% 0% / 0.45);\n animation: ra-clipboard-pop 0.18s ease-out both;\n pointer-events: none;\n}\n@keyframes ra-clipboard-pop {\n from {\n opacity: 0;\n transform: translate(-50%, 6px);\n }\n to {\n opacity: 1;\n transform: translate(-50%, 0);\n }\n}\n.ra-shell .ra-row-menu-wrap {\n display: inline-flex;\n align-items: center;\n margin-left: 0.25rem;\n}\n.ra-shell .ra-row-menu-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 0.35rem;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n opacity: 0;\n transition:\n opacity .15s ease,\n background .15s ease,\n color .15s ease;\n border: 1px solid transparent;\n}\n.ra-shell .ra-row:hover .ra-row-menu-trigger,\n.ra-shell .ra-card-hover:hover .ra-row-menu-trigger,\n.ra-shell .ra-row-menu-trigger:focus-visible,\n.ra-shell .ra-row-menu-trigger[aria-expanded=true] {\n opacity: 1;\n}\n.ra-shell .ra-row-menu-trigger:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 4px);\n z-index: 50;\n min-width: 11rem;\n padding: 0.25rem;\n border-radius: 0.5rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n box-shadow: 0 12px 28px -10px hsl(0 0% 0% / 0.25);\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n.ra-shell .ra-row-menu-item {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 0.55rem;\n border-radius: 0.35rem;\n font-size: 0.75rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n text-align: left;\n width: 100%;\n cursor: pointer;\n}\n.ra-shell .ra-row-menu-item:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-row-menu-item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ra-shell .ra-item-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-item-list-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 1rem 1.25rem 1.5rem;\n}\n.ra-shell .ra-item-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 0.75rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-toolbar-title {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n min-width: 0;\n}\n.ra-shell .ra-item-toolbar-count {\n font-size: 0.7rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.45rem;\n}\n.ra-shell .ra-item-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-item-table-wrap {\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n background: hsl(var(--ra-surface));\n overflow: hidden;\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-item-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-table thead th {\n text-align: left;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n padding: 0.65rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.55);\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-item-table tbody td {\n padding: 0.65rem 0.85rem;\n border-bottom: 1px solid hsl(var(--ra-border) / 0.7);\n vertical-align: middle;\n}\n.ra-shell .ra-item-table tbody tr:last-child td {\n border-bottom: 0;\n}\n.ra-shell .ra-item-row {\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-item-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-item-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n}\n.ra-shell .ra-item-row-title {\n font-weight: var(--ra-title-weight);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-item-row-meta {\n font-size: 0.78rem;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-item-row-actions {\n text-align: right;\n white-space: nowrap;\n}\n.ra-shell .ra-item-row-actions .ra-row-action + .ra-row-action {\n margin-left: 0.15rem;\n}\n.ra-shell .ra-item-cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.85rem;\n}\n.ra-shell .ra-item-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 1rem;\n}\n.ra-shell .ra-item-card {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: left;\n padding: 0;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n overflow: hidden;\n cursor: pointer;\n transition:\n box-shadow .18s ease,\n transform .12s ease,\n border-color .15s ease;\n box-shadow: var(--ra-card-shadow);\n font-family: inherit;\n color: inherit;\n}\n.ra-shell .ra-item-card:hover {\n box-shadow: var(--ra-card-shadow-hover);\n border-color: hsl(var(--ra-accent) / 0.30);\n}\n.ra-shell .ra-item-card[data-selected=true] {\n border-color: hsl(var(--ra-accent) / 0.55);\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-item-card-thumb {\n width: 100%;\n aspect-ratio: 1 / 1;\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.12),\n hsl(var(--ra-accent) / 0.04));\n display: flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-accent));\n overflow: hidden;\n}\n.ra-shell .ra-item-card-thumb--gallery {\n aspect-ratio: 16 / 9;\n}\n.ra-shell .ra-item-card-thumb img {\n width: 100%;\n height: 100%;\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ra-shell .ra-item-card-initials {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1.5rem;\n letter-spacing: 0.02em;\n}\n.ra-shell .ra-item-card-body {\n padding: 0.65rem 0.8rem 0.85rem;\n min-width: 0;\n}\n.ra-shell .ra-item-card-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-delete {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(4px);\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-item-card:hover .ra-item-card-delete,\n.ra-shell .ra-item-card:focus-within .ra-item-card-delete {\n opacity: 1;\n}\n.ra-shell .ra-item-nav {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-nav-position {\n font-size: 0.72rem;\n color: hsl(var(--ra-muted-text));\n font-variant-numeric: tabular-nums;\n}\n.ra-shell .ra-item-nav-arrows {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n}\n.ra-shell .ra-item-nav-arrows .ra-row-action[disabled] {\n opacity: 0.35;\n cursor: not-allowed;\n}\n.ra-shell .ra-sibling-rail {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-sibling-back {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.6rem 0.85rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted) / 0.5);\n border: 0;\n border-bottom: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-sibling-back:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-sibling-heading {\n padding: 0.6rem 0.85rem 0.4rem;\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-sibling-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n.ra-shell .ra-sibling-list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.ra-shell .ra-status-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 9999px;\n}\n.ra-shell .ra-status-icon > svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.ra-shell .ra-status-icon--own {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-status-icon--shared {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-status-icon--missing {\n color: hsl(var(--ra-status-missing) / 0.7);\n}\n.ra-shell .ra-row-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-row-scope {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: calc(var(--ra-radius) * 0.5);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n margin-left: auto;\n opacity: 0.55;\n transition:\n opacity .12s ease,\n color .12s ease,\n background .12s ease;\n}\n.ra-shell .ra-row:hover .ra-row-scope {\n opacity: 0.85;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-scope {\n opacity: 1;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row[data-tone=own] .ra-row-sub {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-row[data-tone=shared] .ra-row-sub {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-row[data-selected=true] {\n background:\n linear-gradient(\n 90deg,\n hsl(var(--ra-accent) / 0.10) 0%,\n hsl(var(--ra-accent) / 0.04) 100%);\n border-left-width: 3px;\n border-left-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-dirty-pip {\n display: inline-block;\n width: 0.45rem;\n height: 0.45rem;\n border-radius: 9999px;\n background: hsl(var(--ra-warning));\n box-shadow: 0 0 0 2px hsl(var(--ra-warning) / 0.18);\n flex-shrink: 0;\n}\n.ra-shell .ra-group-summary {\n background: transparent;\n}\n.ra-shell {\n position: relative;\n}\n.ra-shell .ra-help-float {\n position: absolute;\n top: 0.65rem;\n right: 0.85rem;\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n padding: 0.3rem 0.6rem;\n font-size: 0.7rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(6px);\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n border-color .12s ease;\n}\n.ra-shell .ra-help-float:hover {\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.4);\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-help-float svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-preview-reopen {\n position: absolute;\n top: 50%;\n right: 0;\n transform: translateY(-50%);\n z-index: 4;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.4rem;\n padding: 0.65rem 0.45rem;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n border-right: 0;\n border-radius: calc(var(--ra-radius) * 0.85) 0 0 calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow);\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n padding-right .15s ease;\n writing-mode: vertical-rl;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n.ra-shell .ra-preview-reopen:hover {\n color: hsl(var(--ra-accent));\n background: hsl(var(--ra-accent) / 0.04);\n padding-right: 0.6rem;\n}\n.ra-shell .ra-preview-reopen svg {\n width: 0.85rem;\n height: 0.85rem;\n writing-mode: horizontal-tb;\n}\n");
|
|
3835
|
-
var TOP_LEVEL_SCOPES = ["
|
|
3880
|
+
styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-header-stats--titled {\n flex-direction: column;\n align-items: stretch;\n padding: 0.4rem 0.55rem;\n gap: 0.3rem;\n}\n.ra-shell .ra-header-stats .ra-stats-items {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n}\n.ra-shell .ra-header-stats .ra-stats-heading {\n display: flex;\n align-items: center;\n gap: 0.35rem;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon {\n display: inline-flex;\n align-items: center;\n color: hsl(var(--ra-text));\n opacity: 0.75;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon > svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--sl-control-bg));\n border-radius: var(--sl-control-radius);\n border: 1px solid hsl(var(--sl-control-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--sl-control-radius) - 2px);\n font-size: 0.78rem;\n font-weight: var(--sl-control-weight);\n color: hsl(var(--sl-control-fg));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--sl-control-hover-bg) / 0.10);\n color: hsl(var(--sl-control-hover-fg));\n}\n.ra-shell .ra-tab:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px hsl(var(--sl-control-focus-ring) / 0.45);\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--sl-control-active-bg));\n color: hsl(var(--sl-control-active-fg));\n border-color: hsl(var(--sl-control-active-bd));\n font-weight: var(--sl-control-active-weight);\n box-shadow: 0 1px 2px hsl(var(--sl-control-active-bg) / 0.25);\n}\n.ra-shell .ra-tab[aria-selected=true]:hover {\n background: hsl(var(--sl-control-active-bg) / 0.92);\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--sl-control-active-fg) / 0.20);\n color: hsl(var(--sl-control-active-fg));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--sl-control-fg) / 0.15);\n color: hsl(var(--sl-control-fg));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n text-align: left;\n padding: 0.45rem 0.75rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-compact {\n padding-block: 0.3rem;\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.8125rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.6875rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.05rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-rule-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.2rem;\n margin-top: 0.2rem;\n}\n.ra-shell .ra-rule-chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n border-radius: 999px;\n font-size: 0.625rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.20);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-rule-chip-more {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell[data-density=compact] .ra-row-rule-chips {\n margin-top: 0.15rem;\n gap: 0.15rem;\n}\n.ra-shell[data-density=compact] .ra-rule-chip {\n font-size: 0.6rem;\n padding: 0.02rem 0.35rem;\n}\n.ra-shell .ra-rule-filters {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n}\n.ra-shell .ra-rule-filters-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n.ra-shell .ra-rule-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.65rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n transition:\n background .12s ease,\n color .12s ease,\n border-color .12s ease;\n max-width: 100%;\n}\n.ra-shell .ra-rule-filter-chip:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n border-color: hsl(var(--ra-accent) / 0.25);\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip[data-tone=complexity][data-active=true] {\n background: hsl(var(--ra-info) / 0.15);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 9rem;\n}\n.ra-shell .ra-rule-filter-chip-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.1rem;\n height: 1rem;\n padding: 0 0.3rem;\n border-radius: 999px;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n font-size: 0.6rem;\n font-weight: 600;\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] .ra-rule-filter-chip-count {\n background: hsl(var(--ra-accent) / 0.18);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-rule-filter-clear {\n align-self: flex-start;\n background: transparent;\n border: 0;\n padding: 0;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n cursor: pointer;\n text-decoration: underline;\n text-decoration-style: dotted;\n}\n.ra-shell .ra-rule-filter-clear:hover {\n color: hsl(var(--ra-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.3rem;\n gap: 0.45rem;\n}\n.ra-shell[data-density=compact] .ra-row-title {\n font-size: 0.78125rem;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 60;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n.ra-confirm-root {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n}\n.ra-confirm-root .ra-confirm-backdrop {\n position: absolute;\n inset: 0;\n background: hsl(0 0% 0% / 0.45);\n backdrop-filter: blur(2px);\n animation: ra-confirm-fade .12s ease-out;\n}\n.ra-confirm-root .ra-confirm-card {\n position: relative;\n width: min(440px, 100%);\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: 0 1px 2px hsl(0 0% 0% / 0.08), 0 24px 48px -12px hsl(0 0% 0% / 0.32);\n padding: 1.25rem;\n animation: ra-confirm-pop .14s ease-out;\n}\n.ra-confirm-root .ra-confirm-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 0.5rem;\n}\n.ra-confirm-root .ra-confirm-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 999px;\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.12);\n color: hsl(var(--ra-warning, 38 92% 50%));\n}\n.ra-confirm-root .ra-confirm-title {\n font-family: var(--ra-font-display);\n font-weight: 600;\n font-size: 1rem;\n margin: 0;\n}\n.ra-confirm-root .ra-confirm-body {\n font-size: 0.875rem;\n color: hsl(var(--ra-muted-text));\n margin: 0 0 1.1rem;\n line-height: 1.45;\n}\n.ra-confirm-root .ra-confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.ra-confirm-root .ra-confirm-btn {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.45rem 0.85rem;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease;\n}\n.ra-confirm-root .ra-confirm-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-confirm-root .ra-confirm-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-confirm-root .ra-confirm-btn-ghost:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-confirm-root .ra-confirm-btn-danger {\n background: transparent;\n color: hsl(var(--ra-danger, 0 72% 51%));\n border-color: hsl(var(--ra-danger, 0 72% 51%) / 0.45);\n}\n.ra-confirm-root .ra-confirm-btn-danger:hover {\n background: hsl(var(--ra-danger, 0 72% 51%) / 0.08);\n border-color: hsl(var(--ra-danger, 0 72% 51%));\n}\n.ra-confirm-root .ra-confirm-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-confirm-root .ra-confirm-btn-primary:hover {\n filter: brightness(0.95);\n}\n@keyframes ra-confirm-fade {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes ra-confirm-pop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ra-shell .ra-unsaved-banner {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 0.75rem;\n border: 1px solid hsl(var(--ra-warning, 38 92% 50%) / 0.35);\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.08);\n border-radius: var(--ra-radius);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n animation: ra-unsaved-slide .14s ease-out;\n}\n.ra-shell .ra-unsaved-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-warning, 38 92% 50%));\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ra-shell .ra-unsaved-context {\n color: hsl(var(--ra-muted-text));\n font-weight: 400;\n}\n.ra-shell .ra-unsaved-error {\n color: hsl(var(--ra-danger, 0 72% 51%));\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-weight: 500;\n}\n.ra-shell .ra-unsaved-actions {\n display: inline-flex;\n gap: 0.4rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.3rem 0.6rem;\n font-size: 0.75rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease,\n opacity .12s ease;\n}\n.ra-shell .ra-unsaved-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ra-shell .ra-unsaved-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-shell .ra-unsaved-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell .ra-unsaved-btn-ghost:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-unsaved-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-unsaved-btn-primary:hover:not(:disabled) {\n filter: brightness(0.95);\n}\n@keyframes ra-unsaved-slide {\n from {\n opacity: 0;\n transform: translateY(-3px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ra-shell .ra-clipboard-toast {\n position: fixed;\n bottom: 1.25rem;\n left: 50%;\n transform: translateX(-50%);\n z-index: 90;\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n max-width: min(28rem, calc(100vw - 2rem));\n padding: 0.55rem 0.85rem;\n border-radius: 999px;\n background: hsl(var(--ra-text));\n color: hsl(var(--ra-surface));\n font-size: 0.75rem;\n line-height: 1;\n box-shadow: 0 8px 24px -10px hsl(0 0% 0% / 0.45);\n animation: ra-clipboard-pop 0.18s ease-out both;\n pointer-events: none;\n}\n@keyframes ra-clipboard-pop {\n from {\n opacity: 0;\n transform: translate(-50%, 6px);\n }\n to {\n opacity: 1;\n transform: translate(-50%, 0);\n }\n}\n.ra-shell .ra-row-menu-wrap {\n display: inline-flex;\n align-items: center;\n margin-left: 0.25rem;\n}\n.ra-shell .ra-row-menu-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 0.35rem;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n opacity: 0;\n transition:\n opacity .15s ease,\n background .15s ease,\n color .15s ease;\n border: 1px solid transparent;\n}\n.ra-shell .ra-row:hover .ra-row-menu-trigger,\n.ra-shell .ra-card-hover:hover .ra-row-menu-trigger,\n.ra-shell .ra-row-menu-trigger:focus-visible,\n.ra-shell .ra-row-menu-trigger[aria-expanded=true] {\n opacity: 1;\n}\n.ra-shell .ra-row-menu-trigger:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 4px);\n z-index: 50;\n min-width: 11rem;\n padding: 0.25rem;\n border-radius: 0.5rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n box-shadow: 0 12px 28px -10px hsl(0 0% 0% / 0.25);\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n.ra-shell .ra-row-menu-item {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 0.55rem;\n border-radius: 0.35rem;\n font-size: 0.75rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n text-align: left;\n width: 100%;\n cursor: pointer;\n}\n.ra-shell .ra-row-menu-item:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-row-menu-item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ra-shell .ra-item-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-item-list-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 1rem 1.25rem 1.5rem;\n}\n.ra-shell .ra-item-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 0.75rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-toolbar-title {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n min-width: 0;\n}\n.ra-shell .ra-item-toolbar-count {\n font-size: 0.7rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.45rem;\n}\n.ra-shell .ra-item-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-item-table-wrap {\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n background: hsl(var(--ra-surface));\n overflow: hidden;\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-item-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-table thead th {\n text-align: left;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n padding: 0.65rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.55);\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-item-table tbody td {\n padding: 0.65rem 0.85rem;\n border-bottom: 1px solid hsl(var(--ra-border) / 0.7);\n vertical-align: middle;\n}\n.ra-shell .ra-item-table tbody tr:last-child td {\n border-bottom: 0;\n}\n.ra-shell .ra-item-row {\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-item-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-item-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n}\n.ra-shell .ra-item-row-title {\n font-weight: var(--ra-title-weight);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-item-row-meta {\n font-size: 0.78rem;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-item-row-actions {\n text-align: right;\n white-space: nowrap;\n}\n.ra-shell .ra-item-row-actions .ra-row-action + .ra-row-action {\n margin-left: 0.15rem;\n}\n.ra-shell .ra-item-cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.85rem;\n}\n.ra-shell .ra-item-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 1rem;\n}\n.ra-shell .ra-item-card {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: left;\n padding: 0;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n overflow: hidden;\n cursor: pointer;\n transition:\n box-shadow .18s ease,\n transform .12s ease,\n border-color .15s ease;\n box-shadow: var(--ra-card-shadow);\n font-family: inherit;\n color: inherit;\n}\n.ra-shell .ra-item-card:hover {\n box-shadow: var(--ra-card-shadow-hover);\n border-color: hsl(var(--ra-accent) / 0.30);\n}\n.ra-shell .ra-item-card[data-selected=true] {\n border-color: hsl(var(--ra-accent) / 0.55);\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-item-card-thumb {\n width: 100%;\n aspect-ratio: 1 / 1;\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.12),\n hsl(var(--ra-accent) / 0.04));\n display: flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-accent));\n overflow: hidden;\n}\n.ra-shell .ra-item-card-thumb--gallery {\n aspect-ratio: 16 / 9;\n}\n.ra-shell .ra-item-card-thumb img {\n width: 100%;\n height: 100%;\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ra-shell .ra-item-card-initials {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1.5rem;\n letter-spacing: 0.02em;\n}\n.ra-shell .ra-item-card-body {\n padding: 0.65rem 0.8rem 0.85rem;\n min-width: 0;\n}\n.ra-shell .ra-item-card-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-delete {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(4px);\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-item-card:hover .ra-item-card-delete,\n.ra-shell .ra-item-card:focus-within .ra-item-card-delete {\n opacity: 1;\n}\n.ra-shell .ra-item-nav {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-nav-position {\n font-size: 0.72rem;\n color: hsl(var(--ra-muted-text));\n font-variant-numeric: tabular-nums;\n}\n.ra-shell .ra-item-nav-arrows {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n}\n.ra-shell .ra-item-nav-arrows .ra-row-action[disabled] {\n opacity: 0.35;\n cursor: not-allowed;\n}\n.ra-shell .ra-sibling-rail {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-sibling-back {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.6rem 0.85rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted) / 0.5);\n border: 0;\n border-bottom: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-sibling-back:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-sibling-heading {\n padding: 0.6rem 0.85rem 0.4rem;\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-sibling-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n.ra-shell .ra-sibling-list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.ra-shell .ra-status-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 9999px;\n}\n.ra-shell .ra-status-icon > svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.ra-shell .ra-status-icon--own {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-status-icon--shared {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-status-icon--missing {\n color: hsl(var(--ra-status-missing) / 0.7);\n}\n.ra-shell .ra-row-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-row-scope {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: calc(var(--ra-radius) * 0.5);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n margin-left: auto;\n opacity: 0.55;\n transition:\n opacity .12s ease,\n color .12s ease,\n background .12s ease;\n}\n.ra-shell .ra-row:hover .ra-row-scope {\n opacity: 0.85;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-scope {\n opacity: 1;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row[data-tone=own] .ra-row-sub {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-row[data-tone=shared] .ra-row-sub {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-row[data-selected=true] {\n background:\n linear-gradient(\n 90deg,\n hsl(var(--ra-accent) / 0.10) 0%,\n hsl(var(--ra-accent) / 0.04) 100%);\n border-left-width: 3px;\n border-left-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-dirty-pip {\n display: inline-block;\n width: 0.45rem;\n height: 0.45rem;\n border-radius: 9999px;\n background: hsl(var(--ra-warning));\n box-shadow: 0 0 0 2px hsl(var(--ra-warning) / 0.18);\n flex-shrink: 0;\n}\n.ra-shell .ra-group-summary {\n background: transparent;\n}\n.ra-shell {\n position: relative;\n}\n.ra-shell .ra-help-float {\n position: absolute;\n top: 0.65rem;\n right: 0.85rem;\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n padding: 0.3rem 0.6rem;\n font-size: 0.7rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(6px);\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n border-color .12s ease;\n}\n.ra-shell .ra-help-float:hover {\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.4);\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-help-float svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-preview-reopen {\n position: absolute;\n top: 50%;\n right: 0;\n transform: translateY(-50%);\n z-index: 4;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.4rem;\n padding: 0.65rem 0.45rem;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n border-right: 0;\n border-radius: calc(var(--ra-radius) * 0.85) 0 0 calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow);\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n padding-right .15s ease;\n writing-mode: vertical-rl;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n.ra-shell .ra-preview-reopen:hover {\n color: hsl(var(--ra-accent));\n background: hsl(var(--ra-accent) / 0.04);\n padding-right: 0.6rem;\n}\n.ra-shell .ra-preview-reopen svg {\n width: 0.85rem;\n height: 0.85rem;\n writing-mode: horizontal-tb;\n}\n");
|
|
3881
|
+
var TOP_LEVEL_SCOPES = ["collection", "rule", "product"];
|
|
3836
3882
|
var WARNED_FACET_DEPRECATED = false;
|
|
3837
|
-
var
|
|
3838
|
-
const time = Date.now().toString(36);
|
|
3839
|
-
const rand = Math.random().toString(36).slice(2, 8);
|
|
3840
|
-
return `${time}${rand}`;
|
|
3841
|
-
};
|
|
3842
|
-
var newRuleId = () => {
|
|
3843
|
-
const time = Date.now().toString(36);
|
|
3844
|
-
const rand = Math.random().toString(36).slice(2, 10);
|
|
3845
|
-
return `${time}${rand}`;
|
|
3846
|
-
};
|
|
3883
|
+
var DRAFT_ID = "__draft__";
|
|
3847
3884
|
var productItemToSummary = (p) => {
|
|
3848
3885
|
const ref = buildRef({ productId: p.id });
|
|
3849
3886
|
return {
|
|
@@ -3962,15 +3999,27 @@ function RecordsAdminShell(props) {
|
|
|
3962
3999
|
deepLinkState.emit({ view: next }, "view");
|
|
3963
4000
|
}, [onTelemetry, recordType, itemView, setItemView, deepLinkState]);
|
|
3964
4001
|
const [selectedItemId, setSelectedItemId] = useState(null);
|
|
4002
|
+
const [pendingDeepLinkRecordId, setPendingDeepLinkRecordId] = useState(null);
|
|
3965
4003
|
const ctx = useMemo(
|
|
3966
4004
|
() => ({ SL, collectionId, appId, recordType }),
|
|
3967
4005
|
[SL, collectionId, appId, recordType]
|
|
3968
4006
|
);
|
|
3969
4007
|
const probe = useScopeProbe({ SL, collectionId });
|
|
3970
|
-
const topLevelScopes = useMemo(
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
4008
|
+
const topLevelScopes = useMemo(() => {
|
|
4009
|
+
const requested = requestedScopes ?? [];
|
|
4010
|
+
if (requested.length > 0) {
|
|
4011
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4012
|
+
const ordered = [];
|
|
4013
|
+
for (const s of requested) {
|
|
4014
|
+
if (!TOP_LEVEL_SCOPES.includes(s)) continue;
|
|
4015
|
+
if (seen.has(s)) continue;
|
|
4016
|
+
seen.add(s);
|
|
4017
|
+
ordered.push(s);
|
|
4018
|
+
}
|
|
4019
|
+
return ordered;
|
|
4020
|
+
}
|
|
4021
|
+
return [...TOP_LEVEL_SCOPES];
|
|
4022
|
+
}, [requestedScopes]);
|
|
3974
4023
|
useEffect(() => {
|
|
3975
4024
|
if (requestedScopes.includes("facet") && !WARNED_FACET_DEPRECATED) {
|
|
3976
4025
|
WARNED_FACET_DEPRECATED = true;
|
|
@@ -3990,8 +4039,6 @@ function RecordsAdminShell(props) {
|
|
|
3990
4039
|
const initialScope = useMemo(() => {
|
|
3991
4040
|
if (contextScope?.productId && topLevelScopes.includes("product")) return "product";
|
|
3992
4041
|
if (defaultScope && topLevelScopes.includes(defaultScope)) return defaultScope;
|
|
3993
|
-
if (topLevelScopes.includes("rule")) return "rule";
|
|
3994
|
-
if (topLevelScopes.includes("collection")) return "collection";
|
|
3995
4042
|
return topLevelScopes[0] ?? "product";
|
|
3996
4043
|
}, [contextScope?.productId, defaultScope, topLevelScopes]);
|
|
3997
4044
|
const [activeScope, setActiveScope] = useState(initialScope);
|
|
@@ -4002,7 +4049,8 @@ function RecordsAdminShell(props) {
|
|
|
4002
4049
|
const [filter, setFilter] = useState("all");
|
|
4003
4050
|
const [ruleFilters, setRuleFilters] = useState(EMPTY_RULE_FILTERS);
|
|
4004
4051
|
const [facetBrowseFilter, setFacetBrowseFilter] = useState(null);
|
|
4005
|
-
const [
|
|
4052
|
+
const [selectedRecordId, setSelectedRecordId] = useState(null);
|
|
4053
|
+
const [draftKind, setDraftKind] = useState(null);
|
|
4006
4054
|
const [selectedProductId, setSelectedProductId] = useState(
|
|
4007
4055
|
contextScope?.productId
|
|
4008
4056
|
);
|
|
@@ -4082,25 +4130,30 @@ function RecordsAdminShell(props) {
|
|
|
4082
4130
|
}, [activeScope, selectedProductId, productBrowse.items]);
|
|
4083
4131
|
useEffect(() => {
|
|
4084
4132
|
if (activeScope !== "rule" && activeScope !== "collection") return;
|
|
4085
|
-
if (
|
|
4133
|
+
if (selectedRecordId !== null) return;
|
|
4086
4134
|
if (activeScope === "collection" && cardinality === "collection") {
|
|
4087
|
-
setSelectedFacetRef("");
|
|
4088
4135
|
return;
|
|
4089
4136
|
}
|
|
4090
4137
|
const first = recordList.items[0];
|
|
4091
|
-
if (first)
|
|
4092
|
-
}, [activeScope,
|
|
4138
|
+
if (first?.id) setSelectedRecordId(first.id);
|
|
4139
|
+
}, [activeScope, selectedRecordId, recordList.items, cardinality]);
|
|
4093
4140
|
useEffect(() => {
|
|
4094
4141
|
setSearch("");
|
|
4095
4142
|
setFilter("all");
|
|
4096
4143
|
setRuleFilters(EMPTY_RULE_FILTERS);
|
|
4097
4144
|
setFacetBrowseFilter(null);
|
|
4098
|
-
|
|
4145
|
+
setSelectedRecordId(null);
|
|
4146
|
+
setDraftKind(null);
|
|
4099
4147
|
}, [activeScope]);
|
|
4100
4148
|
const editingScope = useMemo(() => {
|
|
4101
4149
|
if (activeScope === "rule" || activeScope === "collection") {
|
|
4102
|
-
if (
|
|
4103
|
-
|
|
4150
|
+
if (selectedRecordId === null) return null;
|
|
4151
|
+
if (selectedRecordId === DRAFT_ID) {
|
|
4152
|
+
return parseRef("");
|
|
4153
|
+
}
|
|
4154
|
+
const hit = recordList.items.find((it) => it.id === selectedRecordId);
|
|
4155
|
+
if (!hit) return null;
|
|
4156
|
+
return hit.scope;
|
|
4104
4157
|
}
|
|
4105
4158
|
if (!selectedProductId) return null;
|
|
4106
4159
|
if (drillTab === "variant") {
|
|
@@ -4112,19 +4165,9 @@ function RecordsAdminShell(props) {
|
|
|
4112
4165
|
return parseRef(buildRef({ productId: selectedProductId, batchId: selectedBatchId }));
|
|
4113
4166
|
}
|
|
4114
4167
|
return parseRef(buildRef({ productId: selectedProductId }));
|
|
4115
|
-
}, [activeScope,
|
|
4168
|
+
}, [activeScope, selectedRecordId, recordList.items, selectedProductId, drillTab, selectedVariantId, selectedBatchId]);
|
|
4116
4169
|
const isCollection = cardinality === "collection";
|
|
4117
|
-
const
|
|
4118
|
-
if (!isCollection) return null;
|
|
4119
|
-
if (!selectedItemId) return null;
|
|
4120
|
-
const baseRef = editingScope?.raw ?? "";
|
|
4121
|
-
return buildItemRef(baseRef, selectedItemId);
|
|
4122
|
-
}, [isCollection, selectedItemId, editingScope]);
|
|
4123
|
-
const editingTargetScope = useMemo(() => {
|
|
4124
|
-
if (!isCollection) return editingScope;
|
|
4125
|
-
if (!editingItemRef) return null;
|
|
4126
|
-
return parseRef(editingItemRef);
|
|
4127
|
-
}, [isCollection, editingScope, editingItemRef]);
|
|
4170
|
+
const editingTargetScope = editingScope;
|
|
4128
4171
|
const skipNextItemResetRef = useRef(false);
|
|
4129
4172
|
useEffect(() => {
|
|
4130
4173
|
if (skipNextItemResetRef.current) {
|
|
@@ -4141,20 +4184,19 @@ function RecordsAdminShell(props) {
|
|
|
4141
4184
|
useEffect(() => {
|
|
4142
4185
|
if (!deepLinkState.enabled) return;
|
|
4143
4186
|
if (selectedItemId) return;
|
|
4144
|
-
deepLinkState.emit({ scope: editingScope?.raw ?? null,
|
|
4187
|
+
deepLinkState.emit({ scope: editingScope?.raw ?? null, recordId: null }, "scope");
|
|
4145
4188
|
lastAppliedDLRef.current = `${""}|${editingScope?.raw ?? ""}|${itemView}`;
|
|
4146
4189
|
}, [deepLinkState.enabled, editingScope?.raw, selectedItemId, itemView]);
|
|
4147
4190
|
useEffect(() => {
|
|
4148
4191
|
if (!deepLinkState.enabled) return;
|
|
4149
|
-
const {
|
|
4150
|
-
const sig = `${
|
|
4192
|
+
const { recordId, scope, view } = deepLinkState.urlState;
|
|
4193
|
+
const sig = `${recordId ?? ""}|${scope ?? ""}|${view ?? ""}`;
|
|
4151
4194
|
if (sig === lastAppliedDLRef.current) return;
|
|
4152
4195
|
lastAppliedDLRef.current = sig;
|
|
4153
4196
|
if (view && itemViews.includes(view) && view !== itemView) {
|
|
4154
4197
|
setItemView(view);
|
|
4155
4198
|
}
|
|
4156
|
-
const railRef =
|
|
4157
|
-
const itemId = item ? item.includes("item:") ? item.slice(item.lastIndexOf("item:") + "item:".length) : item : null;
|
|
4199
|
+
const railRef = scope ?? "";
|
|
4158
4200
|
const parsed = railRef ? parseRef(railRef) : null;
|
|
4159
4201
|
if (parsed?.productId) {
|
|
4160
4202
|
if (activeScope !== "product") setActiveScope("product");
|
|
@@ -4168,16 +4210,12 @@ function RecordsAdminShell(props) {
|
|
|
4168
4210
|
if (parsed.facetValue) {
|
|
4169
4211
|
setFacetBrowseFilter({ facetKey: parsed.facetId, facetValue: parsed.facetValue });
|
|
4170
4212
|
}
|
|
4171
|
-
if (
|
|
4213
|
+
if (selectedRecordId !== null) setSelectedRecordId(null);
|
|
4172
4214
|
} else {
|
|
4173
|
-
if (
|
|
4174
|
-
}
|
|
4175
|
-
if (itemId !== selectedItemId) {
|
|
4176
|
-
if (railRef && railRef !== editingScope?.raw) {
|
|
4177
|
-
skipNextItemResetRef.current = true;
|
|
4178
|
-
}
|
|
4179
|
-
setSelectedItemId(itemId);
|
|
4215
|
+
if (selectedRecordId !== null) setSelectedRecordId(null);
|
|
4180
4216
|
}
|
|
4217
|
+
setPendingDeepLinkRecordId(recordId ?? null);
|
|
4218
|
+
if (!recordId && selectedItemId !== null) setSelectedItemId(null);
|
|
4181
4219
|
}, [deepLinkState.enabled, deepLinkState.urlState]);
|
|
4182
4220
|
const supportedForResolution = useMemo(() => requestedScopes, [requestedScopes]);
|
|
4183
4221
|
const resolved = useResolvedRecord({
|
|
@@ -4190,7 +4228,12 @@ function RecordsAdminShell(props) {
|
|
|
4190
4228
|
batchId: editingTargetScope?.batchId,
|
|
4191
4229
|
facetId: editingTargetScope?.facetId,
|
|
4192
4230
|
facetValue: editingTargetScope?.facetValue,
|
|
4193
|
-
|
|
4231
|
+
// Id-primary path: when the user has selected a saved record by UUID
|
|
4232
|
+
// (records-driven tabs, deep-link by `?recordId=`), bypass the
|
|
4233
|
+
// inheritance chain and load that exact row. Drafts (`DRAFT_ID`) and
|
|
4234
|
+
// pinned-anchor tabs (Products) leave `recordId` undefined so the
|
|
4235
|
+
// resolver runs `match()` against the anchors above.
|
|
4236
|
+
recordId: selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0,
|
|
4194
4237
|
supportedScopes: supportedForResolution,
|
|
4195
4238
|
enabled: !!editingTargetScope
|
|
4196
4239
|
});
|
|
@@ -4318,8 +4361,8 @@ function RecordsAdminShell(props) {
|
|
|
4318
4361
|
const sourceValue = onCopyOverride ? onCopyOverride({ value: editorCtx.value, scope: editingScope }) : cloneValue(editorCtx.value);
|
|
4319
4362
|
clipboard.set({
|
|
4320
4363
|
value: sourceValue,
|
|
4321
|
-
sourceScope: editingScope
|
|
4322
|
-
|
|
4364
|
+
sourceScope: editingScope,
|
|
4365
|
+
sourceRecordId: resolved.recordId,
|
|
4323
4366
|
sourceLabel: editorHeaderLabel
|
|
4324
4367
|
});
|
|
4325
4368
|
onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: editingScope.raw });
|
|
@@ -4340,10 +4383,7 @@ function RecordsAdminShell(props) {
|
|
|
4340
4383
|
]);
|
|
4341
4384
|
const pasteCurrent = useCallback(async () => {
|
|
4342
4385
|
if (!enableClipboard || !editingScope || !clipboard.entry) return;
|
|
4343
|
-
const compat = checkPasteCompatibility(
|
|
4344
|
-
{ kind: clipboard.entry.sourceScope, raw: clipboard.entry.sourceRef },
|
|
4345
|
-
editingScope
|
|
4346
|
-
);
|
|
4386
|
+
const compat = checkPasteCompatibility(clipboard.entry.sourceScope, editingScope);
|
|
4347
4387
|
if (compat.status === "denied") {
|
|
4348
4388
|
setClipboardNotice({ message: compat.reason ?? "Paste not allowed here", variant: "paste" });
|
|
4349
4389
|
return;
|
|
@@ -4370,7 +4410,7 @@ function RecordsAdminShell(props) {
|
|
|
4370
4410
|
});
|
|
4371
4411
|
if (!ok) return;
|
|
4372
4412
|
}
|
|
4373
|
-
const sourceParsed =
|
|
4413
|
+
const sourceParsed = clipboard.entry.sourceScope;
|
|
4374
4414
|
const transformed = onPasteOverride ? onPasteOverride(
|
|
4375
4415
|
{ value: clipboard.entry.value, sourceScope: sourceParsed },
|
|
4376
4416
|
{ scope: editingScope, currentValue: editorCtx.value ?? null }
|
|
@@ -4380,12 +4420,12 @@ function RecordsAdminShell(props) {
|
|
|
4380
4420
|
onTelemetry?.({
|
|
4381
4421
|
type: "clipboard.paste",
|
|
4382
4422
|
recordType,
|
|
4383
|
-
sourceRef: clipboard.entry.
|
|
4423
|
+
sourceRef: clipboard.entry.sourceScope.raw,
|
|
4384
4424
|
destinationRef: editingScope.raw,
|
|
4385
4425
|
replaced: willReplace
|
|
4386
4426
|
});
|
|
4387
4427
|
setClipboardNotice({
|
|
4388
|
-
message: i18n.pasteToast.replace("{name}", clipboard.entry.sourceLabel ?? clipboard.entry.
|
|
4428
|
+
message: i18n.pasteToast.replace("{name}", clipboard.entry.sourceLabel ?? clipboard.entry.sourceScope.raw),
|
|
4389
4429
|
variant: "paste"
|
|
4390
4430
|
});
|
|
4391
4431
|
}, [
|
|
@@ -4409,11 +4449,10 @@ function RecordsAdminShell(props) {
|
|
|
4409
4449
|
]);
|
|
4410
4450
|
const editorPasteCompat = useMemo(() => {
|
|
4411
4451
|
if (!enableClipboard || !clipboard.entry || !editingScope) return null;
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
);
|
|
4452
|
+
const sameRecord = clipboard.entry.sourceRecordId && resolved.recordId && clipboard.entry.sourceRecordId === resolved.recordId;
|
|
4453
|
+
const sameAnchor = !clipboard.entry.sourceRecordId && clipboard.entry.sourceScope.raw === editingScope.raw;
|
|
4454
|
+
if (sameRecord || sameAnchor) return { status: "denied" };
|
|
4455
|
+
return checkPasteCompatibility(clipboard.entry.sourceScope, editingScope);
|
|
4417
4456
|
}, [enableClipboard, clipboard.entry, editingScope]);
|
|
4418
4457
|
const editorClipboard = enableClipboard && editingScope ? {
|
|
4419
4458
|
onCopy: copyCurrent,
|
|
@@ -4425,31 +4464,30 @@ function RecordsAdminShell(props) {
|
|
|
4425
4464
|
pasteSourceLabel: clipboard.entry?.sourceLabel,
|
|
4426
4465
|
pasteWillReplace: resolved.source === "self" && !!clipboard.entry
|
|
4427
4466
|
} : void 0;
|
|
4428
|
-
const [
|
|
4467
|
+
const [pendingPasteTarget, setPendingPasteTarget] = useState(null);
|
|
4429
4468
|
useEffect(() => {
|
|
4430
|
-
if (!
|
|
4431
|
-
if (!editingScope
|
|
4469
|
+
if (!pendingPasteTarget) return;
|
|
4470
|
+
if (!editingScope) return;
|
|
4471
|
+
const matched = pendingPasteTarget.kind === "record" ? selectedRecordId === pendingPasteTarget.recordId : editingScope.raw === pendingPasteTarget.ref;
|
|
4472
|
+
if (!matched) return;
|
|
4432
4473
|
const t = window.setTimeout(() => {
|
|
4433
|
-
|
|
4474
|
+
setPendingPasteTarget(null);
|
|
4434
4475
|
void pasteCurrent();
|
|
4435
4476
|
}, 0);
|
|
4436
4477
|
return () => window.clearTimeout(t);
|
|
4437
|
-
}, [
|
|
4478
|
+
}, [pendingPasteTarget, editingScope, selectedRecordId, pasteCurrent]);
|
|
4438
4479
|
const rowClipboard = enableClipboard ? (record) => {
|
|
4439
4480
|
const summaryHasData = record.data != null;
|
|
4440
4481
|
const sourceParsed = record.scope;
|
|
4441
|
-
const compat = clipboard.entry ? checkPasteCompatibility(
|
|
4442
|
-
|
|
4443
|
-
sourceParsed
|
|
4444
|
-
) : null;
|
|
4445
|
-
const sameRef = clipboard.entry?.sourceRef === record.ref;
|
|
4482
|
+
const compat = clipboard.entry ? checkPasteCompatibility(clipboard.entry.sourceScope, sourceParsed) : null;
|
|
4483
|
+
const sameTarget = clipboard.entry ? clipboard.entry.sourceRecordId && record.id ? clipboard.entry.sourceRecordId === record.id : clipboard.entry.sourceScope.raw === record.ref : false;
|
|
4446
4484
|
return {
|
|
4447
4485
|
onCopy: summaryHasData ? () => {
|
|
4448
4486
|
const value = onCopyOverride ? onCopyOverride({ value: record.data, scope: sourceParsed }) : cloneValue(record.data);
|
|
4449
4487
|
clipboard.set({
|
|
4450
4488
|
value,
|
|
4451
|
-
sourceScope: sourceParsed
|
|
4452
|
-
|
|
4489
|
+
sourceScope: sourceParsed,
|
|
4490
|
+
sourceRecordId: record.id ?? void 0,
|
|
4453
4491
|
sourceLabel: record.label
|
|
4454
4492
|
});
|
|
4455
4493
|
onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: record.ref });
|
|
@@ -4460,9 +4498,11 @@ function RecordsAdminShell(props) {
|
|
|
4460
4498
|
} : void 0,
|
|
4461
4499
|
onPaste: () => {
|
|
4462
4500
|
onLeftSelectRef.current?.(record);
|
|
4463
|
-
|
|
4501
|
+
setPendingPasteTarget(
|
|
4502
|
+
record.id ? { kind: "record", recordId: record.id } : { kind: "anchor", ref: record.ref }
|
|
4503
|
+
);
|
|
4464
4504
|
},
|
|
4465
|
-
canPaste: !!clipboard.entry && !
|
|
4505
|
+
canPaste: !!clipboard.entry && !sameTarget && compat?.status !== "denied",
|
|
4466
4506
|
pasteWillReplace: record.status === "configured",
|
|
4467
4507
|
clipboardSourceLabel: clipboard.entry?.sourceLabel
|
|
4468
4508
|
};
|
|
@@ -4471,6 +4511,7 @@ function RecordsAdminShell(props) {
|
|
|
4471
4511
|
const baseScopeRef = editingScope?.raw ?? "";
|
|
4472
4512
|
const itemNounLabel = itemNoun || "item";
|
|
4473
4513
|
const buildItemUrlValue = useCallback((id) => {
|
|
4514
|
+
if (!baseScopeRef && id.startsWith("item:")) return id;
|
|
4474
4515
|
return baseScopeRef ? `${baseScopeRef}/item:${id}` : id;
|
|
4475
4516
|
}, [baseScopeRef]);
|
|
4476
4517
|
const onItemOpen = useCallback((itemId) => {
|
|
@@ -4478,31 +4519,31 @@ function RecordsAdminShell(props) {
|
|
|
4478
4519
|
void runWithGuard(() => {
|
|
4479
4520
|
setSelectedItemId(itemId);
|
|
4480
4521
|
onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId });
|
|
4481
|
-
deepLinkState.emit({
|
|
4522
|
+
deepLinkState.emit({ recordId: itemId, scope: baseScopeRef || null }, "record.open");
|
|
4482
4523
|
});
|
|
4483
4524
|
}, [isCollection, runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4484
4525
|
const onItemCreate = useCallback(() => {
|
|
4485
4526
|
if (!isCollection) return;
|
|
4486
4527
|
void runWithGuard(() => {
|
|
4487
|
-
const id = generateItemId ? generateItemId() :
|
|
4528
|
+
const id = generateItemId ? generateItemId() : DRAFT_ID;
|
|
4488
4529
|
setSelectedItemId(id);
|
|
4489
4530
|
onTelemetry?.({ type: "item.create", recordType, scopeRef: baseScopeRef });
|
|
4490
|
-
deepLinkState.emit({
|
|
4531
|
+
deepLinkState.emit({ recordId: null, scope: baseScopeRef || null }, "record.open");
|
|
4491
4532
|
});
|
|
4492
4533
|
}, [isCollection, runWithGuard, generateItemId, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4493
4534
|
const onItemDelete = useCallback(async (itemId) => {
|
|
4494
4535
|
if (!isCollection) return;
|
|
4495
|
-
|
|
4536
|
+
if (itemId === DRAFT_ID) return;
|
|
4496
4537
|
if (onBeforeDelete) {
|
|
4497
|
-
const ok = await onBeforeDelete(parseRef(
|
|
4538
|
+
const ok = await onBeforeDelete(editingScope ?? parseRef(""));
|
|
4498
4539
|
if (!ok) return;
|
|
4499
4540
|
}
|
|
4500
4541
|
try {
|
|
4501
|
-
const {
|
|
4502
|
-
await
|
|
4542
|
+
const { removeRecord: removeRecord2 } = await import('../../records-JWS6LKJ2.js');
|
|
4543
|
+
await removeRecord2(ctx, itemId);
|
|
4503
4544
|
onTelemetry?.({ type: "item.delete", recordType, scopeRef: baseScopeRef, itemId });
|
|
4504
4545
|
if (selectedItemId === itemId) setSelectedItemId(null);
|
|
4505
|
-
if (selectedItemId === itemId) deepLinkState.emit({
|
|
4546
|
+
if (selectedItemId === itemId) deepLinkState.emit({ recordId: null }, "record.close");
|
|
4506
4547
|
collectionItems.refetch();
|
|
4507
4548
|
} catch (err) {
|
|
4508
4549
|
console.error("[RecordsAdminShell] item delete failed", err);
|
|
@@ -4537,14 +4578,14 @@ function RecordsAdminShell(props) {
|
|
|
4537
4578
|
const onItemBack = useCallback(() => {
|
|
4538
4579
|
void runWithGuard(() => {
|
|
4539
4580
|
setSelectedItemId(null);
|
|
4540
|
-
deepLinkState.emit({
|
|
4581
|
+
deepLinkState.emit({ recordId: null }, "record.close");
|
|
4541
4582
|
});
|
|
4542
4583
|
}, [runWithGuard, deepLinkState]);
|
|
4543
4584
|
const stepToItem = useCallback((id) => {
|
|
4544
4585
|
void runWithGuard(() => {
|
|
4545
4586
|
setSelectedItemId(id);
|
|
4546
4587
|
onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId: id });
|
|
4547
|
-
deepLinkState.emit({
|
|
4588
|
+
deepLinkState.emit({ recordId: id, scope: baseScopeRef || null }, "record.step");
|
|
4548
4589
|
});
|
|
4549
4590
|
}, [runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4550
4591
|
const onItemPrev = useCallback(() => {
|
|
@@ -4717,21 +4758,21 @@ function RecordsAdminShell(props) {
|
|
|
4717
4758
|
const isRecordsTab = isRuleTab || isGlobalTab;
|
|
4718
4759
|
const onCreateRule = useCallback(() => {
|
|
4719
4760
|
void runWithGuard(() => {
|
|
4720
|
-
const id = newRuleId();
|
|
4721
|
-
const ref = `rule:${id}`;
|
|
4722
4761
|
if (activeScope !== "rule") setActiveScope("rule");
|
|
4723
|
-
|
|
4762
|
+
setSelectedRecordId(DRAFT_ID);
|
|
4763
|
+
setDraftKind("rule");
|
|
4724
4764
|
});
|
|
4725
4765
|
}, [runWithGuard, activeScope]);
|
|
4726
4766
|
const hasGlobalRecord = useMemo(
|
|
4727
|
-
() => recordList.items.some((it) => !it.scope.productId && !it.scope.facetId && !it.scope.variantId && !it.scope.batchId && !it.scope.proofId
|
|
4767
|
+
() => recordList.items.some((it) => !it.scope.productId && !it.scope.facetId && !it.scope.variantId && !it.scope.batchId && !it.scope.proofId),
|
|
4728
4768
|
[recordList.items]
|
|
4729
4769
|
);
|
|
4730
4770
|
const showCreateGlobal = isGlobalTab && !isCollection && !hasGlobalRecord;
|
|
4731
4771
|
const onCreateGlobal = useCallback(() => {
|
|
4732
4772
|
void runWithGuard(() => {
|
|
4733
4773
|
if (activeScope !== "collection") setActiveScope("collection");
|
|
4734
|
-
|
|
4774
|
+
setSelectedRecordId(DRAFT_ID);
|
|
4775
|
+
setDraftKind("global");
|
|
4735
4776
|
});
|
|
4736
4777
|
}, [runWithGuard, activeScope]);
|
|
4737
4778
|
const filteredRuleItems = useMemo(
|
|
@@ -4773,26 +4814,25 @@ function RecordsAdminShell(props) {
|
|
|
4773
4814
|
}
|
|
4774
4815
|
return Array.from(byKey.values());
|
|
4775
4816
|
}, [facetBrowse.items]);
|
|
4776
|
-
const stripItemRecords = useCallback(
|
|
4777
|
-
(items) => items.filter((it) => !it.scope.itemId && !it.ref.startsWith("item:") && !it.ref.includes("/item:")),
|
|
4778
|
-
[]
|
|
4779
|
-
);
|
|
4780
4817
|
const collectionGlobalAllRow = useMemo(
|
|
4781
4818
|
() => ({
|
|
4782
4819
|
id: null,
|
|
4783
4820
|
ref: "",
|
|
4784
4821
|
scope: parseRef(""),
|
|
4785
4822
|
data: null,
|
|
4786
|
-
status: "
|
|
4823
|
+
status: "empty",
|
|
4787
4824
|
label: i18n.itemsAllLabel,
|
|
4788
4825
|
subtitle: collectionItems.items.length ? `${collectionItems.items.length} ${itemNoun}${collectionItems.items.length === 1 ? "" : "s"}` : void 0
|
|
4789
4826
|
}),
|
|
4790
4827
|
[i18n.itemsAllLabel, collectionItems.items.length, itemNoun]
|
|
4791
4828
|
);
|
|
4792
|
-
const leftItems = isProductTab ? productListItems : isRuleTab ? applyFacetBrowseFilter(
|
|
4829
|
+
const leftItems = isProductTab ? productListItems : isRuleTab ? applyFacetBrowseFilter(filteredRuleItems) : isGlobalTab && isCollection ? [collectionGlobalAllRow] : isRecordsTab ? applyFacetBrowseFilter(recordList.items) : [];
|
|
4793
4830
|
const leftLoading = isProductTab ? !productPinned && productBrowse.isLoading : isRecordsTab ? recordList.isLoading || probe.isLoading : false;
|
|
4794
4831
|
const leftError = isProductTab ? productBrowse.error : isRecordsTab ? recordList.error : null;
|
|
4795
|
-
const
|
|
4832
|
+
const leftSelectedId = isProductTab ? void 0 : selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0;
|
|
4833
|
+
const leftSelectedAnchorKey = isProductTab ? selectedProductId ? buildRef({ productId: selectedProductId }) : void 0 : void 0;
|
|
4834
|
+
const dirtyId = !editorCtx.isDirty ? void 0 : selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0;
|
|
4835
|
+
const dirtyAnchorKey = !editorCtx.isDirty ? void 0 : isProductTab ? editingScope?.raw : void 0;
|
|
4796
4836
|
const onLeftSelect = (item) => {
|
|
4797
4837
|
void runWithGuard(() => {
|
|
4798
4838
|
if (isProductTab) {
|
|
@@ -4801,7 +4841,8 @@ function RecordsAdminShell(props) {
|
|
|
4801
4841
|
setSelectedBatchId(void 0);
|
|
4802
4842
|
setDrillTab("product");
|
|
4803
4843
|
} else {
|
|
4804
|
-
|
|
4844
|
+
setSelectedRecordId(item.id ?? null);
|
|
4845
|
+
setDraftKind(null);
|
|
4805
4846
|
}
|
|
4806
4847
|
});
|
|
4807
4848
|
};
|
|
@@ -5056,9 +5097,11 @@ function RecordsAdminShell(props) {
|
|
|
5056
5097
|
RecordList,
|
|
5057
5098
|
{
|
|
5058
5099
|
items: leftItems,
|
|
5059
|
-
|
|
5100
|
+
selectedId: leftSelectedId,
|
|
5101
|
+
selectedAnchorKey: leftSelectedAnchorKey,
|
|
5060
5102
|
onSelect: onLeftSelect,
|
|
5061
|
-
|
|
5103
|
+
dirtyId,
|
|
5104
|
+
dirtyAnchorKey,
|
|
5062
5105
|
presentation: effectivePresentation,
|
|
5063
5106
|
renderListRow,
|
|
5064
5107
|
groupBy: effectiveGroupBy,
|
|
@@ -5151,7 +5194,7 @@ var RecordBrowser = ({
|
|
|
5151
5194
|
scopes,
|
|
5152
5195
|
activeScope,
|
|
5153
5196
|
onActiveScopeChange,
|
|
5154
|
-
|
|
5197
|
+
selectedId,
|
|
5155
5198
|
onSelectRef,
|
|
5156
5199
|
items,
|
|
5157
5200
|
counts,
|
|
@@ -5194,7 +5237,7 @@ var RecordBrowser = ({
|
|
|
5194
5237
|
!isLoading && error && /* @__PURE__ */ jsx(ErrorState, { error }),
|
|
5195
5238
|
!isLoading && !error && items.length === 0 && /* @__PURE__ */ jsx(EmptyState, { title: i18n.noResults, body: search ? void 0 : i18n.emptyBody }),
|
|
5196
5239
|
!isLoading && !error && items.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5197
|
-
/* @__PURE__ */ jsx(RecordList, { items,
|
|
5240
|
+
/* @__PURE__ */ jsx(RecordList, { items, selectedId, onSelect: onSelectRef }),
|
|
5198
5241
|
hasNextPage && /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
|
|
5199
5242
|
"button",
|
|
5200
5243
|
{
|
|
@@ -5459,16 +5502,13 @@ function useCollectedRecords(args) {
|
|
|
5459
5502
|
target.facetValue = facetValue;
|
|
5460
5503
|
const ctx = { SL, collectionId, appId, recordType };
|
|
5461
5504
|
const result = await matchRecords(ctx, parsedRefToTarget(target), { strategy: "all" }).catch(() => null);
|
|
5462
|
-
const
|
|
5463
|
-
const baseList =
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
depth: i
|
|
5470
|
-
};
|
|
5471
|
-
});
|
|
5505
|
+
const entries = result?.data ?? [];
|
|
5506
|
+
const baseList = entries.map((entry, i) => ({
|
|
5507
|
+
ref: entry.ref ?? "",
|
|
5508
|
+
scope: parseRef(entry.ref ?? ""),
|
|
5509
|
+
data: entry.data,
|
|
5510
|
+
depth: i
|
|
5511
|
+
}));
|
|
5472
5512
|
const sortKind = sort?.kind ?? "specificity";
|
|
5473
5513
|
const direction = sort?.direction ?? (sortKind === "specificity" ? "desc" : "asc");
|
|
5474
5514
|
const sign = direction === "desc" ? -1 : 1;
|
|
@@ -5551,11 +5591,11 @@ function useMergedRecord(args) {
|
|
|
5551
5591
|
target.facetValue = facetValue;
|
|
5552
5592
|
const ctx = { SL, collectionId, appId, recordType };
|
|
5553
5593
|
const result = await matchRecords(ctx, parsedRefToTarget(target), { strategy: "all" }).catch(() => null);
|
|
5554
|
-
const
|
|
5555
|
-
if (
|
|
5556
|
-
const present =
|
|
5557
|
-
ref: entry.
|
|
5558
|
-
data: entry.
|
|
5594
|
+
const entries = result?.data ?? [];
|
|
5595
|
+
if (entries.length === 0) return { data: null, provenance: {}, layers: [] };
|
|
5596
|
+
const present = entries.map((entry) => ({
|
|
5597
|
+
ref: entry.ref ?? "",
|
|
5598
|
+
data: entry.data
|
|
5559
5599
|
}));
|
|
5560
5600
|
const ordered = [...present].reverse();
|
|
5561
5601
|
let merged = null;
|
|
@@ -5578,6 +5618,6 @@ function useMergedRecord(args) {
|
|
|
5578
5618
|
};
|
|
5579
5619
|
}
|
|
5580
5620
|
|
|
5581
|
-
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList,
|
|
5621
|
+
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList, buildRef, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, downloadBlob, exportCsv, importCsv, mergeIcons, parseRef, pickHeaderIcon, resolutionChain, resolveRecord, statusToneLabel, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeProbe, useUnsavedGuard };
|
|
5582
5622
|
//# sourceMappingURL=index.js.map
|
|
5583
5623
|
//# sourceMappingURL=index.js.map
|