Address review: playable PLAY/NEXT, visible rename editor, accurate copy

- PLAY and NEXT continue into the following scenes, so they stay
  enabled while any scene in the project has a shot, not only the
  selected one.
- Renaming a shot drops the number and ellipsis so the editor is no
  longer hidden; qa-scene-controls checks a long rename stays visible.
- PLAY, NEXT, EDIT DETAILS and SHARE SCENE tooltips describe what the
  buttons do, translated in every shipped language.
- The primary actions and the file row keep a hover state.
- Docs: the EXPORT rename in DIRECTOR-SHARING and the playback button
  states in CURRENT-STATE are accurate.
- Test the voice "authoring" alias through set_panel_open.
This commit is contained in:
Said Turksever committed 2026-10-29 18:39:53 +00:00
1 parent 8de75b172a
commit 5a80facf8d
14 files changed
+129 -34

No files matched your search

+5 -1
View File
@@ -220,7 +220,11 @@ export class SceneControls {
const shots = scene?.shots ?? [];
presentSceneButtons(this.elements, running, state.hasRun, {
hasScene: !!scene,
shotCount: shots.length,
// PLAY and NEXT run on into the following scenes.
playableShots: (state.scenes ?? []).reduce(
(total, item) => total + (item.shots?.length ?? 0),
0,
),
hasSelectedShot: shots.some((shot) => shot.id === state.selectedShotId),
});
this.elements.panel?.classList.toggle('has-shots', shots.length > 0);
+9
View File
@@ -184,7 +184,16 @@ test('Authoring disables idle actions that would do nothing', () => {
assert.equal(f.elements.update.disabled, true);
assert.equal(f.elements.start.disabled, false);
// PLAY and NEXT run on into the following scenes, so an empty selected
// scene beside one with shots keeps them available.
f.state.scenes[0].shots = [];
f.state.scenes.push({ id: 'scene-b', title: 'B', shots: [{ id: 'b1' }] });
f.owner.setButtons(false);
assert.equal(f.elements.start.disabled, false);
assert.equal(f.elements.next.disabled, false);
assert.equal(f.elements.update.disabled, true);
f.state.scenes.pop();
f.owner.setButtons(false);
assert.equal(f.elements.start.disabled, true);
assert.equal(f.elements.next.disabled, true);
+8 -6
View File
@@ -173,22 +173,24 @@ export function presentSceneSelection(element, selectedShotId) {
}
/**
* Everything but STOP is off while a scene plays. Otherwise a button is off
* when it would do nothing: DELETE and CAPTURE SHOT without a scene, UPDATE
* SHOT without a selected shot, PLAY and NEXT on a scene with no shots.
* While a scene plays, the authoring and file actions here are off and STOP
* is on. Otherwise a button is off when it would do nothing: DELETE and
* CAPTURE SHOT without a scene, UPDATE SHOT without a selected shot, PLAY and
* NEXT when no scene in the project has a shot (both continue into the
* following scenes).
*/
export function presentSceneButtons(
elements,
running,
hasRun,
{ hasScene = true, shotCount = 1, hasSelectedShot = true } = {},
{ hasScene = true, playableShots = 1, hasSelectedShot = true } = {},
) {
const idleOff = {
delete: !hasScene,
capture: !hasScene,
update: !hasSelectedShot,
start: shotCount === 0,
next: shotCount === 0,
start: playableShots === 0,
next: playableShots === 0,
};
for (const name of [
'start',
+6 -2
View File
@@ -181,8 +181,12 @@ export function mountSceneSharing(
bar.dataset.directorAuthoring = '';
bar.className = 'scene-controls';
const entries = [
[t('EDIT DETAILS'), t('Edit the scene title and description'), edit],
[t('SHARE SCENE'), t('Share this scene as a link or file'), share],
[t('EDIT DETAILS'), t('Edit anchors, data packs and shot details'), edit],
[
t('SHARE SCENE'),
t('Download this scene as JSON or an asset bundle'),
share,
],
];
const removers = [];
for (const [text, title, fn] of entries) {
+18
View File
@@ -223,6 +223,14 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
background: transparent;
}
/* Keep the shared hover on the restyled actions. */
#scene-panel .scene-btn-primary:hover:not(:disabled),
#scene-panel .scene-file-controls .scene-btn:hover:not(:disabled) {
color: var(--accent);
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.scene-shot-hint {
margin: 0 0 8px;
font-size: 11px;
@@ -311,6 +319,16 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
color: var(--text-primary);
}
/* While renaming, the label holds only the editor at full width. */
.scene-shot-label:has(.scene-shot-rename) {
overflow: visible;
white-space: normal;
}
.scene-shot-label:has(.scene-shot-rename)::before {
content: none;
}
/* Shots are numbered 01, 02… in playback order. */
.scene-shot-label::before {
content: counter(scene-shot, decimal-leading-zero);
+2 -2
View File
@@ -166,9 +166,9 @@
<p class="scene-shot-hint" data-i18n>Click a shot to select it, double-click to rename.</p>
<p class="scene-step-heading" data-i18n>PREVIEW</p>
<div class="scene-controls">
<button id="scene-start-btn" type="button" class="gev-action-button scene-btn scene-btn-primary" title="Play the whole scene from its first shot" data-i18n-title data-i18n-runtime>PLAY</button>
<button id="scene-start-btn" type="button" class="gev-action-button scene-btn scene-btn-primary" title="Play from this scene through the rest of the project" data-i18n-title data-i18n-runtime>PLAY</button>
<button id="scene-stop-btn" type="button" class="gev-action-button gev-action-button--danger scene-btn scene-btn-danger" title="Stop playback (Esc)" data-i18n data-i18n-title>STOP</button>
<button id="scene-next-btn" type="button" class="gev-action-button scene-btn" title="Play only the shot after the selected one" data-i18n data-i18n-title>NEXT</button>
<button id="scene-next-btn" type="button" class="gev-action-button scene-btn" title="Play the shot after the selected one, moving on to the next scene when needed" data-i18n data-i18n-title>NEXT</button>
</div>
<p class="scene-step-heading" data-i18n>SAVE &amp; SHARE</p>
<div class="scene-controls scene-file-controls">