1.0.0: delete-group cascade + native-size APNG preview
First stable release. Highlights in this bump: - Group context menu gains a proper danger "Delete group" entry that tears down the group AND every track it contains (layers, clip tracks, script tracks, audio tracks) along with their dependent content. "Ungroup" keeps its old meaning as a separate non-danger item, so the two operations stop being confusable. New removeTrackGroupWithChildren store action clears any selection pointing inside the group before dispatching per-kind removes. - APNG preview page now renders the export at its native pixel size: the .stage + <img> use explicit width/height in pixels instead of a max-960 aspect-ratio box with object-fit: contain. A 4K export looks 4K; the body scrolls if the window is smaller. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
56cecabaae
commit
c2b81b0fb4
7 files changed
+256
-12
No files matched your search
@@ -3023,6 +3023,62 @@ export const useSceneStore = defineStore('scene', {
|
||||
if (idx >= 0) order.splice(idx, 1, ...group.childIds)
|
||||
this.activeScene.groups = this.activeScene.groups.filter((g) => g.id !== id)
|
||||
},
|
||||
/** Delete a group AND every track nested inside it. Dispatches
|
||||
* the per-kind remove action for each child so keyframes, clip
|
||||
* instances, script frames and audio clips are cleaned up along
|
||||
* with their owning track. Selection state (layer + clip-
|
||||
* instance) is cleared up-front since the individual remove
|
||||
* actions don't know about each other. */
|
||||
removeTrackGroupWithChildren(id: string) {
|
||||
const group = this.scene.groups?.find((g) => g.id === id)
|
||||
if (!group) return
|
||||
const childIds = new Set(group.childIds)
|
||||
// Clear any selection that lives inside this group so the
|
||||
// Properties panel + Konva transformer don't point at tracks
|
||||
// we're about to yank.
|
||||
if (this.selectedLayerId && childIds.has(this.selectedLayerId)) {
|
||||
this.selectedLayerId = null
|
||||
this.selectedLayerIds = []
|
||||
} else if (this.selectedLayerIds.length) {
|
||||
this.selectedLayerIds = this.selectedLayerIds.filter((lid) => !childIds.has(lid))
|
||||
if (!this.selectedLayerIds.length) this.selectedLayerId = null
|
||||
}
|
||||
if (this.selectedClipInstanceId) {
|
||||
const inst = this.scene.clipInstances?.find(
|
||||
(ci) => ci.id === this.selectedClipInstanceId,
|
||||
)
|
||||
if (inst && childIds.has(inst.clipTrackId)) {
|
||||
this.selectedClipInstanceId = null
|
||||
}
|
||||
}
|
||||
// Dispatch the right remove action per child. Each call cleans
|
||||
// up its own dependents (layer keyframes come along for free;
|
||||
// clip-tracks drop their instances; script tracks drop their
|
||||
// frames; audio tracks drop their clips).
|
||||
for (const cid of childIds) {
|
||||
if (this.activeLayers.find((l) => l.id === cid)) {
|
||||
this.removeLayer(cid)
|
||||
continue
|
||||
}
|
||||
if (this.scene.clipTracks?.some((t) => t.id === cid)) {
|
||||
this.removeClipTrack(cid)
|
||||
continue
|
||||
}
|
||||
if (this.scene.scriptTracks?.some((t) => t.id === cid)) {
|
||||
this.removeScriptTrack(cid)
|
||||
continue
|
||||
}
|
||||
if (this.activeScene.audioTracks.some((t) => t.id === cid)) {
|
||||
this.removeAudioTrack(cid)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Finally drop the group itself. trackOrder still has the
|
||||
// group id; the per-child removes left it alone because they
|
||||
// only match direct ids, not nested ones.
|
||||
this.activeScene.groups = this.activeScene.groups.filter((g) => g.id !== id)
|
||||
this.activeScene.trackOrder = this.activeScene.trackOrder.filter((tid) => tid !== id)
|
||||
},
|
||||
renameGroup(id: string, name: string) {
|
||||
const group = this.scene.groups?.find((g) => g.id === id)
|
||||
if (!group) return
|
||||
|
||||
Reference in new issue
Block a user