feat(studio): add Tooltip to player and timeline controls

This commit is contained in:
Miguel Ángel
2026-05-21 21:55:13 -04:00
parent 8ffa2eb8c1
commit 2483ab5446
2 changed files with 316 additions and 296 deletions
@@ -4,6 +4,7 @@ import {
} from "../player/components/timelineZoom"; } from "../player/components/timelineZoom";
import { getTimelineToggleTitle } from "../utils/timelineDiscovery"; import { getTimelineToggleTitle } from "../utils/timelineDiscovery";
import { usePlayerStore } from "../player"; import { usePlayerStore } from "../player";
import { Tooltip } from "./ui";
interface TimelineToolbarProps { interface TimelineToolbarProps {
toggleTimelineVisibility: () => void; toggleTimelineVisibility: () => void;
@@ -23,65 +24,71 @@ export function TimelineToolbar({ toggleTimelineVisibility }: TimelineToolbarPro
Timeline Timeline
</div> </div>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<button <Tooltip label="Fit timeline to width">
type="button" <button
onClick={() => setZoomMode("fit")} type="button"
className={`h-7 px-2.5 rounded-md border text-[11px] font-medium transition-colors ${ onClick={() => setZoomMode("fit")}
zoomMode === "fit" className={`h-7 px-2.5 rounded-md border text-[11px] font-medium transition-colors ${
? "border-studio-accent/30 bg-studio-accent/10 text-studio-accent" zoomMode === "fit"
: "border-neutral-800 text-neutral-400 hover:border-neutral-700 hover:text-neutral-200" ? "border-studio-accent/30 bg-studio-accent/10 text-studio-accent"
}`} : "border-neutral-800 text-neutral-400 hover:border-neutral-700 hover:text-neutral-200"
title="Fit timeline to width" }`}
> >
Fit Fit
</button> </button>
<button </Tooltip>
type="button" <Tooltip label="Zoom out">
onClick={() => { <button
setZoomMode("manual"); type="button"
setManualZoomPercent(getNextTimelineZoomPercent("out", zoomMode, manualZoomPercent)); onClick={() => {
}} setZoomMode("manual");
className="h-7 w-7 rounded-md border border-neutral-800 text-neutral-400 transition-colors hover:border-neutral-700 hover:text-neutral-200" setManualZoomPercent(
title="Zoom out" getNextTimelineZoomPercent("out", zoomMode, manualZoomPercent),
> );
- }}
</button> className="h-7 w-7 rounded-md border border-neutral-800 text-neutral-400 transition-colors hover:border-neutral-700 hover:text-neutral-200"
>
-
</button>
</Tooltip>
<div className="min-w-[58px] text-center text-[10px] font-medium tabular-nums text-neutral-500"> <div className="min-w-[58px] text-center text-[10px] font-medium tabular-nums text-neutral-500">
{`${displayedTimelineZoomPercent}%`} {`${displayedTimelineZoomPercent}%`}
</div> </div>
<button <Tooltip label="Zoom in">
type="button" <button
onClick={() => { type="button"
setZoomMode("manual"); onClick={() => {
setManualZoomPercent(getNextTimelineZoomPercent("in", zoomMode, manualZoomPercent)); setZoomMode("manual");
}} setManualZoomPercent(getNextTimelineZoomPercent("in", zoomMode, manualZoomPercent));
className="h-7 w-7 rounded-md border border-neutral-800 text-neutral-400 transition-colors hover:border-neutral-700 hover:text-neutral-200" }}
title="Zoom in" className="h-7 w-7 rounded-md border border-neutral-800 text-neutral-400 transition-colors hover:border-neutral-700 hover:text-neutral-200"
>
+
</button>
<button
type="button"
onClick={toggleTimelineVisibility}
className="ml-1 flex h-7 w-7 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-neutral-900 hover:text-neutral-200"
title={getTimelineToggleTitle(true)}
aria-label="Hide timeline editor"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
> >
<path d="M5 7h14" /> +
<path d="m8 11 4 4 4-4" /> </button>
</svg> </Tooltip>
</button> <Tooltip label={getTimelineToggleTitle(true)}>
<button
type="button"
onClick={toggleTimelineVisibility}
className="ml-1 flex h-7 w-7 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-neutral-900 hover:text-neutral-200"
aria-label="Hide timeline editor"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M5 7h14" />
<path d="m8 11 4 4 4-4" />
</svg>
</button>
</Tooltip>
</div> </div>
</div> </div>
</div> </div>
@@ -4,6 +4,7 @@ import { formatFrameTime, frameToSeconds, stepFrameTime, formatTime } from "../l
import { shouldMutePreviewAudio } from "../lib/timelineIframeHelpers"; import { shouldMutePreviewAudio } from "../lib/timelineIframeHelpers";
import { usePlayerStore, liveTime } from "../store/playerStore"; import { usePlayerStore, liveTime } from "../store/playerStore";
import { trackStudioEvent } from "../../utils/studioTelemetry"; import { trackStudioEvent } from "../../utils/studioTelemetry";
import { Tooltip } from "../../components/ui";
const SPEED_OPTIONS = [0.25, 0.5, 1, 1.5, 2] as const; const SPEED_OPTIONS = [0.25, 0.5, 1, 1.5, 2] as const;
const SEEK_EDGE_SNAP_PX = 8; const SEEK_EDGE_SNAP_PX = 8;
@@ -340,47 +341,51 @@ export const PlayerControls = memo(function PlayerControls({
}} }}
> >
{/* Play/Pause button */} {/* Play/Pause button */}
<button <Tooltip label={isPlaying ? "Pause" : "Play"}>
type="button" <button
title={isPlaying ? "Pause" : "Play"} type="button"
aria-label={isPlaying ? "Pause" : "Play"} aria-label={isPlaying ? "Pause" : "Play"}
onClick={() => { onClick={() => {
trackStudioEvent("playback", { action: isPlaying ? "pause" : "play" }); trackStudioEvent("playback", { action: isPlaying ? "pause" : "play" });
onTogglePlay(); onTogglePlay();
}} }}
disabled={controlsDisabled} disabled={controlsDisabled}
className="flex-shrink-0 w-8 h-8 flex items-center justify-center rounded-lg disabled:opacity-30 disabled:pointer-events-none transition-colors" className="flex-shrink-0 w-8 h-8 flex items-center justify-center rounded-lg disabled:opacity-30 disabled:pointer-events-none transition-colors"
style={{ background: "rgba(255,255,255,0.06)" }} style={{ background: "rgba(255,255,255,0.06)" }}
> >
{isPlaying ? ( {isPlaying ? (
<svg width="12" height="12" viewBox="0 0 24 24" fill="#FAFAFA" aria-hidden="true"> <svg width="12" height="12" viewBox="0 0 24 24" fill="#FAFAFA" aria-hidden="true">
<rect x="6" y="4" width="4" height="16" rx="1" /> <rect x="6" y="4" width="4" height="16" rx="1" />
<rect x="14" y="4" width="4" height="16" rx="1" /> <rect x="14" y="4" width="4" height="16" rx="1" />
</svg> </svg>
) : ( ) : (
<svg width="12" height="12" viewBox="0 0 24 24" fill="#FAFAFA" aria-hidden="true"> <svg width="12" height="12" viewBox="0 0 24 24" fill="#FAFAFA" aria-hidden="true">
<polygon points="6,3 20,12 6,21" /> <polygon points="6,3 20,12 6,21" />
</svg> </svg>
)} )}
</button> </button>
</Tooltip>
{/* Time display — click to toggle time/frame mode */} {/* Time display — click to toggle time/frame mode */}
<button <Tooltip
type="button" label={timeDisplayMode === "time" ? "Switch to frame display" : "Switch to time display"}
onClick={() => setTimeDisplayMode((m) => (m === "time" ? "frame" : "time"))}
disabled={disabled}
title={timeDisplayMode === "time" ? "Switch to frame display" : "Switch to time display"}
className="font-mono text-[11px] tabular-nums flex-shrink-0 w-[118px] text-left transition-colors disabled:pointer-events-none hover:opacity-80"
style={{ color: "#A1A1AA", cursor: "pointer" }}
> >
<span ref={timeDisplayRef}>{formatTime(0)}</span> <button
{timeDisplayMode === "time" ? ( type="button"
<> onClick={() => setTimeDisplayMode((m) => (m === "time" ? "frame" : "time"))}
<span style={{ color: "#3F3F46", margin: "0 2px" }}>/</span> disabled={disabled}
<span style={{ color: "#52525B" }}>{formatTime(duration)}</span> className="font-mono text-[11px] tabular-nums flex-shrink-0 w-[118px] text-left transition-colors disabled:pointer-events-none hover:opacity-80"
</> style={{ color: "#A1A1AA", cursor: "pointer" }}
) : null} >
</button> <span ref={timeDisplayRef}>{formatTime(0)}</span>
{timeDisplayMode === "time" ? (
<>
<span style={{ color: "#3F3F46", margin: "0 2px" }}>/</span>
<span style={{ color: "#52525B" }}>{formatTime(duration)}</span>
</>
) : null}
</button>
</Tooltip>
{/* Seek bar — teal progress fill */} {/* Seek bar — teal progress fill */}
<div <div
@@ -470,71 +475,73 @@ export const PlayerControls = memo(function PlayerControls({
</div> </div>
{/* Mute toggle */} {/* Mute toggle */}
<button <Tooltip label={muteButtonLabel}>
type="button" <button
onClick={() => { type="button"
if (!audioAutoMuted) { onClick={() => {
trackStudioEvent("playback", { action: "mute_toggle", muted: !audioMuted }); if (!audioAutoMuted) {
setAudioMuted(!audioMuted); trackStudioEvent("playback", { action: "mute_toggle", muted: !audioMuted });
} setAudioMuted(!audioMuted);
}} }
disabled={controlsDisabled || audioAutoMuted} }}
title={muteButtonLabel} disabled={controlsDisabled || audioAutoMuted}
aria-label={muteButtonLabel} aria-label={muteButtonLabel}
aria-pressed={effectiveAudioMuted} aria-pressed={effectiveAudioMuted}
className={`h-7 w-7 flex-shrink-0 flex items-center justify-center rounded-md border transition-colors disabled:pointer-events-none ${ className={`h-7 w-7 flex-shrink-0 flex items-center justify-center rounded-md border transition-colors disabled:pointer-events-none ${
effectiveAudioMuted effectiveAudioMuted
? "text-studio-accent bg-studio-accent/10 border-studio-accent/30" ? "text-studio-accent bg-studio-accent/10 border-studio-accent/30"
: "border-neutral-700 text-neutral-400 hover:border-neutral-500 hover:bg-neutral-800" : "border-neutral-700 text-neutral-400 hover:border-neutral-500 hover:bg-neutral-800"
} ${audioAutoMuted ? "opacity-70" : ""}`} } ${audioAutoMuted ? "opacity-70" : ""}`}
> >
{effectiveAudioMuted ? ( {effectiveAudioMuted ? (
<svg <svg
width="13" width="13"
height="13" height="13"
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
strokeWidth="2" strokeWidth="2"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
aria-hidden="true" aria-hidden="true"
> >
<path d="M11 5 6 9H3v6h3l5 4V5Z" /> <path d="M11 5 6 9H3v6h3l5 4V5Z" />
<path d="m19 9-6 6" /> <path d="m19 9-6 6" />
<path d="m13 9 6 6" /> <path d="m13 9 6 6" />
</svg> </svg>
) : ( ) : (
<svg <svg
width="13" width="13"
height="13" height="13"
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
strokeWidth="2" strokeWidth="2"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
aria-hidden="true" aria-hidden="true"
> >
<path d="M11 5 6 9H3v6h3l5 4V5Z" /> <path d="M11 5 6 9H3v6h3l5 4V5Z" />
<path d="M15.5 8.5a5 5 0 0 1 0 7" /> <path d="M15.5 8.5a5 5 0 0 1 0 7" />
<path d="M18.5 5.5a9 9 0 0 1 0 13" /> <path d="M18.5 5.5a9 9 0 0 1 0 13" />
</svg> </svg>
)} )}
</button> </button>
</Tooltip>
{/* Speed control */} {/* Speed control */}
<div ref={speedMenuContainerRef} className="relative flex-shrink-0"> <div ref={speedMenuContainerRef} className="relative flex-shrink-0">
<button <Tooltip label="Playback speed">
type="button" <button
onClick={() => setShowSpeedMenu((v) => !v)} type="button"
disabled={disabled} onClick={() => setShowSpeedMenu((v) => !v)}
title="Playback speed" disabled={disabled}
className="w-10 px-2 py-1 rounded-md text-[10px] font-mono tabular-nums transition-colors" className="w-10 px-2 py-1 rounded-md text-[10px] font-mono tabular-nums transition-colors"
style={{ color: "#71717A", background: "rgba(255,255,255,0.04)" }} style={{ color: "#71717A", background: "rgba(255,255,255,0.04)" }}
> >
{playbackRate === 1 ? "1x" : `${playbackRate}x`} {playbackRate === 1 ? "1x" : `${playbackRate}x`}
</button> </button>
</Tooltip>
{showSpeedMenu && ( {showSpeedMenu && (
<div <div
className="absolute bottom-full right-0 mb-1.5 rounded-lg shadow-xl z-50 min-w-[56px] overflow-hidden" className="absolute bottom-full right-0 mb-1.5 rounded-lg shadow-xl z-50 min-w-[56px] overflow-hidden"
@@ -568,123 +575,126 @@ export const PlayerControls = memo(function PlayerControls({
)} )}
</div> </div>
<button <Tooltip label="Loop playback">
type="button"
onClick={() => {
trackStudioEvent("playback", { action: "loop_toggle", enabled: !loopEnabled });
setLoopEnabled(!loopEnabled);
}}
disabled={disabled}
className={`h-7 w-7 flex items-center justify-center rounded-md border transition-colors ${
loopEnabled
? "text-studio-accent bg-studio-accent/10 border-studio-accent/30"
: "border-neutral-700 text-neutral-400 hover:border-neutral-500 hover:bg-neutral-800"
}`}
title="Loop playback"
aria-label={loopEnabled ? "Disable loop playback" : "Enable loop playback"}
aria-pressed={loopEnabled}
>
<svg
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M17 2l4 4-4 4" />
<path d="M3 11V9a4 4 0 0 1 4-4h14" />
<path d="M7 22l-4-4 4-4" />
<path d="M21 13v2a4 4 0 0 1-4 4H3" />
</svg>
</button>
{/* Fullscreen toggle */}
{onToggleFullscreen && (
<button <button
type="button" type="button"
onClick={() => { onClick={() => {
trackStudioEvent("playback", { action: "fullscreen_toggle", active: !isFullscreen }); trackStudioEvent("playback", { action: "loop_toggle", enabled: !loopEnabled });
onToggleFullscreen(); setLoopEnabled(!loopEnabled);
}} }}
className={`h-7 w-7 flex-shrink-0 flex items-center justify-center rounded-md border transition-colors ${ disabled={disabled}
isFullscreen className={`h-7 w-7 flex items-center justify-center rounded-md border transition-colors ${
loopEnabled
? "text-studio-accent bg-studio-accent/10 border-studio-accent/30" ? "text-studio-accent bg-studio-accent/10 border-studio-accent/30"
: "border-neutral-700 text-neutral-400 hover:border-neutral-500 hover:bg-neutral-800" : "border-neutral-700 text-neutral-400 hover:border-neutral-500 hover:bg-neutral-800"
}`} }`}
title={isFullscreen ? "Exit fullscreen (F)" : "Enter fullscreen (F)"} aria-label={loopEnabled ? "Disable loop playback" : "Enable loop playback"}
aria-label={isFullscreen ? "Exit fullscreen" : "Enter fullscreen"} aria-pressed={loopEnabled}
>
{isFullscreen ? (
<svg
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M8 3v3a2 2 0 0 1-2 2H3" />
<path d="M21 8h-3a2 2 0 0 1-2-2V3" />
<path d="M3 16h3a2 2 0 0 1 2 2v3" />
<path d="M16 21v-3a2 2 0 0 1 2-2h3" />
</svg>
) : (
<svg
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M8 3H5a2 2 0 0 0-2 2v3" />
<path d="M21 8V5a2 2 0 0 0-2-2h-3" />
<path d="M3 16v3a2 2 0 0 0 2 2h3" />
<path d="M16 21h3a2 2 0 0 0 2-2v-3" />
</svg>
)}
</button>
)}
{/* Keyboard shortcuts + frame jump + work area — click to open panel */}
<div ref={shortcutsPanelRef} className="relative flex-shrink-0">
<button
type="button"
onClick={() => setShowShortcuts((v) => !v)}
className={`w-6 h-6 flex items-center justify-center rounded border transition-colors ${
showShortcuts
? "border-neutral-600 text-neutral-200 bg-neutral-800"
: "border-neutral-800 text-neutral-600 hover:text-neutral-300 hover:border-neutral-600"
}`}
title="Shortcuts and tools"
aria-label="Shortcuts and tools"
aria-expanded={showShortcuts}
> >
<svg <svg
width="11" width="13"
height="11" height="13"
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
strokeWidth="1.75" strokeWidth="2"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
aria-hidden="true" aria-hidden="true"
> >
<rect x="2" y="4" width="20" height="16" rx="2" /> <path d="M17 2l4 4-4 4" />
<path d="M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M10 12h.01M14 12h.01M18 12h.01M8 16h8" /> <path d="M3 11V9a4 4 0 0 1 4-4h14" />
<path d="M7 22l-4-4 4-4" />
<path d="M21 13v2a4 4 0 0 1-4 4H3" />
</svg> </svg>
</button> </button>
</Tooltip>
{/* Fullscreen toggle */}
{onToggleFullscreen && (
<Tooltip label={isFullscreen ? "Exit fullscreen (F)" : "Enter fullscreen (F)"}>
<button
type="button"
onClick={() => {
trackStudioEvent("playback", { action: "fullscreen_toggle", active: !isFullscreen });
onToggleFullscreen();
}}
className={`h-7 w-7 flex-shrink-0 flex items-center justify-center rounded-md border transition-colors ${
isFullscreen
? "text-studio-accent bg-studio-accent/10 border-studio-accent/30"
: "border-neutral-700 text-neutral-400 hover:border-neutral-500 hover:bg-neutral-800"
}`}
aria-label={isFullscreen ? "Exit fullscreen" : "Enter fullscreen"}
>
{isFullscreen ? (
<svg
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M8 3v3a2 2 0 0 1-2 2H3" />
<path d="M21 8h-3a2 2 0 0 1-2-2V3" />
<path d="M3 16h3a2 2 0 0 1 2 2v3" />
<path d="M16 21v-3a2 2 0 0 1 2-2h3" />
</svg>
) : (
<svg
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M8 3H5a2 2 0 0 0-2 2v3" />
<path d="M21 8V5a2 2 0 0 0-2-2h-3" />
<path d="M3 16v3a2 2 0 0 0 2 2h3" />
<path d="M16 21h3a2 2 0 0 0 2-2v-3" />
</svg>
)}
</button>
</Tooltip>
)}
{/* Keyboard shortcuts + frame jump + work area — click to open panel */}
<div ref={shortcutsPanelRef} className="relative flex-shrink-0">
<Tooltip label="Shortcuts and tools">
<button
type="button"
onClick={() => setShowShortcuts((v) => !v)}
className={`w-6 h-6 flex items-center justify-center rounded border transition-colors ${
showShortcuts
? "border-neutral-600 text-neutral-200 bg-neutral-800"
: "border-neutral-800 text-neutral-600 hover:text-neutral-300 hover:border-neutral-600"
}`}
aria-label="Shortcuts and tools"
aria-expanded={showShortcuts}
>
<svg
width="11"
height="11"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.75"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<rect x="2" y="4" width="20" height="16" rx="2" />
<path d="M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M10 12h.01M14 12h.01M18 12h.01M8 16h8" />
</svg>
</button>
</Tooltip>
{showShortcuts && ( {showShortcuts && (
<div <div
className="absolute bottom-full right-0 mb-2 z-50 rounded-lg shadow-xl min-w-[220px] overflow-y-auto" className="absolute bottom-full right-0 mb-2 z-50 rounded-lg shadow-xl min-w-[220px] overflow-y-auto"
@@ -712,14 +722,15 @@ export const PlayerControls = memo(function PlayerControls({
onKeyDown={handleJumpKeyDown} onKeyDown={handleJumpKeyDown}
onBlur={commitJumpFrame} onBlur={commitJumpFrame}
/> />
<button <Tooltip label="Jump to frame">
type="submit" <button
disabled={disabled} type="submit"
title="Jump to frame" disabled={disabled}
className="h-6 px-2 rounded border border-neutral-700 text-[10px] text-neutral-300 transition-colors hover:border-neutral-500 hover:bg-neutral-800 disabled:opacity-40" className="h-6 px-2 rounded border border-neutral-700 text-[10px] text-neutral-300 transition-colors hover:border-neutral-500 hover:bg-neutral-800 disabled:opacity-40"
> >
Go Go
</button> </button>
</Tooltip>
</form> </form>
</div> </div>
<div style={{ borderTop: "1px solid rgba(255,255,255,0.06)" }} /> <div style={{ borderTop: "1px solid rgba(255,255,255,0.06)" }} />
@@ -745,24 +756,25 @@ export const PlayerControls = memo(function PlayerControls({
<span className="font-mono text-[10px] text-neutral-300"> <span className="font-mono text-[10px] text-neutral-300">
{formatTime(inPoint)} {formatTime(inPoint)}
</span> </span>
<button <Tooltip label="Clear in-point">
type="button" <button
onClick={() => setInPoint(null)} type="button"
className="w-4 h-4 flex items-center justify-center rounded text-neutral-500 hover:text-neutral-200 transition-colors" onClick={() => setInPoint(null)}
title="Clear in-point" className="w-4 h-4 flex items-center justify-center rounded text-neutral-500 hover:text-neutral-200 transition-colors"
aria-label="Clear in-point" aria-label="Clear in-point"
>
<svg
width="8"
height="8"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
> >
<path d="M18 6L6 18M6 6l12 12" /> <svg
</svg> width="8"
</button> height="8"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
>
<path d="M18 6L6 18M6 6l12 12" />
</svg>
</button>
</Tooltip>
</> </>
) : ( ) : (
<span className="text-[10px] text-neutral-600"></span> <span className="text-[10px] text-neutral-600"></span>
@@ -785,24 +797,25 @@ export const PlayerControls = memo(function PlayerControls({
<span className="font-mono text-[10px] text-neutral-300"> <span className="font-mono text-[10px] text-neutral-300">
{formatTime(outPoint)} {formatTime(outPoint)}
</span> </span>
<button <Tooltip label="Clear out-point">
type="button" <button
onClick={() => setOutPoint(null)} type="button"
className="w-4 h-4 flex items-center justify-center rounded text-neutral-500 hover:text-neutral-200 transition-colors" onClick={() => setOutPoint(null)}
title="Clear out-point" className="w-4 h-4 flex items-center justify-center rounded text-neutral-500 hover:text-neutral-200 transition-colors"
aria-label="Clear out-point" aria-label="Clear out-point"
>
<svg
width="8"
height="8"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
> >
<path d="M18 6L6 18M6 6l12 12" /> <svg
</svg> width="8"
</button> height="8"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
>
<path d="M18 6L6 18M6 6l12 12" />
</svg>
</button>
</Tooltip>
</> </>
) : ( ) : (
<span className="text-[10px] text-neutral-600"></span> <span className="text-[10px] text-neutral-600"></span>