feat: full studio build -- light theme, canvas thumbnails, i18n (fa/en)

This commit is contained in:
Soroush.Asadi
2026-05-24 17:37:21 +03:30
parent d962483359
commit c61f587767
295 changed files with 29797 additions and 265 deletions
+74
View File
@@ -0,0 +1,74 @@
"use client";
import { useEffect } from "react";
import { useStudioStore } from "@/lib/studio-store";
function isEditableTarget(target: EventTarget | null): boolean {
if (!(target instanceof HTMLElement)) return false;
const tag = target.tagName;
return tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable;
}
export function useCanvasKeyboard() {
const selectedLayerId = useStudioStore((state) => state.selectedLayerId);
const deleteLayer = useStudioStore((state) => state.deleteLayer);
const copyLayer = useStudioStore((state) => state.copyLayer);
const pasteLayer = useStudioStore((state) => state.pasteLayer);
const undo = useStudioStore((state) => state.undo);
const redo = useStudioStore((state) => state.redo);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (isEditableTarget(event.target)) return;
if (event.key === "Delete" || event.key === "Backspace") {
if (!selectedLayerId) return;
event.preventDefault();
deleteLayer(selectedLayerId);
return;
}
const mod = event.ctrlKey || event.metaKey;
if (!mod) return;
if (event.key === "c" || event.key === "C") {
if (!selectedLayerId) return;
event.preventDefault();
copyLayer(selectedLayerId);
return;
}
if (event.key === "v" || event.key === "V") {
event.preventDefault();
pasteLayer();
return;
}
if (event.key === "z" || event.key === "Z") {
event.preventDefault();
if (event.shiftKey) {
redo();
} else {
undo();
}
return;
}
if (event.key === "y" || event.key === "Y") {
event.preventDefault();
redo();
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [
selectedLayerId,
deleteLayer,
copyLayer,
pasteLayer,
undo,
redo,
]);
}