mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
- Store: loadImage resets state, applyCrop updates sourceImageSize, setTool clears stale cropState, layer ordering preserved across layers, rotateCanvas/flipCanvas account for object dimensions, trimCanvas implemented, resizeCanvas supports anchor positioning - Canvas: crop overlay interactive, move tool drag events wired, hand tool panning, stage ref effect mount-only, checkerboard tracks pan offset, filter cache clearing - Panels: hslToHex color fix for hue 240-360, adjustments single setAdjustment call, curves draggingIndex after sort, history panel fresh temporal reads, export transparent setting, canvas resize dialog re-sync, hex input respects picker target - Tools: text tool fixed positioning and event cleanup, shape tool deferred addObject, selection mode wired to store, magic wand tolerance controlled, eyedropper coordinate transform - Options: dodge-burn/shape/clone/fill/gradient/pixel-brush use proper store actions instead of raw setState - Added 20+ store actions for tool settings - Updated tests for corrected rotation/flip/trim behavior - Excluded e2e-editor from vitest config
44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
// apps/web/src/components/editor/editor-status-bar.tsx
|
|
import { useEditorStore } from "@/stores/editor-store";
|
|
|
|
export function EditorStatusBar() {
|
|
const cursorPosition = useEditorStore((s) => s.cursorPosition);
|
|
const canvasSize = useEditorStore((s) => s.canvasSize);
|
|
const zoom = useEditorStore((s) => s.zoom);
|
|
const setZoom = useEditorStore((s) => s.setZoom);
|
|
const sourceImageUrl = useEditorStore((s) => s.sourceImageUrl);
|
|
|
|
const zoomPercent = Math.round(zoom * 100);
|
|
|
|
return (
|
|
<div className="flex items-center justify-between h-7 px-3 bg-card border-t border-border text-xs text-muted-foreground">
|
|
<div className="flex items-center gap-3" data-testid="status-cursor">
|
|
{sourceImageUrl && (
|
|
<>
|
|
<span data-testid="status-cursor-x">X: {cursorPosition.x}</span>
|
|
<span data-testid="status-cursor-y">Y: {cursorPosition.y}</span>
|
|
</>
|
|
)}
|
|
</div>
|
|
<div data-testid="status-dimensions">
|
|
{sourceImageUrl && `${canvasSize.width} x ${canvasSize.height} px`}
|
|
</div>
|
|
<div className="flex items-center gap-1" data-testid="status-zoom">
|
|
<input
|
|
type="number"
|
|
value={zoomPercent}
|
|
onChange={(e) => {
|
|
const val = Number.parseFloat(e.target.value);
|
|
if (!Number.isNaN(val) && val > 0) setZoom(val / 100);
|
|
}}
|
|
className="w-14 bg-transparent text-right text-xs border-none outline-none"
|
|
min={0.01}
|
|
max={6400}
|
|
step={0.1}
|
|
/>
|
|
<span>%</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|