0.18.1: editor-hide cascades to groups + rename for layers & clip tracks

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) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.7 committed 2026-04-24 14:55:22 +02:00
1 parent 6784b76607
commit 5af0cdb3d4
9 files changed
+382 -2

No files matched your search

+9
View File
@@ -821,11 +821,20 @@ const stackItems = computed<StackItem[]>(() => {
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<string>()
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
+53
View File
@@ -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<TimelineTrack[]>(() => {
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(() => {
<PhFolder :size="12" class="name-badge" />
<span class="track-label">{{ track.name }}</span>
<span class="group-count">{{ t('timeline.groupChildCount', { n: track.childCount }) }}</span>
<button
class="eye-btn"
:class="{ hidden: !!track.editorHidden }"
v-tooltip="track.editorHidden ? t('timeline.showInEditor') : t('timeline.hideInEditor')"
@click.stop="store.setGroupEditorHidden(track.groupId, !track.editorHidden)"
@mousedown.stop
@dragstart.prevent.stop
>
<component :is="track.editorHidden ? PhEyeSlash : PhEye" :size="12" />
</button>
<button
class="lock-btn"
:class="{ locked: track.locked }"
@@ -3973,6 +4015,13 @@ onBeforeUnmount(() => {
{{ t('timeline.renameScriptTrack') }}
</button>
</template>
<template v-else-if="trackMenu.kind === 'clip'">
<div class="kf-menu-divider"></div>
<button class="kf-menu-item" @click="renameFromMenu">
<PhPencilSimpleLine :size="12" class="kf-menu-icon" />
{{ t('timeline.renameClipTrack') }}
</button>
</template>
<template v-else-if="trackMenu.kind === 'audio'">
<div class="kf-menu-divider"></div>
<button class="kf-menu-item" @click="renameFromMenu">
@@ -3993,6 +4042,10 @@ onBeforeUnmount(() => {
<template v-else>
<template v-if="trackMenu.kind === 'layer'">
<div class="kf-menu-divider"></div>
<button class="kf-menu-item" @click="renameFromMenu">
<PhPencilSimpleLine :size="12" class="kf-menu-icon" />
{{ t('timeline.renameLayer') }}
</button>
<button
class="kf-menu-item"
:disabled="trackMenu.locked"