diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-03-27 00:55:15 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-03-29 15:56:48 +0200 |
| commit | 4d127a038bf768eded68aae3cfa5c1b12241bdac (patch) | |
| tree | 16bbb801caf6770546cff4fdb37b6408ec9ead98 /apps/web/src/components/editor/scenes-view.tsx | |
| parent | 82817cb50cb0487350573d6129130aec705f924b (diff) | |
| download | opencut-4d127a038bf768eded68aae3cfa5c1b12241bdac.tar.gz | |
chore: normalize line endings
Diffstat (limited to 'apps/web/src/components/editor/scenes-view.tsx')
| -rw-r--r-- | apps/web/src/components/editor/scenes-view.tsx | 438 |
1 files changed, 219 insertions, 219 deletions
diff --git a/apps/web/src/components/editor/scenes-view.tsx b/apps/web/src/components/editor/scenes-view.tsx index f7576377..34efeaff 100644 --- a/apps/web/src/components/editor/scenes-view.tsx +++ b/apps/web/src/components/editor/scenes-view.tsx @@ -1,219 +1,219 @@ -"use client"; - -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, - SheetTrigger, -} from "@/components/ui/sheet"; -import { Button } from "@/components/ui/button"; -import { Check, ListCheck, Trash2 } from "lucide-react"; -import { cn } from "@/utils/ui"; -import { useState } from "react"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter, - DialogTrigger, -} from "@/components/ui/dialog"; -import { canDeleteScene, getMainScene } from "@/lib/scenes"; -import { toast } from "sonner"; -import { useEditor } from "@/hooks/use-editor"; - -export function ScenesView({ children }: { children: React.ReactNode }) { - const editor = useEditor(); - const scenes = editor.scenes.getScenes(); - const currentScene = editor.scenes.getActiveScene(); - const [isSelectMode, setIsSelectMode] = useState(false); - const [selectedScenes, setSelectedScenes] = useState<Set<string>>(new Set()); - - const handleSceneSwitch = async (sceneId: string) => { - if (isSelectMode) { - toggleSceneSelection({ sceneId }); - return; - } - - try { - await editor.scenes.switchToScene({ sceneId }); - } catch (error) { - console.error("Failed to switch scene:", error); - } - }; - - const toggleSceneSelection = ({ sceneId }: { sceneId: string }) => { - setSelectedScenes((prev) => { - const newSet = new Set(prev); - if (newSet.has(sceneId)) { - newSet.delete(sceneId); - } else { - newSet.add(sceneId); - } - return newSet; - }); - }; - - const handleSelectMode = () => { - setIsSelectMode(!isSelectMode); - setSelectedScenes(new Set()); - }; - - const handleDeleteSelected = async () => { - for (const sceneId of selectedScenes) { - const scene = scenes.find((scene) => scene.id === sceneId); - if (!scene) { - continue; - } - - const { canDelete, reason } = canDeleteScene({ scene }); - if (!canDelete) { - toast.error(reason || "Failed to delete scene"); - continue; - } - - try { - await editor.scenes.deleteScene({ sceneId }); - } catch (error) { - console.error("Failed to delete scene:", error); - } - } - setSelectedScenes(new Set()); - setIsSelectMode(false); - }; - - const isMainSceneSelected = (() => { - const mainScene = getMainScene({ scenes }); - return Boolean(mainScene?.id && selectedScenes.has(mainScene.id)); - })(); - - return ( - <Sheet> - <SheetTrigger asChild>{children}</SheetTrigger> - <SheetContent> - <SheetHeader> - <SheetTitle> - {isSelectMode ? `Select scenes (${selectedScenes.size})` : "Scenes"} - </SheetTitle> - <SheetDescription> - {isSelectMode - ? "Select scenes to delete" - : "Switch between scenes in your project"} - </SheetDescription> - </SheetHeader> - <div className="flex flex-col gap-4 py-4"> - <div className="flex items-center gap-2"> - <Button - className="rounded-md" - variant={isSelectMode ? "default" : "outline"} - size="sm" - onClick={handleSelectMode} - > - <ListCheck /> - {isSelectMode ? "Cancel" : "Select"} - </Button> - {isSelectMode && ( - <DeleteDialog - count={selectedScenes.size} - onDelete={handleDeleteSelected} - disabled={isMainSceneSelected} - trigger={ - <Button - className="rounded-md" - variant="destructive" - disabled={isMainSceneSelected} - size="sm" - > - <Trash2 /> - Delete ({selectedScenes.size}) - </Button> - } - /> - )} - </div> - {scenes.length === 0 ? ( - <div className="text-muted-foreground text-sm"> - No scenes available - </div> - ) : ( - <div className="space-y-2"> - {scenes.map((scene) => ( - <Button - key={scene.id} - variant="outline" - className={cn( - "w-full justify-between font-normal", - currentScene?.id === scene.id && - !isSelectMode && - "border-primary !text-primary", - isSelectMode && - selectedScenes.has(scene.id) && - "bg-accent border-foreground/30", - )} - onClick={() => handleSceneSwitch(scene.id)} - > - <span>{scene.name}</span> - <div className="flex items-center gap-2"> - {((isSelectMode && selectedScenes.has(scene.id)) || - (!isSelectMode && currentScene?.id === scene.id)) && ( - <Check className="size-4" /> - )} - </div> - </Button> - ))} - </div> - )} - </div> - </SheetContent> - </Sheet> - ); -} - -function DeleteDialog({ - count, - onDelete, - disabled, - trigger, -}: { - count: number; - onDelete: () => void; - disabled?: boolean; - trigger: React.ReactNode; -}) { - const [open, setOpen] = useState(false); - - const handleDelete = () => { - onDelete(); - setOpen(false); - }; - - return ( - <Dialog open={open} onOpenChange={setOpen}> - <DialogTrigger asChild>{trigger}</DialogTrigger> - <DialogContent> - <DialogHeader> - <DialogTitle>Delete Scenes</DialogTitle> - <DialogDescription> - Are you sure you want to delete {count} scene - {count === 1 ? "" : "s"}? This action cannot be undone. - </DialogDescription> - </DialogHeader> - <DialogFooter> - <Button variant="outline" onClick={() => setOpen(false)}> - Cancel - </Button> - <Button - variant="destructive" - onClick={handleDelete} - disabled={disabled} - > - Delete - </Button> - </DialogFooter> - </DialogContent> - </Dialog> - ); -} +"use client";
+
+import {
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from "@/components/ui/sheet";
+import { Button } from "@/components/ui/button";
+import { Check, ListCheck, Trash2 } from "lucide-react";
+import { cn } from "@/utils/ui";
+import { useState } from "react";
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogDescription,
+ DialogFooter,
+ DialogTrigger,
+} from "@/components/ui/dialog";
+import { canDeleteScene, getMainScene } from "@/lib/scenes";
+import { toast } from "sonner";
+import { useEditor } from "@/hooks/use-editor";
+
+export function ScenesView({ children }: { children: React.ReactNode }) {
+ const editor = useEditor();
+ const scenes = editor.scenes.getScenes();
+ const currentScene = editor.scenes.getActiveScene();
+ const [isSelectMode, setIsSelectMode] = useState(false);
+ const [selectedScenes, setSelectedScenes] = useState<Set<string>>(new Set());
+
+ const handleSceneSwitch = async (sceneId: string) => {
+ if (isSelectMode) {
+ toggleSceneSelection({ sceneId });
+ return;
+ }
+
+ try {
+ await editor.scenes.switchToScene({ sceneId });
+ } catch (error) {
+ console.error("Failed to switch scene:", error);
+ }
+ };
+
+ const toggleSceneSelection = ({ sceneId }: { sceneId: string }) => {
+ setSelectedScenes((prev) => {
+ const newSet = new Set(prev);
+ if (newSet.has(sceneId)) {
+ newSet.delete(sceneId);
+ } else {
+ newSet.add(sceneId);
+ }
+ return newSet;
+ });
+ };
+
+ const handleSelectMode = () => {
+ setIsSelectMode(!isSelectMode);
+ setSelectedScenes(new Set());
+ };
+
+ const handleDeleteSelected = async () => {
+ for (const sceneId of selectedScenes) {
+ const scene = scenes.find((scene) => scene.id === sceneId);
+ if (!scene) {
+ continue;
+ }
+
+ const { canDelete, reason } = canDeleteScene({ scene });
+ if (!canDelete) {
+ toast.error(reason || "Failed to delete scene");
+ continue;
+ }
+
+ try {
+ await editor.scenes.deleteScene({ sceneId });
+ } catch (error) {
+ console.error("Failed to delete scene:", error);
+ }
+ }
+ setSelectedScenes(new Set());
+ setIsSelectMode(false);
+ };
+
+ const isMainSceneSelected = (() => {
+ const mainScene = getMainScene({ scenes });
+ return Boolean(mainScene?.id && selectedScenes.has(mainScene.id));
+ })();
+
+ return (
+ <Sheet>
+ <SheetTrigger asChild>{children}</SheetTrigger>
+ <SheetContent>
+ <SheetHeader>
+ <SheetTitle>
+ {isSelectMode ? `Select scenes (${selectedScenes.size})` : "Scenes"}
+ </SheetTitle>
+ <SheetDescription>
+ {isSelectMode
+ ? "Select scenes to delete"
+ : "Switch between scenes in your project"}
+ </SheetDescription>
+ </SheetHeader>
+ <div className="flex flex-col gap-4 py-4">
+ <div className="flex items-center gap-2">
+ <Button
+ className="rounded-md"
+ variant={isSelectMode ? "default" : "outline"}
+ size="sm"
+ onClick={handleSelectMode}
+ >
+ <ListCheck />
+ {isSelectMode ? "Cancel" : "Select"}
+ </Button>
+ {isSelectMode && (
+ <DeleteDialog
+ count={selectedScenes.size}
+ onDelete={handleDeleteSelected}
+ disabled={isMainSceneSelected}
+ trigger={
+ <Button
+ className="rounded-md"
+ variant="destructive"
+ disabled={isMainSceneSelected}
+ size="sm"
+ >
+ <Trash2 />
+ Delete ({selectedScenes.size})
+ </Button>
+ }
+ />
+ )}
+ </div>
+ {scenes.length === 0 ? (
+ <div className="text-muted-foreground text-sm">
+ No scenes available
+ </div>
+ ) : (
+ <div className="space-y-2">
+ {scenes.map((scene) => (
+ <Button
+ key={scene.id}
+ variant="outline"
+ className={cn(
+ "w-full justify-between font-normal",
+ currentScene?.id === scene.id &&
+ !isSelectMode &&
+ "border-primary !text-primary",
+ isSelectMode &&
+ selectedScenes.has(scene.id) &&
+ "bg-accent border-foreground/30",
+ )}
+ onClick={() => handleSceneSwitch(scene.id)}
+ >
+ <span>{scene.name}</span>
+ <div className="flex items-center gap-2">
+ {((isSelectMode && selectedScenes.has(scene.id)) ||
+ (!isSelectMode && currentScene?.id === scene.id)) && (
+ <Check className="size-4" />
+ )}
+ </div>
+ </Button>
+ ))}
+ </div>
+ )}
+ </div>
+ </SheetContent>
+ </Sheet>
+ );
+}
+
+function DeleteDialog({
+ count,
+ onDelete,
+ disabled,
+ trigger,
+}: {
+ count: number;
+ onDelete: () => void;
+ disabled?: boolean;
+ trigger: React.ReactNode;
+}) {
+ const [open, setOpen] = useState(false);
+
+ const handleDelete = () => {
+ onDelete();
+ setOpen(false);
+ };
+
+ return (
+ <Dialog open={open} onOpenChange={setOpen}>
+ <DialogTrigger asChild>{trigger}</DialogTrigger>
+ <DialogContent>
+ <DialogHeader>
+ <DialogTitle>Delete Scenes</DialogTitle>
+ <DialogDescription>
+ Are you sure you want to delete {count} scene
+ {count === 1 ? "" : "s"}? This action cannot be undone.
+ </DialogDescription>
+ </DialogHeader>
+ <DialogFooter>
+ <Button variant="outline" onClick={() => setOpen(false)}>
+ Cancel
+ </Button>
+ <Button
+ variant="destructive"
+ onClick={handleDelete}
+ disabled={disabled}
+ >
+ Delete
+ </Button>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
+ );
+}
|
