Files
Ivan Fontosh 060bbd471a feat(ui): confirm ending a show and surface help
End-session buttons, Escape, and window close share one confirm. Help is a question-mark icon on the control panel and after the version. About opens directly. Scene editor follows the UI language.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-02 08:10:54 +08:00

72 lines
1.9 KiB
TypeScript

import React from 'react';
import type { SceneToken } from '../../shared/types';
import { useEditorI18n } from '../editor/i18n/EditorI18nContext';
import { useTokenImageUrl } from '../shared/tokens/useTokenImageUrl';
import styles from './SceneEditorApp.module.css';
type Props = {
token: SceneToken;
left: number;
top: number;
sizePx: number;
selected: boolean;
onSelect: () => void;
onContextMenu?: (e: React.MouseEvent) => void;
onMovePointerDown: (e: React.PointerEvent) => void;
onResizePointerDown: (e: React.PointerEvent) => void;
onRotatePointerDown: (e: React.PointerEvent) => void;
};
export function SceneTokenMarker({
token,
left,
top,
sizePx,
selected,
onSelect,
onContextMenu,
onMovePointerDown,
onResizePointerDown,
onRotatePointerDown,
}: Props) {
const { t } = useEditorI18n();
const url = useTokenImageUrl(token.tokenId);
return (
<div
className={[styles.sceneToken, selected ? styles.sceneTokenSelected : ''].filter(Boolean).join(' ')}
style={{
left,
top,
width: sizePx,
height: sizePx,
transform: `translate(-50%, -50%) rotate(${String(token.rotationDeg)}deg)`,
}}
title={t('sceneEditor.dragDelete')}
onContextMenu={onContextMenu}
onPointerDown={(e) => {
if (e.button !== 0) return;
onSelect();
onMovePointerDown(e);
}}
>
{url ? <img className={styles.sceneTokenImg} src={url} alt="" draggable={false} /> : null}
{selected ? (
<>
<div className={styles.handle} onPointerDown={onResizePointerDown} />
<button
type="button"
className={styles.rotateHandle}
aria-label={t('sceneEditor.rotate')}
title={t('sceneEditor.rotate')}
onPointerDown={onRotatePointerDown}
>
↻
</button>
</>
) : null}
</div>
);
}