summaryrefslogtreecommitdiff
path: root/apps/web/src
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-07-15 14:16:54 +0200
committerMaze Winther <mazewinther@gmail.com>2025-07-15 14:16:54 +0200
commit1fdf2a051529e40cf7a0857d31a83057b878f08d (patch)
treea81961f9efba930bb4d813d4abdc8fd98bf379d5 /apps/web/src
parent5e86ed9efca3e783d6503f153545f3600cad331a (diff)
downloadopencut-1fdf2a051529e40cf7a0857d31a83057b878f08d.tar.gz
cleanup
Diffstat (limited to 'apps/web/src')
-rw-r--r--apps/web/src/components/editor/snap-indicator.tsx65
-rw-r--r--apps/web/src/components/editor/timeline-playhead.tsx14
-rw-r--r--apps/web/src/components/editor/timeline-track.tsx13
-rw-r--r--apps/web/src/components/editor/timeline.tsx412
-rw-r--r--apps/web/src/hooks/use-timeline-snapping.ts32
-rw-r--r--apps/web/src/stores/timeline-store.ts39
6 files changed, 214 insertions, 361 deletions
diff --git a/apps/web/src/components/editor/snap-indicator.tsx b/apps/web/src/components/editor/snap-indicator.tsx
index 398e06c6..83a1f678 100644
--- a/apps/web/src/components/editor/snap-indicator.tsx
+++ b/apps/web/src/components/editor/snap-indicator.tsx
@@ -2,74 +2,53 @@
import { SnapPoint } from "@/hooks/use-timeline-snapping";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
+import type { TimelineTrack } from "@/types/timeline";
interface SnapIndicatorProps {
snapPoint: SnapPoint | null;
zoomLevel: number;
- timelineHeight: number;
isVisible: boolean;
+ tracks: TimelineTrack[];
+ timelineRef: React.RefObject<HTMLDivElement>;
+ trackLabelsRef?: React.RefObject<HTMLDivElement>;
}
export function SnapIndicator({
snapPoint,
zoomLevel,
- timelineHeight,
isVisible,
+ tracks,
+ timelineRef,
+ trackLabelsRef,
}: SnapIndicatorProps) {
if (!isVisible || !snapPoint) {
return null;
}
- const leftPosition =
- snapPoint.time * TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel;
+ const timelineContainerHeight = timelineRef.current?.offsetHeight || 400;
+ const totalHeight = timelineContainerHeight - 8; // 8px padding from edges
- const getIndicatorColor = () => {
- switch (snapPoint.type) {
- case "grid":
- return "bg-blue-400";
- case "element-start":
- case "element-end":
- return "bg-green-400";
- case "playhead":
- return "bg-red-400";
- default:
- return "bg-gray-400";
- }
- };
+ // Get dynamic track labels width, fallback to 0 if no tracks or no ref
+ const trackLabelsWidth =
+ tracks.length > 0 && trackLabelsRef?.current
+ ? trackLabelsRef.current.offsetWidth
+ : 0;
- const getIndicatorLabel = () => {
- switch (snapPoint.type) {
- case "grid":
- return "Grid";
- case "element-start":
- return "Start";
- case "element-end":
- return "End";
- case "playhead":
- return "Playhead";
- default:
- return "";
- }
- };
+ const leftPosition =
+ trackLabelsWidth +
+ snapPoint.time * TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel;
return (
<div
- className="absolute top-0 pointer-events-none z-50"
+ className="absolute pointer-events-none z-[90]"
style={{
left: `${leftPosition}px`,
- height: `${timelineHeight}px`,
+ top: 0,
+ height: `${totalHeight}px`,
+ width: "2px",
}}
>
- {/* Snap line */}
- <div className={`w-0.5 h-full ${getIndicatorColor()} opacity-80`} />
-
- {/* Snap label */}
- <div
- className={`absolute top-0 left-1 px-1 py-0.5 text-xs text-white rounded ${getIndicatorColor()} opacity-90 whitespace-nowrap`}
- style={{ transform: "translateY(-100%)" }}
- >
- {getIndicatorLabel()} ({snapPoint.time.toFixed(1)}s)
- </div>
+ <div className={`w-0.5 h-full bg-primary/40 opacity-80`} />
</div>
);
}
diff --git a/apps/web/src/components/editor/timeline-playhead.tsx b/apps/web/src/components/editor/timeline-playhead.tsx
index ce4ed1ff..78aed3a8 100644
--- a/apps/web/src/components/editor/timeline-playhead.tsx
+++ b/apps/web/src/components/editor/timeline-playhead.tsx
@@ -20,6 +20,7 @@ interface TimelinePlayheadProps {
trackLabelsRef?: React.RefObject<HTMLDivElement>;
timelineRef: React.RefObject<HTMLDivElement>;
playheadRef?: React.RefObject<HTMLDivElement>;
+ isSnappingToPlayhead?: boolean;
}
export function TimelinePlayhead({
@@ -34,6 +35,7 @@ export function TimelinePlayhead({
trackLabelsRef,
timelineRef,
playheadRef: externalPlayheadRef,
+ isSnappingToPlayhead = false,
}: TimelinePlayheadProps) {
const internalPlayheadRef = useRef<HTMLDivElement>(null);
const playheadRef = externalPlayheadRef || internalPlayheadRef;
@@ -73,11 +75,15 @@ export function TimelinePlayhead({
}}
onMouseDown={handlePlayheadMouseDown}
>
- {/* The red line spanning full height */}
- <div className="absolute left-0 w-0.5 bg-foreground cursor-col-resize h-full" />
+ {/* The playhead line spanning full height */}
+ <div
+ className={`absolute left-0 w-0.5 cursor-col-resize h-full ${isSnappingToPlayhead ? "bg-primary" : "bg-foreground"}`}
+ />
- {/* Red dot indicator at the top (in ruler area) */}
- <div className="absolute top-1 left-1/2 transform -translate-x-1/2 w-3 h-3 bg-foreground rounded-full border-2 border-foreground shadow-sm" />
+ {/* Playhead dot indicator at the top (in ruler area) */}
+ <div
+ className={`absolute top-1 left-1/2 transform -translate-x-1/2 w-3 h-3 rounded-full border-2 shadow-sm ${isSnappingToPlayhead ? "bg-primary border-primary" : "bg-foreground border-foreground"}`}
+ />
</div>
);
}
diff --git a/apps/web/src/components/editor/timeline-track.tsx b/apps/web/src/components/editor/timeline-track.tsx
index aeb6f040..2be143eb 100644
--- a/apps/web/src/components/editor/timeline-track.tsx
+++ b/apps/web/src/components/editor/timeline-track.tsx
@@ -49,22 +49,15 @@ export function TimelineTrackContent({
clearSelectedElements,
insertTrackAt,
snappingEnabled,
- gridSnappingEnabled,
- elementSnappingEnabled,
- playheadSnappingEnabled,
- snapThreshold,
- gridInterval,
} = useTimelineStore();
const { currentTime } = usePlaybackStore();
// Initialize snapping hook
const { snapElementPosition } = useTimelineSnapping({
- snapThreshold,
- gridInterval,
- enableGridSnapping: snappingEnabled && gridSnappingEnabled,
- enableElementSnapping: snappingEnabled && elementSnappingEnabled,
- enablePlayheadSnapping: snappingEnabled && playheadSnappingEnabled,
+ snapThreshold: 10,
+ enableElementSnapping: snappingEnabled,
+ enablePlayheadSnapping: snappingEnabled,
});
const timelineRef = useRef<HTMLDivElement>(null);
diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx
index 882af66e..e83b64b9 100644
--- a/apps/web/src/components/editor/timeline.tsx
+++ b/apps/web/src/components/editor/timeline.tsx
@@ -16,9 +16,7 @@ import {
Music,
TypeIcon,
Magnet,
- Grid3X3,
- Move,
- Target,
+ Lock,
} from "lucide-react";
import {
Tooltip,
@@ -40,13 +38,6 @@ import { useTimelineZoom } from "@/hooks/use-timeline-zoom";
import { processMediaFiles } from "@/lib/media-processing";
import { toast } from "sonner";
import { useState, useRef, useEffect, useCallback } from "react";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "../ui/select";
import { TimelineTrackContent } from "./timeline-track";
import {
TimelinePlayhead,
@@ -55,7 +46,7 @@ import {
import { SelectionBox } from "./selection-box";
import { useSelectionBox } from "@/hooks/use-selection-box";
import { SnapIndicator } from "./snap-indicator";
-import { useTimelineSnapping, SnapPoint } from "@/hooks/use-timeline-snapping";
+import { SnapPoint } from "@/hooks/use-timeline-snapping";
import type { DragData, TimelineTrack } from "@/types/timeline";
import {
getTrackHeight,
@@ -85,15 +76,7 @@ export function Timeline() {
undo,
redo,
snappingEnabled,
- gridSnappingEnabled,
- elementSnappingEnabled,
- playheadSnappingEnabled,
- snapThreshold,
- gridInterval,
toggleSnapping,
- toggleGridSnapping,
- toggleElementSnapping,
- togglePlayheadSnapping,
dragState,
} = useTimelineStore();
const { mediaItems, addMediaItem } = useMediaStore();
@@ -135,7 +118,7 @@ export function Timeline() {
const lastVerticalSync = useRef(0);
// Timeline playhead ruler handlers
- const { handleRulerMouseDown, isDraggingRuler } = useTimelinePlayheadRuler({
+ const { handleRulerMouseDown } = useTimelinePlayheadRuler({
currentTime,
duration,
zoomLevel,
@@ -162,15 +145,6 @@ export function Timeline() {
},
});
- // Initialize snapping functionality
- const { snapElementPosition } = useTimelineSnapping({
- snapThreshold,
- gridInterval,
- enableGridSnapping: snappingEnabled && gridSnappingEnabled,
- enableElementSnapping: snappingEnabled && elementSnappingEnabled,
- enablePlayheadSnapping: snappingEnabled && playheadSnappingEnabled,
- });
-
// Calculate snap indicator state
const [currentSnapPoint, setCurrentSnapPoint] = useState<SnapPoint | null>(
null
@@ -724,202 +698,168 @@ export function Timeline() {
onMouseLeave={() => setIsInTimeline(false)}
>
{/* Toolbar */}
- <div className="border-b flex items-center px-2 py-1 gap-1">
- <TooltipProvider delayDuration={500}>
- {/* Play/Pause Button */}
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant="text"
- size="icon"
- onClick={toggle}
- className="mr-2"
- >
- {isPlaying ? (
- <Pause className="h-4 w-4" />
- ) : (
- <Play className="h-4 w-4" />
- )}
- </Button>
- </TooltipTrigger>
- <TooltipContent>
- {isPlaying ? "Pause (Space)" : "Play (Space)"}
- </TooltipContent>
- </Tooltip>
- <div className="w-px h-6 bg-border mx-1" />
- {/* Time Display */}
- <div
- className="text-xs text-muted-foreground font-mono px-2"
- style={{ minWidth: "18ch", textAlign: "center" }}
- >
- {currentTime.toFixed(1)}s / {duration.toFixed(1)}s
- </div>
- {/* Test Clip Button - for debugging */}
- {tracks.length === 0 && (
- <>
- <div className="w-px h-6 bg-border mx-1" />
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant="outline"
- size="sm"
- onClick={() => {
- const trackId = addTrack("media");
- addElementToTrack(trackId, {
- type: "media",
- mediaId: "test",
- name: "Test Clip",
- duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION,
- startTime: 0,
- trimStart: 0,
- trimEnd: 0,
- });
- }}
- className="text-xs"
- >
- Add Test Clip
- </Button>
- </TooltipTrigger>
- <TooltipContent>Add a test clip to try playback</TooltipContent>
- </Tooltip>
- </>
- )}
- <div className="w-px h-6 bg-border mx-1" />
- <Tooltip>
- <TooltipTrigger asChild>
- <Button variant="text" size="icon" onClick={handleSplitSelected}>
- <Scissors className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Split element (Ctrl+S)</TooltipContent>
- </Tooltip>
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant="text"
- size="icon"
- onClick={handleSplitAndKeepLeft}
- >
- <ArrowLeftToLine className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Split and keep left (Ctrl+Q)</TooltipContent>
- </Tooltip>
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant="text"
- size="icon"
- onClick={handleSplitAndKeepRight}
- >
- <ArrowRightToLine className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Split and keep right (Ctrl+W)</TooltipContent>
- </Tooltip>
- <Tooltip>
- <TooltipTrigger asChild>
- <Button variant="text" size="icon" onClick={handleSeparateAudio}>
- <SplitSquareHorizontal className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Separate audio (Ctrl+D)</TooltipContent>
- </Tooltip>
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant="text"
- size="icon"
- onClick={handleDuplicateSelected}
- >
- <Copy className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Duplicate element (Ctrl+D)</TooltipContent>
- </Tooltip>
- <Tooltip>
- <TooltipTrigger asChild>
- <Button variant="text" size="icon" onClick={handleFreezeSelected}>
- <Snowflake className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Freeze frame (F)</TooltipContent>
- </Tooltip>
- <Tooltip>
- <TooltipTrigger asChild>
- <Button variant="text" size="icon" onClick={handleDeleteSelected}>
- <Trash2 className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Delete element (Delete)</TooltipContent>
- </Tooltip>
-
- <div className="w-px h-6 bg-border mx-1" />
-
- {/* Snapping Controls */}
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant={snappingEnabled ? "default" : "text"}
- size="icon"
- onClick={toggleSnapping}
- >
- <Magnet className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Toggle snapping (S)</TooltipContent>
- </Tooltip>
-
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant={
- gridSnappingEnabled && snappingEnabled ? "default" : "text"
- }
- size="icon"
- onClick={toggleGridSnapping}
- disabled={!snappingEnabled}
- >
- <Grid3X3 className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Toggle grid snapping</TooltipContent>
- </Tooltip>
-
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant={
- elementSnappingEnabled && snappingEnabled ? "default" : "text"
- }
- size="icon"
- onClick={toggleElementSnapping}
- disabled={!snappingEnabled}
- >
- <Move className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Toggle element snapping</TooltipContent>
- </Tooltip>
-
- <Tooltip>
- <TooltipTrigger asChild>
- <Button
- variant={
- playheadSnappingEnabled && snappingEnabled
- ? "default"
- : "text"
- }
- size="icon"
- onClick={togglePlayheadSnapping}
- disabled={!snappingEnabled}
- >
- <Target className="h-4 w-4" />
- </Button>
- </TooltipTrigger>
- <TooltipContent>Toggle playhead snapping</TooltipContent>
- </Tooltip>
- </TooltipProvider>
+ <div className="border-b flex items-center justify-between px-2 py-1">
+ <div className="flex items-center gap-1 w-full">
+ <TooltipProvider delayDuration={500}>
+ {/* Play/Pause Button */}
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="text"
+ size="icon"
+ onClick={toggle}
+ className="mr-2"
+ >
+ {isPlaying ? (
+ <Pause className="h-4 w-4" />
+ ) : (
+ <Play className="h-4 w-4" />
+ )}
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>
+ {isPlaying ? "Pause (Space)" : "Play (Space)"}
+ </TooltipContent>
+ </Tooltip>
+ <div className="w-px h-6 bg-border mx-1" />
+ {/* Time Display */}
+ <div
+ className="text-xs text-muted-foreground font-mono px-2"
+ style={{ minWidth: "18ch", textAlign: "center" }}
+ >
+ {currentTime.toFixed(1)}s / {duration.toFixed(1)}s
+ </div>
+ {/* Test Clip Button - for debugging */}
+ {tracks.length === 0 && (
+ <>
+ <div className="w-px h-6 bg-border mx-1" />
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={() => {
+ const trackId = addTrack("media");
+ addElementToTrack(trackId, {
+ type: "media",
+ mediaId: "test",
+ name: "Test Clip",
+ duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION,
+ startTime: 0,
+ trimStart: 0,
+ trimEnd: 0,
+ });
+ }}
+ className="text-xs"
+ >
+ Add Test Clip
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>
+ Add a test clip to try playback
+ </TooltipContent>
+ </Tooltip>
+ </>
+ )}
+ <div className="w-px h-6 bg-border mx-1" />
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="text"
+ size="icon"
+ onClick={handleSplitSelected}
+ >
+ <Scissors className="h-4 w-4" />
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>Split element (Ctrl+S)</TooltipContent>
+ </Tooltip>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="text"
+ size="icon"
+ onClick={handleSplitAndKeepLeft}
+ >
+ <ArrowLeftToLine className="h-4 w-4" />
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>Split and keep left (Ctrl+Q)</TooltipContent>
+ </Tooltip>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="text"
+ size="icon"
+ onClick={handleSplitAndKeepRight}
+ >
+ <ArrowRightToLine className="h-4 w-4" />
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>Split and keep right (Ctrl+W)</TooltipContent>
+ </Tooltip>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="text"
+ size="icon"
+ onClick={handleSeparateAudio}
+ >
+ <SplitSquareHorizontal className="h-4 w-4" />
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>Separate audio (Ctrl+D)</TooltipContent>
+ </Tooltip>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="text"
+ size="icon"
+ onClick={handleDuplicateSelected}
+ >
+ <Copy className="h-4 w-4" />
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>Duplicate element (Ctrl+D)</TooltipContent>
+ </Tooltip>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="text"
+ size="icon"
+ onClick={handleFreezeSelected}
+ >
+ <Snowflake className="h-4 w-4" />
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>Freeze frame (F)</TooltipContent>
+ </Tooltip>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="text"
+ size="icon"
+ onClick={handleDeleteSelected}
+ >
+ <Trash2 className="h-4 w-4" />
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>Delete element (Delete)</TooltipContent>
+ </Tooltip>
+ </TooltipProvider>
+ </div>
+ <div className="flex items-center gap-1">
+ <TooltipProvider delayDuration={500}>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button variant="text" size="icon" onClick={toggleSnapping}>
+ <Lock className="h-4 w-4" />
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>Auto snapping</TooltipContent>
+ </Tooltip>
+ </TooltipProvider>
+ </div>
</div>
{/* Timeline Container */}
@@ -939,6 +879,17 @@ export function Timeline() {
trackLabelsRef={trackLabelsRef}
timelineRef={timelineRef}
playheadRef={playheadRef}
+ isSnappingToPlayhead={
+ showSnapIndicator && currentSnapPoint?.type === "playhead"
+ }
+ />
+ <SnapIndicator
+ snapPoint={currentSnapPoint}
+ zoomLevel={zoomLevel}
+ tracks={tracks}
+ timelineRef={timelineRef}
+ trackLabelsRef={trackLabelsRef}
+ isVisible={showSnapIndicator}
/>
{/* Timeline Header with Ruler */}
<div className="flex bg-panel sticky top-0 z-10">
@@ -1138,17 +1089,6 @@ export function Timeline() {
))}
</>
)}
-
- {/* Snap Indicator */}
- <SnapIndicator
- snapPoint={currentSnapPoint}
- zoomLevel={zoomLevel}
- timelineHeight={Math.max(
- 200,
- Math.min(800, getTotalTracksHeight(tracks))
- )}
- isVisible={showSnapIndicator}
- />
</div>
</ScrollArea>
</div>
diff --git a/apps/web/src/hooks/use-timeline-snapping.ts b/apps/web/src/hooks/use-timeline-snapping.ts
index c7e1f15d..f7f96392 100644
--- a/apps/web/src/hooks/use-timeline-snapping.ts
+++ b/apps/web/src/hooks/use-timeline-snapping.ts
@@ -1,10 +1,10 @@
import { useCallback } from "react";
-import { TimelineElement, TimelineTrack } from "@/types/timeline";
+import { TimelineTrack } from "@/types/timeline";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
export interface SnapPoint {
time: number;
- type: "grid" | "element-start" | "element-end" | "playhead";
+ type: "element-start" | "element-end" | "playhead";
elementId?: string;
trackId?: string;
}
@@ -17,16 +17,12 @@ export interface SnapResult {
export interface UseTimelineSnappingOptions {
snapThreshold?: number; // Distance in pixels to trigger snapping
- gridInterval?: number; // Grid interval in seconds
- enableGridSnapping?: boolean;
enableElementSnapping?: boolean;
enablePlayheadSnapping?: boolean;
}
export function useTimelineSnapping({
snapThreshold = 10,
- gridInterval = 1,
- enableGridSnapping = true,
enableElementSnapping = true,
enablePlayheadSnapping = true,
}: UseTimelineSnappingOptions = {}) {
@@ -40,23 +36,6 @@ export function useTimelineSnapping({
): SnapPoint[] => {
const snapPoints: SnapPoint[] = [];
- // Add grid snap points
- if (enableGridSnapping) {
- const gridStart = Math.floor(currentTime / gridInterval) * gridInterval;
- const gridEnd = Math.ceil(currentTime / gridInterval) * gridInterval;
-
- // Add nearby grid points
- for (let i = -2; i <= 2; i++) {
- const gridTime = gridStart + i * gridInterval;
- if (gridTime >= 0) {
- snapPoints.push({
- time: gridTime,
- type: "grid",
- });
- }
- }
- }
-
// Add element snap points
if (enableElementSnapping) {
tracks.forEach((track) => {
@@ -97,12 +76,7 @@ export function useTimelineSnapping({
return snapPoints;
},
- [
- enableGridSnapping,
- enableElementSnapping,
- enablePlayheadSnapping,
- gridInterval,
- ]
+ [enableElementSnapping, enablePlayheadSnapping]
);
const snapToNearestPoint = useCallback(
diff --git a/apps/web/src/stores/timeline-store.ts b/apps/web/src/stores/timeline-store.ts
index 2734903a..f6b9bfd8 100644
--- a/apps/web/src/stores/timeline-store.ts
+++ b/apps/web/src/stores/timeline-store.ts
@@ -44,19 +44,9 @@ interface TimelineStore {
// Snapping settings
snappingEnabled: boolean;
- gridSnappingEnabled: boolean;
- elementSnappingEnabled: boolean;
- playheadSnappingEnabled: boolean;
- snapThreshold: number;
- gridInterval: number;
// Snapping actions
toggleSnapping: () => void;
- toggleGridSnapping: () => void;
- toggleElementSnapping: () => void;
- togglePlayheadSnapping: () => void;
- setSnapThreshold: (threshold: number) => void;
- setGridInterval: (interval: number) => void;
// Multi-selection
selectedElements: { trackId: string; elementId: string }[];
@@ -221,11 +211,6 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
// Snapping settings defaults
snappingEnabled: true,
- gridSnappingEnabled: true,
- elementSnappingEnabled: true,
- playheadSnappingEnabled: true,
- snapThreshold: 10, // pixels
- gridInterval: 1, // seconds
getSortedTracks: () => {
const { _tracks } = get();
@@ -978,29 +963,5 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
toggleSnapping: () => {
set((state) => ({ snappingEnabled: !state.snappingEnabled }));
},
-
- toggleGridSnapping: () => {
- set((state) => ({ gridSnappingEnabled: !state.gridSnappingEnabled }));
- },
-
- toggleElementSnapping: () => {
- set((state) => ({
- elementSnappingEnabled: !state.elementSnappingEnabled,
- }));
- },
-
- togglePlayheadSnapping: () => {
- set((state) => ({
- playheadSnappingEnabled: !state.playheadSnappingEnabled,
- }));
- },
-
- setSnapThreshold: (threshold) => {
- set({ snapThreshold: Math.max(0, threshold) }); // Ensure non-negative threshold
- },
-
- setGridInterval: (interval) => {
- set({ gridInterval: Math.max(0.1, interval) }); // Ensure minimum interval
- },
};
});