feat(control): таймер сессии поверх сцены

Отдельное окно countdown с «Показать игрокам»; на превью — move/resize/rotate, на презентации тот же layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-09-03 16:51:56 +08:00
parent a4d7ab77e7
commit db1168a46c
23 changed files with 1313 additions and 3 deletions
+18
View File
@@ -61,6 +61,7 @@ import { useMaterialsOverlayState } from '../shared/materials/useMaterialsOverla
import { NpcsSceneOverlay } from '../shared/npcs/NpcsSceneOverlay';
import { useNpcsOverlayState } from '../shared/npcs/useNpcsOverlayState';
import { SceneOverlayHost } from '../shared/sceneOverlay/SceneOverlayHost';
import { SessionTimerLayer } from '../shared/sessionTimer/SessionTimerLayer';
import { useSceneViewState } from '../shared/sceneView/useSceneViewState';
import { SceneGridOverlay } from '../shared/grid/SceneGridOverlay';
import { SceneTokensOverlay } from '../shared/tokens/SceneTokensOverlay';
@@ -1842,6 +1843,22 @@ export function ControlApp() {
🎵
</span>
</Button>
<Button
variant="ghost"
iconOnly
title={t('control.timerTool')}
ariaLabel={t('control.timerTool')}
data-testid="control-timer-tool"
onClick={() => {
void api.invoke(ipcChannels.windows.openTimer, {}).catch((err) => {
console.error('[control] openTimer failed', err);
});
}}
>
<span className={styles.iconGlyph} aria-hidden>
⏱
</span>
</Button>
<Button
variant="ghost"
iconOnly
@@ -2980,6 +2997,7 @@ export function ControlApp() {
style={{ zIndex: 48 }}
/>
) : null}
<SessionTimerLayer viewport={previewContentRect} editable />
</div>
</Surface>