feat: implement document actions for managing artboards, zoom, and history; update UI components to utilize new actions

This commit is contained in:
syntaxbullet
2026-07-11 11:26:27 +02:00
parent 1236b6dd2f
commit 53cf25c132
12 changed files with 168 additions and 59 deletions

View File

@@ -15,7 +15,6 @@ import { resolveTransformTargetBounds, selectedTransformTarget } from "@editor/t
import type { AppState } from "@editor/state";
import { handleCommandPaletteKey, handleDeleteSelectionKey, handleHistoryKey, handleOperationKey, handleToolKey, keybindEventFromKeyboardEvent } from "@input/index";
import { shallowEqual, useAppState } from "./useAppState";
import { downloadArtboardPng } from "@operations/export/downloadArtboard";
import { useImageImport } from "./useImageImport";
import { useViewportActivityIsland } from "./useViewportActivityIsland";
import { useProjectLifecycle } from "./useProjectLifecycle";
@@ -42,8 +41,8 @@ export function App({ app }: AppProps) {
}, [app.workflows.generation, generateOpen]);
const openGenerate = useCallback(() => {
app.store.dispatch(commandIds.workspaceSetPanel, { panel: "generate" });
}, [app.store]);
app.actions.document.openGenerate();
}, [app.actions.document]);
const closeGenerate = useCallback(() => {
app.store.dispatch(commandIds.workspaceSetPanel, { panel: "none" });
@@ -90,7 +89,7 @@ export function App({ app }: AppProps) {
if (editableTarget) return;
const historyConsumed = handleHistoryKey({ event: keybindEvent, dispatch: app.store.dispatch });
const historyConsumed = handleHistoryKey({ event: keybindEvent, actions: app.actions.document });
if (historyConsumed) {
event.preventDefault();
return;
@@ -134,7 +133,7 @@ export function App({ app }: AppProps) {
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [app.store, toggleLayers]);
}, [app.actions.document, app.store, toggleLayers]);
const transformBounds = transformTarget ? resolveTransformTargetBounds(document, transformTarget) : undefined;
const brushHint = brushUnavailableHint(document, { selection, tools, maskEdit });
@@ -156,6 +155,7 @@ export function App({ app }: AppProps) {
openGenerate={openGenerate}
openLayers={openLayers}
closeLayers={closeLayers}
documentActions={app.actions.document}
/>
<header className="pointer-events-none absolute inset-x-3 top-3 z-10 flex h-20 items-center justify-end gap-4 rounded-full px-4 text-white backdrop-blur-xl">
<div className="pointer-events-auto flex items-center gap-2">
@@ -174,7 +174,7 @@ export function App({ app }: AppProps) {
<button type="button" className={topBarButtonClass(generateOpen)} aria-pressed={generateOpen} onClick={toggleGenerate}>
<Sparkle size={24} weight={generateOpen ? "fill" : "regular"} />
</button>
<button type="button" className={topBarButtonClass()} disabled={!activeArtboard} onClick={() => activeArtboard && void downloadArtboardPng(activeArtboard, document.assets)}>
<button type="button" className={topBarButtonClass()} disabled={!activeArtboard} onClick={() => void app.actions.document.exportArtboard(activeArtboard?.id)}>
<DownloadSimple size={24} />
</button>
<button type="button" className={topBarButtonClass(layersOpen)} aria-pressed={layersOpen} onClick={toggleLayers}>
@@ -202,6 +202,7 @@ export function App({ app }: AppProps) {
maskEdit={maskEdit}
open={layersOpen}
dispatch={app.store.dispatch}
documentActions={app.actions.document}
/>
<div className="absolute inset-x-0 bottom-4 z-10 flex justify-center">
<BottomControlsIsland
@@ -224,6 +225,7 @@ export function App({ app }: AppProps) {
transformTarget={viewportActivityIsland.visible ? undefined : transformTarget}
dispatch={app.store.dispatch}
generationWorkflow={app.workflows.generation}
documentActions={app.actions.document}
/>
</div>
<div className="absolute bottom-4 left-4 z-10">