diff --git a/lib/folk-shape.ts b/lib/folk-shape.ts index a54c3b2..f930060 100644 --- a/lib/folk-shape.ts +++ b/lib/folk-shape.ts @@ -310,9 +310,13 @@ export class FolkShape extends FolkElement { handleEvent(event: PointerEvent | KeyboardEvent | TouchEvent) { // Handle touch events for mobile drag support if (event instanceof TouchEvent) { - event.preventDefault(); - const target = event.composedPath()[0] as HTMLElement; + // Allow interactive elements to receive focus on mobile + const tag = target?.tagName?.toLowerCase(); + const isInteractive = tag === "input" || tag === "textarea" || tag === "select" || tag === "button" || target?.isContentEditable; + if (!isInteractive) { + event.preventDefault(); + } const isDragHandle = target?.closest?.(".header, [data-drag]") !== null; const isValidDragTarget = target === this || isDragHandle; diff --git a/website/canvas.html b/website/canvas.html index 5ee7af0..66cd329 100644 --- a/website/canvas.html +++ b/website/canvas.html @@ -245,7 +245,6 @@ background-size: 20px 20px; background-position: -1px -1px; position: relative; - overflow: hidden; touch-action: none; /* Prevent browser gestures, handle manually */ } @@ -253,7 +252,10 @@ position: absolute; top: 0; left: 0; + width: 100%; + height: 100%; transform-origin: 0 0; + overflow: visible; } /* Touch-friendly resize handles */ @@ -334,29 +336,101 @@ outline-offset: 4px !important; } - /* Mobile toolbar: icon-only scrollable strip */ + /* Mobile menu toggle (hidden on desktop) */ + #mobile-menu { + display: none; + } + + #mobile-zoom { + display: none; + } + @media (max-width: 768px) { - #toolbar { - max-width: calc(100vw - 32px); - overflow-x: auto; - scrollbar-width: none; - gap: 4px; - padding: 6px 8px; - touch-action: pan-x; + /* FAB toggle button */ + #mobile-menu { + display: flex; + position: fixed; + bottom: 24px; + right: 16px; + width: 56px; + height: 56px; + border: none; + border-radius: 50%; + background: #14b8a6; + color: white; + font-size: 28px; + align-items: center; + justify-content: center; + z-index: 1002; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); + cursor: pointer; + touch-action: manipulation; } - #toolbar::-webkit-scrollbar { + + /* Always-visible zoom strip */ + #mobile-zoom { + display: flex; + position: fixed; + bottom: 24px; + left: 16px; + gap: 4px; + z-index: 1002; + } + + #mobile-zoom button { + width: 40px; + height: 40px; + border: none; + border-radius: 50%; + background: white; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + font-size: 16px; + cursor: pointer; + touch-action: manipulation; + } + + /* Hide desktop toolbar, show as grid overlay when toggled */ + #toolbar { + display: none; + position: fixed; + top: 72px; + left: 8px; + right: 8px; + transform: none; + flex-wrap: wrap; + max-height: calc(100vh - 160px); + overflow-y: auto; + gap: 6px; + padding: 12px; + border-radius: 16px; + z-index: 1001; + } + + #toolbar.mobile-open { + display: flex; + } + + #toolbar button { + flex: 0 0 calc(33.33% - 4px); + padding: 10px 4px; + font-size: 12px; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + /* Hide zoom/reset from toolbar grid (they're in #mobile-zoom) */ + #toolbar #zoom-in, + #toolbar #zoom-out, + #toolbar #reset-view { display: none; } - #toolbar button { - max-width: 36px; - min-width: 36px; - padding: 8px; - overflow: hidden; - white-space: nowrap; - } + #community-info { display: none; } + #memory-panel { max-width: calc(100vw - 32px); } @@ -369,6 +443,13 @@
+ +