fix: remove thick black border from checkbox for cleaner UI
This commit is contained in:
parent
14475dc9a6
commit
df3b092010
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/OpenCut.iml" filepath="$PROJECT_DIR$/.idea/OpenCut.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -72,6 +72,7 @@
|
|||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/bun": "latest",
|
||||
"@types/node": "^24.1.0",
|
||||
"@types/pg": "^8.15.4",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ function ProjectCard({
|
|||
>
|
||||
{isSelectionMode && (
|
||||
<div className="absolute top-3 left-3 z-10">
|
||||
<div className="w-5 h-5 rounded bg-background/80 backdrop-blur-sm border flex items-center justify-center">
|
||||
<div className="w-4.9 h-4.9 rounded-full bg-background/80 backdrop-blur-sm border flex items-center justify-center">
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
onCheckedChange={(checked) =>
|
||||
|
|
|
|||
|
|
@ -26,136 +26,204 @@ export function useEditorActions() {
|
|||
const { activeProject } = useProjectStore();
|
||||
|
||||
// Playback actions
|
||||
useActionHandler("toggle-play", () => {
|
||||
toggle();
|
||||
}, undefined);
|
||||
|
||||
useActionHandler("stop-playback", () => {
|
||||
if (isPlaying) {
|
||||
useActionHandler(
|
||||
"toggle-play",
|
||||
() => {
|
||||
toggle();
|
||||
}
|
||||
seek(0);
|
||||
}, undefined);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("seek-forward", (args) => {
|
||||
const seconds = args?.seconds ?? 1;
|
||||
seek(Math.min(duration, currentTime + seconds));
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"stop-playback",
|
||||
() => {
|
||||
if (isPlaying) {
|
||||
toggle();
|
||||
}
|
||||
seek(0);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("seek-backward", (args) => {
|
||||
const seconds = args?.seconds ?? 1;
|
||||
seek(Math.max(0, currentTime - seconds));
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"seek-forward",
|
||||
(args) => {
|
||||
const seconds = args?.seconds ?? 1;
|
||||
seek(Math.min(duration, currentTime + seconds));
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("frame-step-forward", () => {
|
||||
const projectFps = activeProject?.fps || 30;
|
||||
seek(Math.min(duration, currentTime + 1 / projectFps));
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"seek-backward",
|
||||
(args) => {
|
||||
const seconds = args?.seconds ?? 1;
|
||||
seek(Math.max(0, currentTime - seconds));
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("frame-step-backward", () => {
|
||||
const projectFps = activeProject?.fps || 30;
|
||||
seek(Math.max(0, currentTime - 1 / projectFps));
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"frame-step-forward",
|
||||
() => {
|
||||
const projectFps = activeProject?.fps || 30;
|
||||
seek(Math.min(duration, currentTime + 1 / projectFps));
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("jump-forward", (args) => {
|
||||
const seconds = args?.seconds ?? 5;
|
||||
seek(Math.min(duration, currentTime + seconds));
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"frame-step-backward",
|
||||
() => {
|
||||
const projectFps = activeProject?.fps || 30;
|
||||
seek(Math.max(0, currentTime - 1 / projectFps));
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("jump-backward", (args) => {
|
||||
const seconds = args?.seconds ?? 5;
|
||||
seek(Math.max(0, currentTime - seconds));
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"jump-forward",
|
||||
(args) => {
|
||||
const seconds = args?.seconds ?? 5;
|
||||
seek(Math.min(duration, currentTime + seconds));
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("goto-start", () => {
|
||||
seek(0);
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"jump-backward",
|
||||
(args) => {
|
||||
const seconds = args?.seconds ?? 5;
|
||||
seek(Math.max(0, currentTime - seconds));
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("goto-end", () => {
|
||||
seek(duration);
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"goto-start",
|
||||
() => {
|
||||
seek(0);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler(
|
||||
"goto-end",
|
||||
() => {
|
||||
seek(duration);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
// Timeline editing actions
|
||||
useActionHandler("split-element", () => {
|
||||
if (selectedElements.length !== 1) {
|
||||
toast.error("Select exactly one element to split");
|
||||
return;
|
||||
}
|
||||
|
||||
const { trackId, elementId } = selectedElements[0];
|
||||
const track = tracks.find((t: any) => t.id === trackId);
|
||||
const element = track?.elements.find((el: any) => el.id === elementId);
|
||||
|
||||
if (element) {
|
||||
const effectiveStart = element.startTime;
|
||||
const effectiveEnd =
|
||||
element.startTime +
|
||||
(element.duration - element.trimStart - element.trimEnd);
|
||||
|
||||
if (currentTime > effectiveStart && currentTime < effectiveEnd) {
|
||||
splitElement(trackId, elementId, currentTime);
|
||||
} else {
|
||||
toast.error("Playhead must be within selected element");
|
||||
useActionHandler(
|
||||
"split-element",
|
||||
() => {
|
||||
if (selectedElements.length !== 1) {
|
||||
toast.error("Select exactly one element to split");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, undefined);
|
||||
|
||||
useActionHandler("delete-selected", () => {
|
||||
if (selectedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
selectedElements.forEach(
|
||||
({ trackId, elementId }: { trackId: string; elementId: string }) => {
|
||||
removeElementFromTrack(trackId, elementId);
|
||||
const { trackId, elementId } = selectedElements[0];
|
||||
const track = tracks.find((t: any) => t.id === trackId);
|
||||
const element = track?.elements.find((el: any) => el.id === elementId);
|
||||
|
||||
if (element) {
|
||||
const effectiveStart = element.startTime;
|
||||
const effectiveEnd =
|
||||
element.startTime +
|
||||
(element.duration - element.trimStart - element.trimEnd);
|
||||
|
||||
if (currentTime > effectiveStart && currentTime < effectiveEnd) {
|
||||
splitElement(trackId, elementId, currentTime);
|
||||
} else {
|
||||
toast.error("Playhead must be within selected element");
|
||||
}
|
||||
}
|
||||
);
|
||||
clearSelectedElements();
|
||||
}, undefined);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("select-all", () => {
|
||||
const allElements = tracks.flatMap((track: any) =>
|
||||
track.elements.map((element: any) => ({
|
||||
trackId: track.id,
|
||||
elementId: element.id,
|
||||
}))
|
||||
);
|
||||
setSelectedElements(allElements);
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"delete-selected",
|
||||
() => {
|
||||
if (selectedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
selectedElements.forEach(
|
||||
({ trackId, elementId }: { trackId: string; elementId: string }) => {
|
||||
removeElementFromTrack(trackId, elementId);
|
||||
}
|
||||
);
|
||||
clearSelectedElements();
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("duplicate-selected", () => {
|
||||
if (selectedElements.length !== 1) {
|
||||
toast.error("Select exactly one element to duplicate");
|
||||
return;
|
||||
}
|
||||
useActionHandler(
|
||||
"select-all",
|
||||
() => {
|
||||
const allElements = tracks.flatMap((track: any) =>
|
||||
track.elements.map((element: any) => ({
|
||||
trackId: track.id,
|
||||
elementId: element.id,
|
||||
}))
|
||||
);
|
||||
setSelectedElements(allElements);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
const { trackId, elementId } = selectedElements[0];
|
||||
const track = tracks.find((t: any) => t.id === trackId);
|
||||
const element = track?.elements.find((el: any) => el.id === elementId);
|
||||
useActionHandler(
|
||||
"duplicate-selected",
|
||||
() => {
|
||||
if (selectedElements.length !== 1) {
|
||||
toast.error("Select exactly one element to duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (element) {
|
||||
const newStartTime =
|
||||
element.startTime +
|
||||
(element.duration - element.trimStart - element.trimEnd) +
|
||||
0.1;
|
||||
const { id, ...elementWithoutId } = element;
|
||||
const { trackId, elementId } = selectedElements[0];
|
||||
const track = tracks.find((t: any) => t.id === trackId);
|
||||
const element = track?.elements.find((el: any) => el.id === elementId);
|
||||
|
||||
addElementToTrack(trackId, {
|
||||
...elementWithoutId,
|
||||
startTime: newStartTime,
|
||||
});
|
||||
}
|
||||
}, undefined);
|
||||
if (element) {
|
||||
const newStartTime =
|
||||
element.startTime +
|
||||
(element.duration - element.trimStart - element.trimEnd) +
|
||||
0.1;
|
||||
const { id, ...elementWithoutId } = element;
|
||||
|
||||
useActionHandler("toggle-snapping", () => {
|
||||
toggleSnapping();
|
||||
}, undefined);
|
||||
addElementToTrack(trackId, {
|
||||
...elementWithoutId,
|
||||
startTime: newStartTime,
|
||||
});
|
||||
}
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler(
|
||||
"toggle-snapping",
|
||||
() => {
|
||||
toggleSnapping();
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
// History actions
|
||||
useActionHandler("undo", () => {
|
||||
undo();
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"undo",
|
||||
() => {
|
||||
undo();
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
useActionHandler("redo", () => {
|
||||
redo();
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"redo",
|
||||
() => {
|
||||
redo();
|
||||
},
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
|
|
|||
18
bun.lock
18
bun.lock
|
|
@ -9,6 +9,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.1.2",
|
||||
"@types/node": "^24.1.0",
|
||||
"husky": "^9.1.7",
|
||||
"turbo": "^2.5.4",
|
||||
"typescript": "5.8.3",
|
||||
|
|
@ -75,6 +76,7 @@
|
|||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/bun": "latest",
|
||||
"@types/node": "^24.1.0",
|
||||
"@types/pg": "^8.15.4",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
|
|
@ -536,7 +538,7 @@
|
|||
|
||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||
|
||||
"@types/node": ["@types/node@22.16.5", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ=="],
|
||||
"@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
|
||||
|
||||
"@types/pg": ["@types/pg@8.15.4", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg=="],
|
||||
|
||||
|
|
@ -1236,7 +1238,7 @@
|
|||
|
||||
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||
|
||||
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
|
||||
|
||||
|
|
@ -1300,10 +1302,16 @@
|
|||
|
||||
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
|
||||
|
||||
"@opencut/auth/@types/node": ["@types/node@22.16.5", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ=="],
|
||||
|
||||
"@types/pg/@types/node": ["@types/node@22.16.5", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ=="],
|
||||
|
||||
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"better-auth/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"bun-types/@types/node": ["@types/node@22.16.5", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ=="],
|
||||
|
||||
"chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
|
@ -1388,6 +1396,12 @@
|
|||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
|
||||
|
||||
"@opencut/auth/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"@types/pg/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"bun-types/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"motion/framer-motion/motion-dom": ["motion-dom@12.23.6", "", { "dependencies": { "motion-utils": "^12.23.6" } }, "sha512-G2w6Nw7ZOVSzcQmsdLc0doMe64O/Sbuc2bVAbgMz6oP/6/pRStKRiVRV4bQfHp5AHYAKEGhEdVHTM+R3FDgi5w=="],
|
||||
|
||||
"motion/framer-motion/motion-utils": ["motion-utils@12.23.6", "", {}, "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ=="],
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
"packageManager": "bun@1.2.18",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.1.2",
|
||||
"@types/node": "^24.1.0",
|
||||
"husky": "^9.1.7",
|
||||
"turbo": "^2.5.4",
|
||||
"typescript": "5.8.3",
|
||||
|
|
|
|||
Loading…
Reference in New Issue