diff --git a/apps/og-generator/app/page.tsx b/apps/og-generator/app/page.tsx index 11a086609ed..b2fd96c2b92 100644 --- a/apps/og-generator/app/page.tsx +++ b/apps/og-generator/app/page.tsx @@ -463,6 +463,51 @@ export default function Page() { return () => document.removeEventListener('pointerdown', onPointerDown) }, [iconPickerOpen]) + // "Z" toggles the zoom tool; Escape cancels it; Alt (while active) flips + // the cursor/click direction from zoom-in to zoom-out, matching + // Illustrator/Photoshop. Ignored while typing in a text field. + useEffect(() => { + const isTyping = (target: EventTarget | null) => { + const el = target as HTMLElement | null + return !!el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable) + } + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Alt') { + setAltHeld(true) + return + } + if (isTyping(e.target)) return + if (e.key === 'Escape') { + setZoomToolActive(false) + } else if ((e.key === 'z' || e.key === 'Z') && !e.metaKey && !e.ctrlKey) { + setZoomToolActive((v) => !v) + } + } + const onKeyUp = (e: KeyboardEvent) => { + if (e.key === 'Alt') setAltHeld(false) + } + // Alt can be released outside the window (e.g. after alt-tabbing) — + // clear the stuck state once focus returns. + const onBlur = () => setAltHeld(false) + window.addEventListener('keydown', onKeyDown) + window.addEventListener('keyup', onKeyUp) + window.addEventListener('blur', onBlur) + return () => { + window.removeEventListener('keydown', onKeyDown) + window.removeEventListener('keyup', onKeyUp) + window.removeEventListener('blur', onBlur) + } + }, []) + + const handleCanvasZoomClick = (e: React.MouseEvent) => { + if (!zoomToolActive) return + if (e.altKey) { + setZoom((z) => Math.max(ZOOM_MIN, z - ZOOM_STEP)) + } else { + setZoom((z) => Math.min(ZOOM_MAX, z + ZOOM_STEP)) + } + } + const uploadSvg = async (file: File) => { setUploading(true) setUploadError(null) @@ -537,6 +582,10 @@ export default function Page() { const ZOOM_MIN = 25 const ZOOM_MAX = 200 const ZOOM_STEP = 25 + // "Z" zoom tool (brief follow-up, Illustrator/Photoshop-style): toggles a + // zoom cursor over the canvas; click to zoom in, Alt+click to zoom out. + const [zoomToolActive, setZoomToolActive] = useState(false) + const [altHeld, setAltHeld] = useState(false) const [copied, setCopied] = useState(null) @@ -606,10 +655,12 @@ export default function Page() { own siblings so they stay anchored regardless of scroll position. */}
{inContext === 'none' ? ( @@ -689,18 +740,40 @@ export default function Page() { - {/* Canvas zoom — bottom-left corner, independent of the centered - toolbar. Scales the image cards themselves (via the row's width - style above), not the surrounding controls. */} + {/* Canvas zoom — bottom-right corner, independent of the centered + toolbar. Same height/padding as that toolbar so the two visually + center-align against the shared bottom-6 offset. Scales the image + cards themselves (via the row's width style above), not the + surrounding controls. */} {inContext === 'none' && ( -
-
+
+
+ +