refactor: fresh properties panel

This commit is contained in:
Maze Winther
2025-07-09 21:03:56 +02:00
parent dd35c91f39
commit c02f276303
6 changed files with 280 additions and 255 deletions

View File

@ -1,6 +1,8 @@
import { create } from "zustand";
import { CanvasSize, CanvasPreset } from "@/types/editor";
type CanvasMode = "preset" | "original" | "custom";
interface EditorState {
// Loading states
isInitializing: boolean;
@ -8,6 +10,7 @@ interface EditorState {
// Canvas/Project settings
canvasSize: CanvasSize;
canvasMode: CanvasMode;
canvasPresets: CanvasPreset[];
// Actions
@ -15,6 +18,7 @@ interface EditorState {
setPanelsReady: (ready: boolean) => void;
initializeApp: () => Promise<void>;
setCanvasSize: (size: CanvasSize) => void;
setCanvasSizeToOriginal: (aspectRatio: number) => void;
setCanvasSizeFromAspectRatio: (aspectRatio: number) => void;
}
@ -65,6 +69,7 @@ export const useEditorStore = create<EditorState>((set, get) => ({
isInitializing: true,
isPanelsReady: false,
canvasSize: { width: 1920, height: 1080 }, // Default 16:9 HD
canvasMode: "preset" as CanvasMode,
canvasPresets: DEFAULT_CANVAS_PRESETS,
// Actions
@ -85,15 +90,16 @@ export const useEditorStore = create<EditorState>((set, get) => ({
},
setCanvasSize: (size) => {
set({ canvasSize: size });
set({ canvasSize: size, canvasMode: "preset" });
},
setCanvasSizeToOriginal: (aspectRatio) => {
const newCanvasSize = findBestCanvasPreset(aspectRatio);
set({ canvasSize: newCanvasSize, canvasMode: "original" });
},
setCanvasSizeFromAspectRatio: (aspectRatio) => {
const newCanvasSize = findBestCanvasPreset(aspectRatio);
console.log(
`Setting canvas size based on aspect ratio ${aspectRatio}:`,
newCanvasSize
);
set({ canvasSize: newCanvasSize });
set({ canvasSize: newCanvasSize, canvasMode: "custom" });
},
}));

View File

@ -117,6 +117,13 @@ interface TimelineStore {
) => void;
separateAudio: (trackId: string, elementId: string) => string | null;
// Replace media for an element
replaceElementMedia: (
trackId: string,
elementId: string,
newFile: File
) => Promise<boolean>;
// Computed values
getTotalDuration: () => number;
@ -677,6 +684,102 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
return audioElementId;
},
// Replace media for an element
replaceElementMedia: async (trackId, elementId, newFile) => {
const { _tracks } = get();
const track = _tracks.find((t) => t.id === trackId);
const element = track?.elements.find((c) => c.id === elementId);
if (!element || element.type !== "media") return false;
try {
const mediaStore = useMediaStore.getState();
const projectStore = useProjectStore.getState();
if (!projectStore.activeProject) return false;
// Import required media processing functions
const {
getFileType,
getImageDimensions,
generateVideoThumbnail,
getMediaDuration,
} = await import("./media-store");
const fileType = getFileType(newFile);
if (!fileType) return false;
// Process the new media file
let mediaData: any = {
name: newFile.name,
type: fileType,
file: newFile,
url: URL.createObjectURL(newFile),
};
// Get media-specific metadata
if (fileType === "image") {
const { width, height } = await getImageDimensions(newFile);
mediaData.width = width;
mediaData.height = height;
} else if (fileType === "video") {
const [duration, { thumbnailUrl, width, height }] = await Promise.all(
[getMediaDuration(newFile), generateVideoThumbnail(newFile)]
);
mediaData.duration = duration;
mediaData.thumbnailUrl = thumbnailUrl;
mediaData.width = width;
mediaData.height = height;
} else if (fileType === "audio") {
mediaData.duration = await getMediaDuration(newFile);
}
// Add new media item to store
await mediaStore.addMediaItem(projectStore.activeProject.id, mediaData);
// Find the newly created media item
const newMediaItem = mediaStore.mediaItems.find(
(item) => item.file === newFile
);
if (!newMediaItem) return false;
get().pushHistory();
// Update the timeline element to reference the new media
updateTracksAndSave(
_tracks.map((track) =>
track.id === trackId
? {
...track,
elements: track.elements.map((c) =>
c.id === elementId
? {
...c,
mediaId: newMediaItem.id,
name: newMediaItem.name,
// Update duration if the new media has a different duration
duration: newMediaItem.duration || c.duration,
}
: c
),
}
: track
)
);
return true;
} catch (error) {
console.log(
JSON.stringify({
error: "Failed to replace element media",
details: error,
})
);
return false;
}
},
getTotalDuration: () => {
const { _tracks } = get();
if (_tracks.length === 0) return 0;