From 355d33768a2a5ceb51b12bf093b028973e05a412 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Wed, 25 Mar 2026 16:59:04 -0700 Subject: [PATCH] =?UTF-8?q?fix(mobile):=20responsive=20parity=20=E2=80=94?= =?UTF-8?q?=20touch=20targets,=20iOS=20zoom,=20viewport=20clamping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rNotes: always-visible add button on touch, 36px toolbar buttons with horizontal scroll, URL popover as bottom sheet on mobile, improved comment sidebar bottom panel with drag handle, larger footer buttons, slash menu viewport clamping and mobile-friendly item sizes, reduced code-textarea/image-preview heights. rTasks/rFiles: font-size 16px on inputs to prevent iOS Safari auto-zoom. Shell: .hover-reveal touch utility, 36px min-height on rapp-nav buttons. Co-Authored-By: Claude Opus 4.6 --- .../rfiles/components/folk-file-browser.ts | 1 + modules/rnotes/components/comment-panel.ts | 8 ++++ modules/rnotes/components/folk-notes-app.ts | 46 +++++++++++++++---- modules/rnotes/components/slash-command.ts | 6 ++- modules/rtasks/components/folk-tasks-board.ts | 2 + website/public/shell.css | 7 +++ 6 files changed, 60 insertions(+), 10 deletions(-) diff --git a/modules/rfiles/components/folk-file-browser.ts b/modules/rfiles/components/folk-file-browser.ts index 5adae03..fd05a5f 100644 --- a/modules/rfiles/components/folk-file-browser.ts +++ b/modules/rfiles/components/folk-file-browser.ts @@ -465,6 +465,7 @@ class FolkFileBrowser extends HTMLElement { .upload-row { flex-direction: column; align-items: stretch; } .file-card { padding: 10px; } .card-form-row { flex-direction: column; } + input[type="text"], select, textarea { font-size: 16px; } } diff --git a/modules/rnotes/components/comment-panel.ts b/modules/rnotes/components/comment-panel.ts index 1f34b1b..aaafd60 100644 --- a/modules/rnotes/components/comment-panel.ts +++ b/modules/rnotes/components/comment-panel.ts @@ -253,6 +253,14 @@ class NotesCommentPanel extends HTMLElement { .new-comment-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: 6px; } .first-message-text { word-break: break-word; overflow-wrap: anywhere; } .message-text { word-break: break-word; overflow-wrap: anywhere; } + @media (max-width: 480px) { + .panel { max-height: none; height: 100%; } + .thread-action { padding: 8px 10px; font-size: 12px; } + .reply-btn, .reply-cancel-btn { padding: 8px 16px; } + .reply-input { padding: 8px 10px; font-size: 14px; } + .emoji-pick { padding: 6px 8px; font-size: 18px; } + .new-comment-input { min-height: 44px; max-height: 100px; font-size: 14px; } + }
diff --git a/modules/rnotes/components/folk-notes-app.ts b/modules/rnotes/components/folk-notes-app.ts index d063d08..15c10b5 100644 --- a/modules/rnotes/components/folk-notes-app.ts +++ b/modules/rnotes/components/folk-notes-app.ts @@ -2130,8 +2130,10 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF popover.className = 'url-popover'; const hostRect = (this.shadow.host as HTMLElement).getBoundingClientRect(); - popover.style.left = `${anchorRect.left - hostRect.left}px`; - popover.style.top = `${anchorRect.bottom - hostRect.top + 4}px`; + if (window.innerWidth > 640) { + popover.style.left = `${anchorRect.left - hostRect.left}px`; + popover.style.top = `${anchorRect.bottom - hostRect.top + 4}px`; + } const input = document.createElement('input'); input.type = 'url'; @@ -3118,6 +3120,10 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF } .sbt-notebook-header:hover .sbt-nb-add { opacity: 1; } .sbt-nb-add:hover { color: var(--rs-primary); background: var(--rs-bg-surface-raised); } + @media (pointer: coarse) { + .sbt-nb-add { opacity: 0.6; } + .sbt-nb-add:active { opacity: 1; color: var(--rs-primary); } + } .sbt-notes { padding-left: 20px; } .sbt-note { display: flex; align-items: center; gap: 8px; @@ -3201,11 +3207,16 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF @media (max-width: 480px) { .editor-with-comments { flex-direction: column; } .comment-sidebar.has-comments { - width: 100%; - border-left: none; - border-top: 1px solid var(--rs-border, #e5e7eb); - max-height: 250px; - overflow-y: auto; + width: 100%; border-left: none; + border-top: 2px solid var(--rs-border, #e5e7eb); + max-height: 250px; max-height: 40dvh; + min-height: 120px; overflow-y: auto; + border-radius: 12px 12px 0 0; padding-top: 4px; + } + .comment-sidebar.has-comments::before { + content: ''; display: block; width: 32px; height: 4px; + background: var(--rs-border-strong, #d1d5db); border-radius: 2px; + margin: 0 auto 4px; } } @@ -3521,13 +3532,17 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF .mobile-sidebar-toggle { display: flex !important; } .editor-wrapper .editable-title { padding: 12px 14px 0; } .tiptap-container .tiptap { padding: 14px 16px; } + .sidebar-footer-btn { min-height: 36px; padding: 7px 12px; } } @media (max-width: 480px) { .rapp-nav__btn { padding: 5px 10px; font-size: 12px; } .editable-title { font-size: 18px; } .tiptap-container .tiptap { font-size: 14px; padding: 12px 14px; min-height: 200px; } - .editor-toolbar { padding: 3px 4px; gap: 1px; } - .toolbar-btn { width: 26px; height: 24px; } + .editor-toolbar { padding: 3px 4px; gap: 1px; overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap; } + .toolbar-btn { width: 36px; height: 36px; } + .toolbar-sep { display: none; } + .code-textarea { min-height: 200px; } + .image-preview { max-height: 240px; } .note-actions-bar { flex-wrap: wrap; gap: 6px; } .note-action-btn { padding: 5px 10px; font-size: 11px; } } @@ -3570,6 +3585,13 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF border: 1px solid var(--rs-border); } .url-popover__btn--cancel:hover { color: var(--rs-text-primary); border-color: var(--rs-border-strong); } + @media (max-width: 640px) { + .url-popover { + position: fixed; left: 8px !important; right: 8px !important; + top: auto !important; bottom: max(env(safe-area-inset-bottom), 8px); + min-width: 0; width: auto; border-radius: 12px 12px 0 0; + } + } /* ── Slash Menu ── */ .slash-menu { @@ -3604,6 +3626,12 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF font-size: 10px; color: var(--rs-text-muted); padding: 1px 6px; background: var(--rs-bg-surface-raised); border-radius: 3px; margin-left: auto; } + @media (max-width: 480px) { + .slash-menu { min-width: 200px; max-height: 260px; } + .slash-menu-item { padding: 10px 12px; } + .slash-menu-desc { display: none; } + .slash-menu-hint { display: none; } + } /* ── Code highlighting (lowlight) ── */ .tiptap-container .tiptap .hljs-keyword { color: #c792ea; } diff --git a/modules/rnotes/components/slash-command.ts b/modules/rnotes/components/slash-command.ts index 053383b..774569c 100644 --- a/modules/rnotes/components/slash-command.ts +++ b/modules/rnotes/components/slash-command.ts @@ -191,7 +191,11 @@ export function createSlashCommandPlugin(editor: Editor, shadowRoot: ShadowRoot) const shadowHost = shadowRoot.host as HTMLElement; const hostRect = shadowHost.getBoundingClientRect(); - menuEl.style.left = `${coords.left - hostRect.left}px`; + let left = coords.left - hostRect.left; + const menuWidth = 240; + const maxLeft = window.innerWidth - menuWidth - 8 - hostRect.left; + left = Math.max(4, Math.min(left, maxLeft)); + menuEl.style.left = `${left}px`; menuEl.style.top = `${coords.bottom - hostRect.top + 4}px`; } diff --git a/modules/rtasks/components/folk-tasks-board.ts b/modules/rtasks/components/folk-tasks-board.ts index 799c568..bebbea5 100644 --- a/modules/rtasks/components/folk-tasks-board.ts +++ b/modules/rtasks/components/folk-tasks-board.ts @@ -656,6 +656,8 @@ class FolkTasksBoard extends HTMLElement { .card { padding: 10px; } .card-title { font-size: 13px; } .card-meta { font-size: 10px; } + .create-form input, .create-form select, .create-form textarea { font-size: 16px; } + .create-form-actions button { min-height: 36px; padding: 6px 14px; } } diff --git a/website/public/shell.css b/website/public/shell.css index 08ee348..e54136c 100644 --- a/website/public/shell.css +++ b/website/public/shell.css @@ -443,6 +443,7 @@ body.rstack-sidebar-open #toolbar { body.rstack-sidebar-open rstack-user-dashboard { left: 0; } body.rstack-sidebar-open .rspace-iframe-wrap { left: 0; } body.rstack-sidebar-open #toolbar { left: 12px; } + .rapp-nav__btn, .rapp-nav__back { min-height: 36px; } } @media (max-width: 480px) { @@ -482,3 +483,9 @@ body.rstack-sidebar-open #toolbar { border-radius: 50%; animation: rspace-spin 0.8s linear infinite; } + +/* ── Touch-device utilities ── */ +@media (pointer: coarse) { + .hover-reveal { opacity: 0.5 !important; } + .hover-reveal:active { opacity: 1 !important; } +}