From 5af0cdb3d4f7b9853063dbb3d939803013466c66 Mon Sep 17 00:00:00 2001 From: th Date: Fri, 24 Apr 2026 14:55:22 +0200 Subject: [PATCH] 0.18.1: editor-hide cascades to groups + rename for layers & clip tracks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track groups get the same editor-hide affordance as layer and clip tracks: new eye button on the group header, setGroupEditorHidden action (clears selection pointing inside the group), and a cascade through the Konva stackItems + render.ts so every child track in a hidden group vanishes in the editor. Track renaming via right-click context menu now covers layers and clip tracks too — setLayerName / setClipTrackName actions, new i18n strings, and end-to-end UI tests driving the menu → promptDialog → rename flow. Co-Authored-By: Claude Opus 4.7 (1M context) --- package.json | 2 +- src/components/CanvasStage.vue | 9 ++ src/components/Timeline.vue | 53 +++++++ src/devtools/tests.ts | 260 +++++++++++++++++++++++++++++++++ src/i18n/messages.ts | 10 ++ src/lib/render.ts | 4 + src/stores/scene.ts | 39 +++++ src/types/scene.ts | 5 + src/version.ts | 2 +- 9 files changed, 382 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d0b7ff3..4f84adc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ruwio", "private": true, - "version": "0.18.0", + "version": "0.18.1", "type": "module", "scripts": { "dev": "vite", diff --git a/src/components/CanvasStage.vue b/src/components/CanvasStage.vue index 81eb633..d9bce85 100644 --- a/src/components/CanvasStage.vue +++ b/src/components/CanvasStage.vue @@ -821,11 +821,20 @@ const stackItems = computed(() => { instancesByTrack.set(ci.clipTrackId, arr) } + // Tracks whose parent TrackGroup is editor-hidden — same cascade + // as the Timeline's lockedGroupChildIds logic, just for the eye + // toggle. A child with its own editorHidden flag unset still + // disappears if its group carries one. + const hiddenGroupChildIds = new Set() + for (const g of store.scene.groups ?? []) { + if (g.editorHidden) for (const cid of g.childIds) hiddenGroupChildIds.add(cid) + } const expanded = expandedTrackOrder(store.scene) const order = expanded.length ? expanded : store.scene.layers.map((l) => l.id) // iterate bottom → top: reverse the array for (let i = order.length - 1; i >= 0; i--) { const id = order[i] + if (hiddenGroupChildIds.has(id)) continue const layer = layerById.get(id) if (layer) { // Editor-only hide: skip on the Konva stage while the scene diff --git a/src/components/Timeline.vue b/src/components/Timeline.vue index d9b2f9a..8820381 100644 --- a/src/components/Timeline.vue +++ b/src/components/Timeline.vue @@ -89,6 +89,7 @@ interface TimelineGroupTrack { collapsed: boolean color: string | null locked: boolean + editorHidden: boolean orderIndex: number childCount: number } @@ -808,6 +809,7 @@ const tracks = computed(() => { collapsed: !!grp.collapsed, color: grp.color ?? null, locked: !!grp.locked, + editorHidden: !!grp.editorHidden, orderIndex, childCount: grp.childIds.length, }) @@ -2741,6 +2743,36 @@ function duplicateTrackFromMenu() { async function renameFromMenu() { if (!trackMenu.value) return + if (trackMenu.value.kind === 'layer') { + const layer = store.activeLayers.find((l) => l.id === trackMenu.value!.trackId) + if (!layer) return + const id = trackMenu.value.trackId + const current = layer.name + trackMenu.value = null + const next = await promptDialog({ + title: t('timeline.renameLayerDialog.title'), + defaultValue: current, + confirmLabel: t('timeline.renameLayerDialog.confirm'), + }) + if (next === null) return + store.setLayerName(id, next) + return + } + if (trackMenu.value.kind === 'clip') { + const track = store.scene.clipTracks?.find((t) => t.id === trackMenu.value!.trackId) + if (!track) return + const id = trackMenu.value.trackId + const current = track.name ?? t('timeline.clipTrackName') + trackMenu.value = null + const next = await promptDialog({ + title: t('timeline.renameClipTrackDialog.title'), + defaultValue: current, + confirmLabel: t('timeline.renameClipTrackDialog.confirm'), + }) + if (next === null) return + store.setClipTrackName(id, next) + return + } if (trackMenu.value.kind === 'group') { const group = groupById.value.get(trackMenu.value.trackId) if (!group) return @@ -3778,6 +3810,16 @@ onBeforeUnmount(() => { {{ track.name }} {{ t('timeline.groupChildCount', { n: track.childCount }) }} + +