@lingjingai/script-editor 0.3.1 → 0.4.1
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/index.d.ts +42 -2
- package/dist/index.js +176 -121
- package/dist/index.js.map +1 -1
- package/dist/style.css +11 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -265,6 +265,15 @@ declare function getSceneContext(scene: Scene): {
|
|
|
265
265
|
state_id?: string | null;
|
|
266
266
|
}[];
|
|
267
267
|
};
|
|
268
|
+
/**
|
|
269
|
+
* Count how many scenes each asset appears in (its scene-cast / location / prop
|
|
270
|
+
* refs), in one pass. Drives the TOC's "出现次数" sort. v3-aware via getSceneContext.
|
|
271
|
+
*/
|
|
272
|
+
declare function countAssetAppearances(data: ScriptProject): {
|
|
273
|
+
actors: Map<string, number>;
|
|
274
|
+
locations: Map<string, number>;
|
|
275
|
+
props: Map<string, number>;
|
|
276
|
+
};
|
|
268
277
|
declare function getEpisodeTitle(episode: ScriptEpisode, index: number): string;
|
|
269
278
|
|
|
270
279
|
interface SelectOption {
|
|
@@ -289,6 +298,33 @@ type ScriptFormat = "standard" | "asian";
|
|
|
289
298
|
|
|
290
299
|
type SaveStatus = "idle" | "saving" | "saved" | "error";
|
|
291
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Flattens a ScriptProject into ONE continuous, stable-keyed item list for the
|
|
303
|
+
* virtualized stream — mirroring agent-frontend's single global scroll:
|
|
304
|
+
* each episode (episode-header → scene → scene → …)
|
|
305
|
+
* → asset groups (角色 / 场景 / 道具: group-header → asset-card × N)
|
|
306
|
+
* Plus selection ↔ flatIndex lookups (two-way) for scroll/scrollspy sync.
|
|
307
|
+
* (世界观 & 风格 is edited in a dialog now, not inline — see ScriptEditor.)
|
|
308
|
+
*/
|
|
309
|
+
|
|
310
|
+
type AssetGroup = "actors" | "locations" | "props";
|
|
311
|
+
/** An asset as seen by `assetSort` — enough to reproduce any TOC ordering
|
|
312
|
+
* (by name / importance / appearance count) host-side. */
|
|
313
|
+
interface AssetSortItem {
|
|
314
|
+
group: AssetGroup;
|
|
315
|
+
id: string;
|
|
316
|
+
name: string;
|
|
317
|
+
importance?: string;
|
|
318
|
+
/** appearance count (scenes referencing this asset). */
|
|
319
|
+
count: number;
|
|
320
|
+
}
|
|
321
|
+
/** The built-in asset ordering, ALSO used by the bundled StudioToc: background
|
|
322
|
+
* last, then appearance count desc, ties by name. This is the single source of
|
|
323
|
+
* truth so the built-in TOC and the preview agree by default. Hosts override
|
|
324
|
+
* BOTH by passing their own comparator as `assetSort` (and feeding the same one
|
|
325
|
+
* to their own TOC). */
|
|
326
|
+
declare function defaultAssetSort(a: AssetSortItem, b: AssetSortItem): number;
|
|
327
|
+
|
|
292
328
|
/**
|
|
293
329
|
* Reference focus — the INVERSE of "quote to chat". The host pushes a
|
|
294
330
|
* ScriptReferenceFocusRequest (e.g. when a chat message / comment that quotes
|
|
@@ -576,6 +612,10 @@ interface ScriptEditorProps extends ScriptEditorAdapters {
|
|
|
576
612
|
sceneId: string;
|
|
577
613
|
actionIndex: number;
|
|
578
614
|
}) => void;
|
|
615
|
+
/** order assets within each group in the preview (角色/场景/道具). Feed the SAME
|
|
616
|
+
* comparator your TOC uses so the left nav and right preview stay in lockstep.
|
|
617
|
+
* Omit → script.json array order. */
|
|
618
|
+
assetSort?: (a: AssetSortItem, b: AssetSortItem) => number;
|
|
579
619
|
}
|
|
580
620
|
/** A host range highlight targeting one action (same coords as DiffActionMark). */
|
|
581
621
|
interface ScriptHighlight {
|
|
@@ -587,7 +627,7 @@ interface ScriptHighlight {
|
|
|
587
627
|
className?: string;
|
|
588
628
|
style?: React.CSSProperties;
|
|
589
629
|
}
|
|
590
|
-
declare function ScriptEditor({ value, onEdit: onEditProp, selection: controlledSelection, onSelectionChange, format: controlledFormat, onFormatChange, disabled, className, dark, toc, onTitleChange, topBarActions, saveStatus, canUndo, canRedo, onUndo, onRedo, onEditingChange, referenceFocusRequest, scrollScopeKey, showAssets, showTitle, showFormatToggle, paper, showTimestamp, highlights, contentWidth, showSaveCapsule, onActionHover, onActionClick, diff, asset, onAddChatReferences, onRequestAssetDelete, }: ScriptEditorProps): react.JSX.Element;
|
|
630
|
+
declare function ScriptEditor({ value, onEdit: onEditProp, selection: controlledSelection, onSelectionChange, format: controlledFormat, onFormatChange, disabled, className, dark, toc, onTitleChange, topBarActions, saveStatus, canUndo, canRedo, onUndo, onRedo, onEditingChange, referenceFocusRequest, scrollScopeKey, showAssets, showTitle, showFormatToggle, paper, showTimestamp, highlights, contentWidth, showSaveCapsule, onActionHover, onActionClick, assetSort, diff, asset, onAddChatReferences, onRequestAssetDelete, }: ScriptEditorProps): react.JSX.Element;
|
|
591
631
|
|
|
592
632
|
/**
|
|
593
633
|
* Action timestamps live at `action.extend.timestamp` as an in-episode
|
|
@@ -898,4 +938,4 @@ declare function DeleteConfirmButton({ onConfirm, disabled, targetScope, title,
|
|
|
898
938
|
description?: string;
|
|
899
939
|
}): react.JSX.Element;
|
|
900
940
|
|
|
901
|
-
export { type AssetAdapter, type AssetDeleteRequest, type AssetState, type ChangeSet, type ChatReference, DeleteConfirmButton, type DiffActionMark, type DiffAdapter, type DiffSceneMark, EMPTY_SELECTION, EditableText, type EpisodeWorkspaceView, type FieldChange, type Importance, type ParsedTimestamp, Popover, type SaveStatus, type Scene, type SceneActionDiff, type SceneChangeKind, type SceneContext, type SceneEnvironment, type ScriptActor, ScriptContentType, type ScriptData, ScriptEditor, type ScriptEditorAdapters, type ScriptEditorProps, type ScriptEpisode, type ScriptFormat, type ScriptHighlight, type ScriptItem, type ScriptLocation, type ScriptNav, type ScriptNavEntity, type ScriptNavEpisode, type ScriptNavScene, type ScriptProject, type ScriptProp, type ScriptReferenceFocusRequest, type ScriptReferenceLocator, type ScriptSpeaker, type ScriptTargetKind, SelectField, type StateChange, type StudioSelection, type StudioSelectionFrom, type StudioSelectionOrigin, type TransitionPrompt, type V3Speaker, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, findBaselineScene, formatTimestamp, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, index as mutations, rejectActionToBaseline, rejectSceneToBaseline, sceneChangeKey, selectionFromScriptReference, selectionTargetKey, withOrigin };
|
|
941
|
+
export { type AssetAdapter, type AssetDeleteRequest, type AssetSortItem, type AssetState, type ChangeSet, type ChatReference, DeleteConfirmButton, type DiffActionMark, type DiffAdapter, type DiffSceneMark, EMPTY_SELECTION, EditableText, type EpisodeWorkspaceView, type FieldChange, type Importance, type ParsedTimestamp, Popover, type SaveStatus, type Scene, type SceneActionDiff, type SceneChangeKind, type SceneContext, type SceneEnvironment, type ScriptActor, ScriptContentType, type ScriptData, ScriptEditor, type ScriptEditorAdapters, type ScriptEditorProps, type ScriptEpisode, type ScriptFormat, type ScriptHighlight, type ScriptItem, type ScriptLocation, type ScriptNav, type ScriptNavEntity, type ScriptNavEpisode, type ScriptNavScene, type ScriptProject, type ScriptProp, type ScriptReferenceFocusRequest, type ScriptReferenceLocator, type ScriptSpeaker, type ScriptTargetKind, SelectField, type StateChange, type StudioSelection, type StudioSelectionFrom, type StudioSelectionOrigin, type TransitionPrompt, type V3Speaker, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, countAssetAppearances, defaultAssetSort, findBaselineScene, formatTimestamp, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, index as mutations, rejectActionToBaseline, rejectSceneToBaseline, sceneChangeKey, selectionFromScriptReference, selectionTargetKey, withOrigin };
|
package/dist/index.js
CHANGED
|
@@ -471,6 +471,137 @@ function getDialogueDeliveryLabel(delivery) {
|
|
|
471
471
|
return "";
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
+
// src/stream/flat-items.ts
|
|
475
|
+
var SCENE_KEY = (e, s) => `ep:${e}:sc:${s}`;
|
|
476
|
+
var SCENE_ID_KEY = (e, id) => `ep:${e}:id:${id}`;
|
|
477
|
+
var ASSET_KEY = (g, id) => `${g}:${id}`;
|
|
478
|
+
function safeId(raw, fallback) {
|
|
479
|
+
const t = (raw ?? "").toString().trim();
|
|
480
|
+
return t.length > 0 ? t : fallback;
|
|
481
|
+
}
|
|
482
|
+
var GROUP_LABEL = { actors: "\u89D2\u8272", locations: "\u573A\u666F", props: "\u9053\u5177" };
|
|
483
|
+
var assetGroupLabel = (g) => GROUP_LABEL[g];
|
|
484
|
+
function defaultAssetSort(a, b) {
|
|
485
|
+
const bgA = a.importance === "background" ? 1 : 0;
|
|
486
|
+
const bgB = b.importance === "background" ? 1 : 0;
|
|
487
|
+
return bgA - bgB || b.count - a.count || a.name.localeCompare(b.name, "zh");
|
|
488
|
+
}
|
|
489
|
+
function buildFlatStream(data, opts = {}) {
|
|
490
|
+
const includeAssets = opts.includeAssets ?? true;
|
|
491
|
+
const items = [];
|
|
492
|
+
const indexByKey = /* @__PURE__ */ new Map();
|
|
493
|
+
const sceneIndexLookup = /* @__PURE__ */ new Map();
|
|
494
|
+
const sceneIdLookup = /* @__PURE__ */ new Map();
|
|
495
|
+
const assetIndexLookup = /* @__PURE__ */ new Map();
|
|
496
|
+
const push = (item) => {
|
|
497
|
+
indexByKey.set(item.key, items.length);
|
|
498
|
+
if (item.kind === "scene") {
|
|
499
|
+
sceneIndexLookup.set(SCENE_KEY(item.episodeIdx, item.sceneIdx), items.length);
|
|
500
|
+
sceneIdLookup.set(SCENE_ID_KEY(item.episodeIdx, item.sceneId), items.length);
|
|
501
|
+
}
|
|
502
|
+
if (item.kind === "asset-card") assetIndexLookup.set(ASSET_KEY(item.group, item.assetId), items.length);
|
|
503
|
+
items.push(item);
|
|
504
|
+
};
|
|
505
|
+
if (!data) {
|
|
506
|
+
return { items, indexByKey, sceneIndexLookup, sceneIdLookup, assetIndexLookup, paperStartKey: null, paperEndKey: null };
|
|
507
|
+
}
|
|
508
|
+
let paperStartKey = null;
|
|
509
|
+
let paperEndKey = null;
|
|
510
|
+
(data.episodes ?? []).forEach((episode, ei) => {
|
|
511
|
+
const headerKey = `ep:${ei}:header`;
|
|
512
|
+
push({ key: headerKey, kind: "episode-header", episodeIdx: ei });
|
|
513
|
+
if (paperStartKey === null) paperStartKey = headerKey;
|
|
514
|
+
paperEndKey = headerKey;
|
|
515
|
+
const scenes = episode.scenes ?? [];
|
|
516
|
+
if (scenes.length === 0) {
|
|
517
|
+
const emptyKey = `ep:${ei}:empty`;
|
|
518
|
+
push({ key: emptyKey, kind: "episode-empty", episodeIdx: ei });
|
|
519
|
+
paperEndKey = emptyKey;
|
|
520
|
+
} else {
|
|
521
|
+
scenes.forEach((scene, si) => {
|
|
522
|
+
const sceneId = safeId(scene.scene_id, `__idx:${si}`);
|
|
523
|
+
const key = `sc:ep${ei}:sc${si}:${sceneId}`;
|
|
524
|
+
push({
|
|
525
|
+
key,
|
|
526
|
+
kind: "scene",
|
|
527
|
+
episodeIdx: ei,
|
|
528
|
+
sceneIdx: si,
|
|
529
|
+
sceneId,
|
|
530
|
+
isStart: si === 0,
|
|
531
|
+
isEnd: si === scenes.length - 1
|
|
532
|
+
});
|
|
533
|
+
paperEndKey = key;
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
push({ key: "add-episode", kind: "add-episode" });
|
|
538
|
+
if (includeAssets) {
|
|
539
|
+
const specs = [
|
|
540
|
+
{ group: "actors", ids: (data.actors ?? []).map((a, i) => safeId(a.actor_id, `__idx:${i}`)) },
|
|
541
|
+
{ group: "locations", ids: (data.locations ?? []).map((l, i) => safeId(l.location_id, `__idx:${i}`)) },
|
|
542
|
+
{ group: "props", ids: (data.props ?? []).map((p, i) => safeId(p.prop_id, `__idx:${i}`)) }
|
|
543
|
+
];
|
|
544
|
+
const sort = opts.assetSort ?? defaultAssetSort;
|
|
545
|
+
const counts = countAssetAppearances(data);
|
|
546
|
+
const actorMap = getActorMap(data.actors ?? []);
|
|
547
|
+
const locationMap = getLocationMap(data.locations ?? []);
|
|
548
|
+
const propMap = getPropMap(data.props ?? []);
|
|
549
|
+
const enrich = (group, id) => {
|
|
550
|
+
if (group === "actors") return { group, id, name: getActorDisplayName(actorMap.get(id)) || id, importance: actorMap.get(id)?.importance, count: counts.actors.get(id) ?? 0 };
|
|
551
|
+
if (group === "locations") return { group, id, name: getLocationDisplayName(locationMap.get(id)) || id, importance: locationMap.get(id)?.importance, count: counts.locations.get(id) ?? 0 };
|
|
552
|
+
return { group, id, name: getPropDisplayName(propMap.get(id)) || id, importance: propMap.get(id)?.importance, count: counts.props.get(id) ?? 0 };
|
|
553
|
+
};
|
|
554
|
+
for (const spec of specs) {
|
|
555
|
+
spec.ids = spec.ids.map((id) => enrich(spec.group, id)).sort(sort).map((it) => it.id);
|
|
556
|
+
}
|
|
557
|
+
for (const { group, ids } of specs) {
|
|
558
|
+
push({ key: `asset-group:${group}`, kind: "asset-group-header", group });
|
|
559
|
+
ids.forEach((assetId) => push({ key: `asset:${group}:${assetId}`, kind: "asset-card", group, assetId }));
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return { items, indexByKey, sceneIndexLookup, sceneIdLookup, assetIndexLookup, paperStartKey, paperEndKey };
|
|
563
|
+
}
|
|
564
|
+
function selectionToFlatIndex(stream, sel) {
|
|
565
|
+
switch (sel.kind) {
|
|
566
|
+
case "episode":
|
|
567
|
+
return stream.indexByKey.get(`ep:${sel.episodeIdx}:header`) ?? null;
|
|
568
|
+
case "scene":
|
|
569
|
+
return stream.sceneIndexLookup.get(SCENE_KEY(sel.episodeIdx, sel.sceneIdx)) ?? null;
|
|
570
|
+
case "clip": {
|
|
571
|
+
if (sel.sceneIdx !== void 0) {
|
|
572
|
+
const byIdx = stream.sceneIndexLookup.get(SCENE_KEY(sel.episodeIdx, sel.sceneIdx));
|
|
573
|
+
if (byIdx !== void 0) return byIdx;
|
|
574
|
+
}
|
|
575
|
+
const id = (sel.sceneId ?? "").trim();
|
|
576
|
+
return id ? stream.sceneIdLookup.get(SCENE_ID_KEY(sel.episodeIdx, id)) ?? null : null;
|
|
577
|
+
}
|
|
578
|
+
case "actor":
|
|
579
|
+
return stream.assetIndexLookup.get(ASSET_KEY("actors", sel.actorId)) ?? null;
|
|
580
|
+
case "location":
|
|
581
|
+
return stream.assetIndexLookup.get(ASSET_KEY("locations", sel.locationId)) ?? null;
|
|
582
|
+
case "prop":
|
|
583
|
+
return stream.assetIndexLookup.get(ASSET_KEY("props", sel.propId)) ?? null;
|
|
584
|
+
default:
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
function flatIndexToSelection(stream, idx) {
|
|
589
|
+
const item = stream.items[idx];
|
|
590
|
+
if (!item) return null;
|
|
591
|
+
switch (item.kind) {
|
|
592
|
+
case "episode-header":
|
|
593
|
+
return { kind: "episode", episodeIdx: item.episodeIdx };
|
|
594
|
+
case "scene":
|
|
595
|
+
return { kind: "scene", episodeIdx: item.episodeIdx, sceneIdx: item.sceneIdx };
|
|
596
|
+
case "asset-card":
|
|
597
|
+
if (item.group === "actors") return { kind: "actor", actorId: item.assetId };
|
|
598
|
+
if (item.group === "locations") return { kind: "location", locationId: item.assetId };
|
|
599
|
+
return { kind: "prop", propId: item.assetId };
|
|
600
|
+
default:
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
474
605
|
// src/cn.ts
|
|
475
606
|
function cn(...parts) {
|
|
476
607
|
return parts.filter(Boolean).join(" ");
|
|
@@ -501,7 +632,8 @@ function StudioToc({
|
|
|
501
632
|
data,
|
|
502
633
|
selection,
|
|
503
634
|
onSelect,
|
|
504
|
-
onAddEpisode
|
|
635
|
+
onAddEpisode,
|
|
636
|
+
assetSort
|
|
505
637
|
}) {
|
|
506
638
|
const episodes = data.episodes ?? [];
|
|
507
639
|
const [episodesOpen, setEpisodesOpen] = useState(true);
|
|
@@ -576,7 +708,9 @@ function StudioToc({
|
|
|
576
708
|
{
|
|
577
709
|
icon: Users,
|
|
578
710
|
label: "\u89D2\u8272",
|
|
711
|
+
group: "actors",
|
|
579
712
|
emptyText: "\u5C1A\u65E0\u89D2\u8272",
|
|
713
|
+
sort: assetSort,
|
|
580
714
|
items: (data.actors ?? []).map((a) => {
|
|
581
715
|
const id = (a.actor_id ?? "").trim();
|
|
582
716
|
return { id, name: getActorDisplayName(a), importance: a.importance, count: counts.actors.get(id) ?? 0 };
|
|
@@ -591,7 +725,9 @@ function StudioToc({
|
|
|
591
725
|
{
|
|
592
726
|
icon: MapPin,
|
|
593
727
|
label: "\u573A\u666F",
|
|
728
|
+
group: "locations",
|
|
594
729
|
emptyText: "\u5C1A\u65E0\u573A\u666F",
|
|
730
|
+
sort: assetSort,
|
|
595
731
|
items: (data.locations ?? []).map((l) => {
|
|
596
732
|
const id = (l.location_id ?? "").trim();
|
|
597
733
|
return { id, name: getLocationDisplayName(l), importance: l.importance, count: counts.locations.get(id) ?? 0 };
|
|
@@ -606,7 +742,9 @@ function StudioToc({
|
|
|
606
742
|
{
|
|
607
743
|
icon: Package,
|
|
608
744
|
label: "\u9053\u5177",
|
|
745
|
+
group: "props",
|
|
609
746
|
emptyText: "\u5C1A\u65E0\u9053\u5177",
|
|
747
|
+
sort: assetSort,
|
|
610
748
|
items: (data.props ?? []).map((p) => {
|
|
611
749
|
const id = (p.prop_id ?? "").trim();
|
|
612
750
|
return { id, name: getPropDisplayName(p), importance: p.importance, count: counts.props.get(id) ?? 0 };
|
|
@@ -618,21 +756,47 @@ function StudioToc({
|
|
|
618
756
|
)
|
|
619
757
|
] });
|
|
620
758
|
}
|
|
759
|
+
function TocLabel({ text, className }) {
|
|
760
|
+
const ref = useRef(null);
|
|
761
|
+
const [tip, setTip] = useState(null);
|
|
762
|
+
const onEnter = () => {
|
|
763
|
+
const el = ref.current;
|
|
764
|
+
if (!el || el.scrollWidth <= el.clientWidth) return;
|
|
765
|
+
const r = el.getBoundingClientRect();
|
|
766
|
+
setTip({ x: r.right, y: r.top + r.height / 2 });
|
|
767
|
+
};
|
|
768
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
769
|
+
/* @__PURE__ */ jsx(
|
|
770
|
+
"span",
|
|
771
|
+
{
|
|
772
|
+
ref,
|
|
773
|
+
className,
|
|
774
|
+
onMouseEnter: onEnter,
|
|
775
|
+
onMouseLeave: () => setTip(null),
|
|
776
|
+
children: text
|
|
777
|
+
}
|
|
778
|
+
),
|
|
779
|
+
tip ? /* @__PURE__ */ jsx("span", { className: "lj-se-toc-tip", style: { left: tip.x, top: tip.y }, role: "tooltip", children: text }) : null
|
|
780
|
+
] });
|
|
781
|
+
}
|
|
621
782
|
function EntityGroup({
|
|
622
783
|
icon: Icon,
|
|
623
784
|
label,
|
|
785
|
+
group,
|
|
624
786
|
emptyText,
|
|
625
787
|
items,
|
|
788
|
+
sort,
|
|
626
789
|
highlighted,
|
|
627
790
|
isActive,
|
|
628
791
|
onPick
|
|
629
792
|
}) {
|
|
630
793
|
const [open, setOpen] = useState(true);
|
|
631
794
|
const [bgOpen, setBgOpen] = useState(false);
|
|
632
|
-
const
|
|
795
|
+
const cmp = sort ?? defaultAssetSort;
|
|
796
|
+
const byCmp = (a, b) => cmp({ group, ...a }, { group, ...b });
|
|
633
797
|
const valid = items.filter((i) => i.id);
|
|
634
|
-
const featured = valid.filter((i) => i.importance !== "background").sort(
|
|
635
|
-
const background = valid.filter((i) => i.importance === "background").sort(
|
|
798
|
+
const featured = valid.filter((i) => i.importance !== "background").sort(byCmp);
|
|
799
|
+
const background = valid.filter((i) => i.importance === "background").sort(byCmp);
|
|
636
800
|
const row = (i, bg = false) => /* @__PURE__ */ jsxs(
|
|
637
801
|
"button",
|
|
638
802
|
{
|
|
@@ -641,7 +805,7 @@ function EntityGroup({
|
|
|
641
805
|
onClick: () => onPick(i.id),
|
|
642
806
|
children: [
|
|
643
807
|
/* @__PURE__ */ jsx(Icon, { className: "lj-se-tocitem-icon lj-se-ic-3", strokeWidth: 1.5 }),
|
|
644
|
-
/* @__PURE__ */ jsx(
|
|
808
|
+
/* @__PURE__ */ jsx(TocLabel, { className: "lj-se-tocitem-label", text: i.name }),
|
|
645
809
|
i.count > 0 ? /* @__PURE__ */ jsx("span", { className: "lj-se-tocitem-meta", children: i.count }) : null
|
|
646
810
|
]
|
|
647
811
|
},
|
|
@@ -2847,119 +3011,6 @@ function SceneEditorImpl({
|
|
|
2847
3011
|
}
|
|
2848
3012
|
var SceneEditor = memo(SceneEditorImpl);
|
|
2849
3013
|
|
|
2850
|
-
// src/stream/flat-items.ts
|
|
2851
|
-
var SCENE_KEY = (e, s) => `ep:${e}:sc:${s}`;
|
|
2852
|
-
var SCENE_ID_KEY = (e, id) => `ep:${e}:id:${id}`;
|
|
2853
|
-
var ASSET_KEY = (g, id) => `${g}:${id}`;
|
|
2854
|
-
function safeId(raw, fallback) {
|
|
2855
|
-
const t = (raw ?? "").toString().trim();
|
|
2856
|
-
return t.length > 0 ? t : fallback;
|
|
2857
|
-
}
|
|
2858
|
-
var GROUP_LABEL = { actors: "\u89D2\u8272", locations: "\u573A\u666F", props: "\u9053\u5177" };
|
|
2859
|
-
var assetGroupLabel = (g) => GROUP_LABEL[g];
|
|
2860
|
-
function buildFlatStream(data, opts = {}) {
|
|
2861
|
-
const includeAssets = opts.includeAssets ?? true;
|
|
2862
|
-
const items = [];
|
|
2863
|
-
const indexByKey = /* @__PURE__ */ new Map();
|
|
2864
|
-
const sceneIndexLookup = /* @__PURE__ */ new Map();
|
|
2865
|
-
const sceneIdLookup = /* @__PURE__ */ new Map();
|
|
2866
|
-
const assetIndexLookup = /* @__PURE__ */ new Map();
|
|
2867
|
-
const push = (item) => {
|
|
2868
|
-
indexByKey.set(item.key, items.length);
|
|
2869
|
-
if (item.kind === "scene") {
|
|
2870
|
-
sceneIndexLookup.set(SCENE_KEY(item.episodeIdx, item.sceneIdx), items.length);
|
|
2871
|
-
sceneIdLookup.set(SCENE_ID_KEY(item.episodeIdx, item.sceneId), items.length);
|
|
2872
|
-
}
|
|
2873
|
-
if (item.kind === "asset-card") assetIndexLookup.set(ASSET_KEY(item.group, item.assetId), items.length);
|
|
2874
|
-
items.push(item);
|
|
2875
|
-
};
|
|
2876
|
-
if (!data) {
|
|
2877
|
-
return { items, indexByKey, sceneIndexLookup, sceneIdLookup, assetIndexLookup, paperStartKey: null, paperEndKey: null };
|
|
2878
|
-
}
|
|
2879
|
-
let paperStartKey = null;
|
|
2880
|
-
let paperEndKey = null;
|
|
2881
|
-
(data.episodes ?? []).forEach((episode, ei) => {
|
|
2882
|
-
const headerKey = `ep:${ei}:header`;
|
|
2883
|
-
push({ key: headerKey, kind: "episode-header", episodeIdx: ei });
|
|
2884
|
-
if (paperStartKey === null) paperStartKey = headerKey;
|
|
2885
|
-
paperEndKey = headerKey;
|
|
2886
|
-
const scenes = episode.scenes ?? [];
|
|
2887
|
-
if (scenes.length === 0) {
|
|
2888
|
-
const emptyKey = `ep:${ei}:empty`;
|
|
2889
|
-
push({ key: emptyKey, kind: "episode-empty", episodeIdx: ei });
|
|
2890
|
-
paperEndKey = emptyKey;
|
|
2891
|
-
} else {
|
|
2892
|
-
scenes.forEach((scene, si) => {
|
|
2893
|
-
const sceneId = safeId(scene.scene_id, `__idx:${si}`);
|
|
2894
|
-
const key = `sc:ep${ei}:sc${si}:${sceneId}`;
|
|
2895
|
-
push({
|
|
2896
|
-
key,
|
|
2897
|
-
kind: "scene",
|
|
2898
|
-
episodeIdx: ei,
|
|
2899
|
-
sceneIdx: si,
|
|
2900
|
-
sceneId,
|
|
2901
|
-
isStart: si === 0,
|
|
2902
|
-
isEnd: si === scenes.length - 1
|
|
2903
|
-
});
|
|
2904
|
-
paperEndKey = key;
|
|
2905
|
-
});
|
|
2906
|
-
}
|
|
2907
|
-
});
|
|
2908
|
-
push({ key: "add-episode", kind: "add-episode" });
|
|
2909
|
-
if (includeAssets) {
|
|
2910
|
-
const specs = [
|
|
2911
|
-
{ group: "actors", ids: (data.actors ?? []).map((a, i) => safeId(a.actor_id, `__idx:${i}`)) },
|
|
2912
|
-
{ group: "locations", ids: (data.locations ?? []).map((l, i) => safeId(l.location_id, `__idx:${i}`)) },
|
|
2913
|
-
{ group: "props", ids: (data.props ?? []).map((p, i) => safeId(p.prop_id, `__idx:${i}`)) }
|
|
2914
|
-
];
|
|
2915
|
-
for (const { group, ids } of specs) {
|
|
2916
|
-
push({ key: `asset-group:${group}`, kind: "asset-group-header", group });
|
|
2917
|
-
ids.forEach((assetId) => push({ key: `asset:${group}:${assetId}`, kind: "asset-card", group, assetId }));
|
|
2918
|
-
}
|
|
2919
|
-
}
|
|
2920
|
-
return { items, indexByKey, sceneIndexLookup, sceneIdLookup, assetIndexLookup, paperStartKey, paperEndKey };
|
|
2921
|
-
}
|
|
2922
|
-
function selectionToFlatIndex(stream, sel) {
|
|
2923
|
-
switch (sel.kind) {
|
|
2924
|
-
case "episode":
|
|
2925
|
-
return stream.indexByKey.get(`ep:${sel.episodeIdx}:header`) ?? null;
|
|
2926
|
-
case "scene":
|
|
2927
|
-
return stream.sceneIndexLookup.get(SCENE_KEY(sel.episodeIdx, sel.sceneIdx)) ?? null;
|
|
2928
|
-
case "clip": {
|
|
2929
|
-
if (sel.sceneIdx !== void 0) {
|
|
2930
|
-
const byIdx = stream.sceneIndexLookup.get(SCENE_KEY(sel.episodeIdx, sel.sceneIdx));
|
|
2931
|
-
if (byIdx !== void 0) return byIdx;
|
|
2932
|
-
}
|
|
2933
|
-
const id = (sel.sceneId ?? "").trim();
|
|
2934
|
-
return id ? stream.sceneIdLookup.get(SCENE_ID_KEY(sel.episodeIdx, id)) ?? null : null;
|
|
2935
|
-
}
|
|
2936
|
-
case "actor":
|
|
2937
|
-
return stream.assetIndexLookup.get(ASSET_KEY("actors", sel.actorId)) ?? null;
|
|
2938
|
-
case "location":
|
|
2939
|
-
return stream.assetIndexLookup.get(ASSET_KEY("locations", sel.locationId)) ?? null;
|
|
2940
|
-
case "prop":
|
|
2941
|
-
return stream.assetIndexLookup.get(ASSET_KEY("props", sel.propId)) ?? null;
|
|
2942
|
-
default:
|
|
2943
|
-
return null;
|
|
2944
|
-
}
|
|
2945
|
-
}
|
|
2946
|
-
function flatIndexToSelection(stream, idx) {
|
|
2947
|
-
const item = stream.items[idx];
|
|
2948
|
-
if (!item) return null;
|
|
2949
|
-
switch (item.kind) {
|
|
2950
|
-
case "episode-header":
|
|
2951
|
-
return { kind: "episode", episodeIdx: item.episodeIdx };
|
|
2952
|
-
case "scene":
|
|
2953
|
-
return { kind: "scene", episodeIdx: item.episodeIdx, sceneIdx: item.sceneIdx };
|
|
2954
|
-
case "asset-card":
|
|
2955
|
-
if (item.group === "actors") return { kind: "actor", actorId: item.assetId };
|
|
2956
|
-
if (item.group === "locations") return { kind: "location", locationId: item.assetId };
|
|
2957
|
-
return { kind: "prop", propId: item.assetId };
|
|
2958
|
-
default:
|
|
2959
|
-
return null;
|
|
2960
|
-
}
|
|
2961
|
-
}
|
|
2962
|
-
|
|
2963
3014
|
// src/mutations/entity-mutations.ts
|
|
2964
3015
|
var ID_FIELD = {
|
|
2965
3016
|
actor: "actor_id",
|
|
@@ -3659,6 +3710,7 @@ function ScriptStream({
|
|
|
3659
3710
|
onRejectAction,
|
|
3660
3711
|
scrollScopeKey,
|
|
3661
3712
|
includeAssets = true,
|
|
3713
|
+
assetSort,
|
|
3662
3714
|
paper = true,
|
|
3663
3715
|
showTimestamp = false,
|
|
3664
3716
|
highlights,
|
|
@@ -3668,7 +3720,7 @@ function ScriptStream({
|
|
|
3668
3720
|
onSelectionChange,
|
|
3669
3721
|
onRequestAssetDelete
|
|
3670
3722
|
}) {
|
|
3671
|
-
const stream = useMemo(() => buildFlatStream(value, { includeAssets }), [value, includeAssets]);
|
|
3723
|
+
const stream = useMemo(() => buildFlatStream(value, { includeAssets, assetSort }), [value, includeAssets, assetSort]);
|
|
3672
3724
|
const highlightsByScene = useMemo(() => {
|
|
3673
3725
|
const m = /* @__PURE__ */ new Map();
|
|
3674
3726
|
for (const h of highlights ?? []) {
|
|
@@ -4640,6 +4692,7 @@ function ScriptEditor({
|
|
|
4640
4692
|
showSaveCapsule = true,
|
|
4641
4693
|
onActionHover,
|
|
4642
4694
|
onActionClick,
|
|
4695
|
+
assetSort,
|
|
4643
4696
|
diff,
|
|
4644
4697
|
asset,
|
|
4645
4698
|
onAddChatReferences,
|
|
@@ -4801,6 +4854,7 @@ function ScriptEditor({
|
|
|
4801
4854
|
onRejectAction: diff?.onRejectAction,
|
|
4802
4855
|
scrollScopeKey,
|
|
4803
4856
|
includeAssets: showAssets,
|
|
4857
|
+
assetSort,
|
|
4804
4858
|
paper,
|
|
4805
4859
|
showTimestamp,
|
|
4806
4860
|
highlights: streamHighlights,
|
|
@@ -4824,7 +4878,8 @@ function ScriptEditor({
|
|
|
4824
4878
|
data: value,
|
|
4825
4879
|
selection,
|
|
4826
4880
|
onSelect: setSelection,
|
|
4827
|
-
onAddEpisode: disabled ? void 0 : () => onEdit((p) => addEpisode(p))
|
|
4881
|
+
onAddEpisode: disabled ? void 0 : () => onEdit((p) => addEpisode(p)),
|
|
4882
|
+
assetSort
|
|
4828
4883
|
}
|
|
4829
4884
|
) : null,
|
|
4830
4885
|
/* @__PURE__ */ jsxs("div", { className: "lj-se-main", children: [
|
|
@@ -5077,6 +5132,6 @@ function DeleteConfirmButton({
|
|
|
5077
5132
|
);
|
|
5078
5133
|
}
|
|
5079
5134
|
|
|
5080
|
-
export { DeleteConfirmButton, EMPTY_SELECTION, EditableText, Popover, ScriptContentType, ScriptEditor, SelectField, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, findBaselineScene, formatTimestamp, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, mutations_exports as mutations, rejectActionToBaseline, rejectSceneToBaseline, sceneChangeKey, selectionFromScriptReference, selectionTargetKey, withOrigin };
|
|
5135
|
+
export { DeleteConfirmButton, EMPTY_SELECTION, EditableText, Popover, ScriptContentType, ScriptEditor, SelectField, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, countAssetAppearances, defaultAssetSort, findBaselineScene, formatTimestamp, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, mutations_exports as mutations, rejectActionToBaseline, rejectSceneToBaseline, sceneChangeKey, selectionFromScriptReference, selectionTargetKey, withOrigin };
|
|
5081
5136
|
//# sourceMappingURL=index.js.map
|
|
5082
5137
|
//# sourceMappingURL=index.js.map
|