diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-02-10 16:28:21 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-02-10 16:28:21 +0100 |
| commit | fca99d6126c31fbb18ed9f1034cee6f940b040e8 (patch) | |
| tree | 11500ff0fcc4a933650e3e91f1ea00fd315c4d0c /apps/web/src/components/editor/timeline/timeline-toolbar.tsx | |
| parent | 33a8705f0d967891402c61dd3192e6bad24921ef (diff) | |
| download | opencut-fca99d6126c31fbb18ed9f1034cee6f940b040e8.tar.gz | |
refactor
Diffstat (limited to 'apps/web/src/components/editor/timeline/timeline-toolbar.tsx')
| -rw-r--r-- | apps/web/src/components/editor/timeline/timeline-toolbar.tsx | 354 |
1 files changed, 0 insertions, 354 deletions
diff --git a/apps/web/src/components/editor/timeline/timeline-toolbar.tsx b/apps/web/src/components/editor/timeline/timeline-toolbar.tsx deleted file mode 100644 index 6ac6fba5..00000000 --- a/apps/web/src/components/editor/timeline/timeline-toolbar.tsx +++ /dev/null @@ -1,354 +0,0 @@ -import { useEditor } from "@/hooks/use-editor"; -import { - TooltipProvider, - Tooltip, - TooltipTrigger, - TooltipContent, -} from "@/components/ui/tooltip"; -import { Button } from "@/components/ui/button"; -import { SkipBack, SplitSquareHorizontal } from "lucide-react"; -import { - SplitButton, - SplitButtonLeft, - SplitButtonRight, - SplitButtonSeparator, -} from "@/components/ui/split-button"; -import { Slider } from "@/components/ui/slider"; -import { formatTimeCode } from "@/lib/time"; -import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; -import { sliderToZoom, zoomToSlider } from "@/lib/timeline/zoom-utils"; -import { EditableTimecode } from "@/components/editable-timecode"; -import { ScenesView } from "../scenes-view"; -import { type TAction, invokeAction } from "@/lib/actions"; -import { cn } from "@/utils/ui"; -import { useTimelineStore } from "@/stores/timeline-store"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { - Bookmark02Icon, - Delete02Icon, - SnowIcon, - ScissorIcon, - MagnetIcon, - Link04Icon, - SearchAddIcon, - SearchMinusIcon, - PauseIcon, - PlayIcon, - Copy01Icon, - AlignLeftIcon, - AlignRightIcon, - Layers01Icon, -} from "@hugeicons/core-free-icons"; -import { HugeiconsIcon } from "@hugeicons/react"; - -export function TimelineToolbar({ - zoomLevel, - minZoom, - setZoomLevel, -}: { - zoomLevel: number; - minZoom: number; - setZoomLevel: ({ zoom }: { zoom: number }) => void; -}) { - const handleZoom = ({ direction }: { direction: "in" | "out" }) => { - const newZoomLevel = - direction === "in" - ? Math.min( - TIMELINE_CONSTANTS.ZOOM_MAX, - zoomLevel * TIMELINE_CONSTANTS.ZOOM_BUTTON_FACTOR, - ) - : Math.max(minZoom, zoomLevel / TIMELINE_CONSTANTS.ZOOM_BUTTON_FACTOR); - setZoomLevel({ zoom: newZoomLevel }); - }; - - return ( - <ScrollArea className="scrollbar-hidden"> - <div className="flex h-10 items-center justify-between border-b px-2 py-1"> - <ToolbarLeftSection /> - - <SceneSelector /> - - <ToolbarRightSection - zoomLevel={zoomLevel} - minZoom={minZoom} - onZoomChange={(zoom) => setZoomLevel({ zoom })} - onZoom={handleZoom} - /> - </div> - </ScrollArea> - ); -} - -function ToolbarLeftSection() { - const editor = useEditor(); - const currentTime = editor.playback.getCurrentTime(); - const isPlaying = editor.playback.getIsPlaying(); - const currentBookmarked = editor.scenes.isBookmarked({ time: currentTime }); - - const handleAction = ({ - action, - event, - }: { - action: TAction; - event: React.MouseEvent; - }) => { - event.stopPropagation(); - invokeAction(action); - }; - - return ( - <div className="flex items-center gap-1"> - <TooltipProvider delayDuration={500}> - <ToolbarButton - icon={ - isPlaying ? ( - <HugeiconsIcon icon={PauseIcon} /> - ) : ( - <HugeiconsIcon icon={PlayIcon} /> - ) - } - tooltip={isPlaying ? "Pause" : "Play"} - onClick={({ event }) => - handleAction({ action: "toggle-play", event }) - } - /> - - <ToolbarButton - icon={<SkipBack />} - tooltip="Go to start" - onClick={({ event }) => handleAction({ action: "goto-start", event })} - /> - - <div className="bg-border mx-1 h-6 w-px" /> - - <TimeDisplay /> - - <div className="bg-border mx-1 h-6 w-px" /> - - <ToolbarButton - icon={<HugeiconsIcon icon={ScissorIcon} />} - tooltip="Split element" - onClick={({ event }) => handleAction({ action: "split", event })} - /> - - <ToolbarButton - icon={<HugeiconsIcon icon={AlignLeftIcon} />} - tooltip="Split left" - onClick={({ event }) => handleAction({ action: "split-left", event })} - /> - - <ToolbarButton - icon={<HugeiconsIcon icon={AlignRightIcon} />} - tooltip="Split right" - onClick={({ event }) => - handleAction({ action: "split-right", event }) - } - /> - - <ToolbarButton - icon={<SplitSquareHorizontal />} - tooltip="Coming soon" /* separate audio */ - disabled={true} - onClick={({ event: _event }) => {}} - /> - - <ToolbarButton - icon={<HugeiconsIcon icon={Copy01Icon} />} - tooltip="Duplicate element" - onClick={({ event }) => - handleAction({ action: "duplicate-selected", event }) - } - /> - - <ToolbarButton - icon={<HugeiconsIcon icon={SnowIcon} />} - tooltip="Coming soon" /* freeze frame */ - disabled={true} - onClick={({ event: _event }) => {}} - /> - - <ToolbarButton - icon={<HugeiconsIcon icon={Delete02Icon} />} - tooltip="Delete element" - onClick={({ event }) => - handleAction({ action: "delete-selected", event }) - } - /> - - <div className="bg-border mx-1 h-6 w-px" /> - - <Tooltip> - <ToolbarButton - icon={ - <HugeiconsIcon - icon={Bookmark02Icon} - className={currentBookmarked ? "fill-primary text-primary" : ""} - /> - } - tooltip={currentBookmarked ? "Remove bookmark" : "Add bookmark"} - onClick={({ event }) => - handleAction({ action: "toggle-bookmark", event }) - } - /> - </Tooltip> - </TooltipProvider> - </div> - ); -} - -function TimeDisplay() { - const editor = useEditor(); - const currentTime = editor.playback.getCurrentTime(); - const totalDuration = editor.timeline.getTotalDuration(); - const fps = editor.project.getActive().settings.fps; - - return ( - <div className="flex flex-row items-center justify-center px-2"> - <EditableTimecode - time={currentTime} - duration={totalDuration} - format="HH:MM:SS:FF" - fps={fps} - onTimeChange={({ time }) => editor.playback.seek({ time })} - className="text-center" - /> - <div className="text-muted-foreground px-2 font-mono text-xs">/</div> - <div className="text-muted-foreground text-center font-mono text-xs"> - {formatTimeCode({ - timeInSeconds: totalDuration, - format: "HH:MM:SS:FF", - fps, - })} - </div> - </div> - ); -} - -function SceneSelector() { - const editor = useEditor(); - const currentScene = editor.scenes.getActiveScene(); - - return ( - <div> - <SplitButton className="border-foreground/10 border"> - <SplitButtonLeft>{currentScene?.name || "No Scene"}</SplitButtonLeft> - <SplitButtonSeparator /> - <ScenesView> - <SplitButtonRight onClick={() => {}} type="button"> - <HugeiconsIcon icon={Layers01Icon} className="size-4" /> - </SplitButtonRight> - </ScenesView> - </SplitButton> - </div> - ); -} - -function ToolbarRightSection({ - zoomLevel, - minZoom, - onZoomChange, - onZoom, -}: { - zoomLevel: number; - minZoom: number; - onZoomChange: (zoom: number) => void; - onZoom: (options: { direction: "in" | "out" }) => void; -}) { - const { - snappingEnabled, - rippleEditingEnabled, - toggleSnapping, - toggleRippleEditing, - } = useTimelineStore(); - - return ( - <div className="flex items-center gap-1"> - <TooltipProvider delayDuration={500}> - <ToolbarButton - icon={ - <HugeiconsIcon - icon={MagnetIcon} - className={cn(snappingEnabled ? "text-primary" : "")} - /> - } - tooltip="Auto snapping" - onClick={() => toggleSnapping()} - /> - - <ToolbarButton - icon={ - <HugeiconsIcon - icon={Link04Icon} - className={cn( - rippleEditingEnabled ? "text-primary" : "", - "scale-110", - )} - /> - } - tooltip="Ripple editing" - onClick={() => toggleRippleEditing()} - /> - </TooltipProvider> - - <div className="bg-border mx-1 h-6 w-px" /> - - <div className="flex items-center gap-1"> - <Button - variant="text" - size="icon" - type="button" - onClick={() => onZoom({ direction: "out" })} - > - <HugeiconsIcon icon={SearchMinusIcon} /> - </Button> - <Slider - className="w-28" - value={[zoomToSlider({ zoomLevel, minZoom })]} - onValueChange={(values) => - onZoomChange(sliderToZoom({ sliderPosition: values[0], minZoom })) - } - min={0} - max={1} - step={0.005} - /> - <Button - variant="text" - size="icon" - type="button" - onClick={() => onZoom({ direction: "in" })} - > - <HugeiconsIcon icon={SearchAddIcon} /> - </Button> - </div> - </div> - ); -} - -function ToolbarButton({ - icon, - tooltip, - onClick, - disabled, -}: { - icon: React.ReactNode; - tooltip: string; - onClick: ({ event }: { event: React.MouseEvent }) => void; - disabled?: boolean; -}) { - return ( - <Tooltip delayDuration={200}> - <TooltipTrigger asChild> - <Button - variant="text" - size="icon" - type="button" - onClick={(event) => onClick({ event })} - className={disabled ? "cursor-not-allowed opacity-50" : ""} - > - {icon} - </Button> - </TooltipTrigger> - <TooltipContent>{tooltip}</TooltipContent> - </Tooltip> - ); -} |
