1.0.2: persist editor-session UI state with the project
Canvas zoom + pan, crop / mask-preview / stage-preview / centre- crosshair overlays, and timeline snap / show-locked / displayMode / px-per-sec / auto-fit now ride along in the saved project under a new optional `editor` block. Reopening a project restores the workbench exactly how the user left it — zoom level, pan offset, HUD toggles, timeline density — instead of snapping back to defaults. Editor state lives on the store as a sibling of `this.project` rather than inside it, so `JSON.stringify(store.project)` (the undo/redo snapshot) still only captures content. The new `projectForSave` getter stitches the two on the way to disk; `loadProject` reads them back apart on the way in. Saves through App.vue, the rename flow, and IDB recents all go through `projectForSave`. CanvasStage skips its first auto-fit when a non-default canvas zoom/pan was restored so the user's exact view survives mount. Frame-based export options pick up the same source of truth for a consistent starting point. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
cd9cf91ef0
commit
647f09b287
9 files changed
+285
-19
No files matched your search
@@ -52,19 +52,45 @@ const stageRef = ref<{ getStage(): Konva.Stage } | null>(null)
|
||||
const bgVideoEl = ref<HTMLVideoElement | null>(null)
|
||||
const transformerRef = ref<{ getNode(): Konva.Transformer } | null>(null)
|
||||
|
||||
const zoom = ref(1)
|
||||
const viewX = ref(0)
|
||||
const viewY = ref(0)
|
||||
const cropObjects = ref(false)
|
||||
const maskPreview = ref(false)
|
||||
// Canvas zoom / pan / overlay toggles live on the store so the
|
||||
// project file can round-trip the workbench state. Thin
|
||||
// writableComputed shims keep the rest of this component's code
|
||||
// (which reads/writes `zoom.value`, `cropObjects.value = …`, etc.)
|
||||
// unchanged.
|
||||
const zoom = computed<number>({
|
||||
get: () => store.editor.canvasZoom,
|
||||
set: (v) => { store.editor.canvasZoom = v },
|
||||
})
|
||||
const viewX = computed<number>({
|
||||
get: () => store.editor.canvasViewX,
|
||||
set: (v) => { store.editor.canvasViewX = v },
|
||||
})
|
||||
const viewY = computed<number>({
|
||||
get: () => store.editor.canvasViewY,
|
||||
set: (v) => { store.editor.canvasViewY = v },
|
||||
})
|
||||
const cropObjects = computed<boolean>({
|
||||
get: () => store.editor.cropObjects,
|
||||
set: (v) => { store.editor.cropObjects = v },
|
||||
})
|
||||
const maskPreview = computed<boolean>({
|
||||
get: () => store.editor.maskPreview,
|
||||
set: (v) => { store.editor.maskPreview = v },
|
||||
})
|
||||
// Dashed horizontal + vertical lines through the center of the
|
||||
// effective canvas — a composition guide the user can toggle on/off
|
||||
// from the HUD. Not persisted; local to this editor session.
|
||||
const centerCrosshair = ref(false)
|
||||
// from the HUD.
|
||||
const centerCrosshair = computed<boolean>({
|
||||
get: () => store.editor.centerCrosshair,
|
||||
set: (v) => { store.editor.centerCrosshair = v },
|
||||
})
|
||||
// Stage-preview mode: when false (default) buttons behave like normal
|
||||
// assets — draggable, no hover/click interaction. When true the canvas
|
||||
// turns into a live preview with buttons responding to input.
|
||||
const stagePreview = ref(false)
|
||||
const stagePreview = computed<boolean>({
|
||||
get: () => store.editor.stagePreview,
|
||||
set: (v) => { store.editor.stagePreview = v },
|
||||
})
|
||||
const previewCanvasEl = ref<HTMLCanvasElement | null>(null)
|
||||
const previewImages = ref<Record<string, HTMLImageElement>>({})
|
||||
let didInitialFit = false
|
||||
@@ -3039,6 +3065,17 @@ function zoomBy(factor: number) {
|
||||
viewY.value = sy - logY * newZoom
|
||||
}
|
||||
|
||||
// Project-loaded zoom/pan? Treat a non-default editor state as an
|
||||
// explicit user choice and skip the first auto-fit so the workbench
|
||||
// restores exactly where the user left off.
|
||||
if (
|
||||
store.editor.canvasZoom !== 1 ||
|
||||
store.editor.canvasViewX !== 0 ||
|
||||
store.editor.canvasViewY !== 0
|
||||
) {
|
||||
didInitialFit = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!container.value) return
|
||||
ro = new ResizeObserver((entries) => {
|
||||
|
||||
Reference in new issue
Block a user