0.8.1: dirty-state + Cmd/Ctrl+S, fullscreen plays to OUT, UX fixes
- Unsaved-changes indicator: a small accent dot appears on the save
button whenever the scene has changed since the last save/load.
Save/load/new all mark the project clean on next tick.
- Cmd/Ctrl+S saves the project (reuses the same flow as the button;
prompts for a name on first save). Tooltip now mentions the
shortcut.
- Fullscreen preview plays to the OUT marker (or scene.duration when
no OUT is set) instead of looping at the last keyframe. Dropped
the runtime's effectiveEnd helper; RUNTIME_VERSION 13 → 14.
- "Still frame" keyframes no longer disable easing. A held kf's
easing still drives the segment INTO it from the previous kf, so
you can ease into a pause. Only the first kf disables easing
(nothing precedes it). Dropped `timeline.holdDisabledHint`.
- Settings dialog: hint text 11px → 13px (and dropped italic) so
the inline help is readable; section headings 10px → 13px.
- Canvas stage shadow: `shadowCfg` always emits explicit values plus
a `shadowEnabled` flag instead of returning `{}`. Konva's default
shadowOpacity is 1, so bailing with `{}` could leave stale shadow
attrs on the shape. Preview and editor now gate on the same
condition deterministically.
- Sidebar empty-state copy: "No clips" → "No clips yet" to match
"No buttons yet".
Regression tests: runtime rangeOut fallback is scene.duration (not
last kf); sidebar empty-states both contain "yet"; the
holdDisabledHint key is gone; saveProject tooltips mention the
shortcut.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1e89ea86e0
commit
82ee5c98d0
10 files changed
+133
-48
No files matched your search
@@ -685,6 +685,20 @@ export function registerAllTests(): void {
|
||||
expect(r).toContain('shadowColor')
|
||||
expect(r).toContain('out.blur')
|
||||
})
|
||||
|
||||
test('runtime rangeOut falls back to scene.duration (not last keyframe)', () => {
|
||||
// Regression: the runtime used to fall back to `effectiveEnd(scene)`
|
||||
// — the time of the last keyframe — when scene.outTime was unset.
|
||||
// That made fullscreen preview loop at the last kf, ignoring any
|
||||
// blank tail before the OUT mark and any still-frame-past-end
|
||||
// extension. The fallback is now scene.duration, matching the
|
||||
// editor's `playbackOut` getter.
|
||||
const r = generateRuntimeScript()
|
||||
// The old helper must be gone entirely.
|
||||
expect(r.indexOf('effectiveEnd')).toBe(-1)
|
||||
// And the current fallback must be scene.duration.
|
||||
expect(r).toContain('scene.outTime==null?scene.duration:scene.outTime')
|
||||
})
|
||||
})
|
||||
|
||||
suite('playback — transport', () => {
|
||||
@@ -4350,6 +4364,35 @@ export function registerAllTests(): void {
|
||||
expect(title === 'timeline.renameScriptTrackDialog.title').toBe(false)
|
||||
expect(confirm === 'timeline.renameScriptTrackDialog.confirm').toBe(false)
|
||||
})
|
||||
|
||||
test('sidebar noClips / noButtons empty-states both suggest "yet"', () => {
|
||||
// Regression: the clip library used to read "No clips" while the
|
||||
// button library read "No buttons yet". Minor inconsistency that
|
||||
// the user called out — both should suggest "more coming", not
|
||||
// "there will never be any".
|
||||
expect(i18nT('sidebar.noClips')).toContain('yet')
|
||||
expect(i18nT('sidebar.noButtons')).toContain('yet')
|
||||
})
|
||||
|
||||
test('holdDisabledHint key is gone (held kfs keep easing now)', () => {
|
||||
// Regression: "Still frame — easing disabled" used to appear in
|
||||
// the keyframe context menu and the easing buttons were grayed
|
||||
// out. A held kf's easing still matters for the segment INTO it
|
||||
// from the previous keyframe, so the restriction was wrong.
|
||||
// Pin that the note is no longer emitted.
|
||||
const v = i18nT('timeline.holdDisabledHint')
|
||||
expect(v === 'timeline.holdDisabledHint').toBe(true)
|
||||
})
|
||||
|
||||
test('app.saveProject tooltip mentions the Ctrl/Cmd+S shortcut', () => {
|
||||
// Regression: Cmd/Ctrl+S was added as a keyboard save shortcut
|
||||
// alongside the dirty-state dot. Surface it in the tooltip so
|
||||
// the shortcut is discoverable; assert both the idle and the
|
||||
// unsaved-changes variant stay in sync with the handler.
|
||||
expect(i18nT('app.saveProject')).toContain('Ctrl/Cmd+S')
|
||||
expect(i18nT('app.saveProjectDirty')).toContain('Ctrl/Cmd+S')
|
||||
expect(i18nT('app.saveProjectDirty')).toContain('unsaved')
|
||||
})
|
||||
})
|
||||
|
||||
suite('timeline — scrub-handle obscured logic', () => {
|
||||
|
||||
Reference in new issue
Block a user