| 1 | import type { StoryProfile, WorkplaceData } from "@/lib/types"; |
| 2 | |
| 3 | /** Canonical overlay keys: `story` or `beat:{shotId}`. */ |
| 4 | export type FieldPath = "story" | `beat:${number}`; |
| 5 | |
| 6 | export type LeaseMode = "follow" | "held"; |
| 7 | |
| 8 | export type EditorSegment = { |
| 9 | id: string; |
| 10 | shotId: number; |
| 11 | text: string; |
| 12 | }; |
| 13 | |
| 14 | export type CommitAction = |
| 15 | | { type: "confirm_story" } |
| 16 | | { type: "start_generation" } |
| 17 | | { type: "start_merge" } |
| 18 | | { |
| 19 | type: "split_shot"; |
| 20 | shotId: number; |
| 21 | beforeText: string; |
| 22 | afterText: string; |
| 23 | } |
| 24 | | { type: "merge_shot"; shotId: number; mergedText: string } |
| 25 | | { type: "delete_shot"; shotId: number }; |
| 26 | |
| 27 | export type WorkplaceEditorState = { |
| 28 | server: WorkplaceData | null; |
| 29 | overlay: Partial<Record<FieldPath, string>>; |
| 30 | lease: Partial<Record<FieldPath, LeaseMode>>; |
| 31 | dirty: Partial<Record<FieldPath, boolean>>; |
| 32 | committing: boolean; |
| 33 | }; |
| 34 | |
| 35 | export type WorkplaceMutations = { |
| 36 | saveStory: (storyMd: string) => Promise<void>; |
| 37 | saveStoryProfile: (profile: StoryProfile) => Promise<void>; |
| 38 | confirmStory: (storyMd?: string) => Promise<void>; |
| 39 | startGeneration: () => Promise<void>; |
| 40 | startMerge: () => Promise<void>; |
| 41 | splitShot: ( |
| 42 | shotId: number, |
| 43 | payload: { before_text: string; after_text: string }, |
| 44 | ) => Promise<void>; |
| 45 | mergeShotUp: (shotId: number, mergedText?: string) => Promise<void>; |
| 46 | deleteShot: (shotId: number) => Promise<void>; |
| 47 | }; |
| 48 | |
| 49 | export function beatPath(shotId: number): FieldPath { |
| 50 | return `beat:${shotId}`; |
| 51 | } |
| 52 | |
| 53 | export function parseBeatPath(path: FieldPath): number | null { |
| 54 | if (path === "story") return null; |
| 55 | const id = Number(path.slice("beat:".length)); |
| 56 | return Number.isFinite(id) ? id : null; |
| 57 | } |
| 58 | |
| 59 | export function segmentIdForShot(shotId: number): string { |
| 60 | return `shot_${String(shotId).padStart(3, "0")}`; |
| 61 | } |
| 62 |