From de7a435a0104ac7fd7ce9fa973ff08f65090be64 Mon Sep 17 00:00:00 2001 From: Gigi Date: Fri, 10 Oct 2025 16:57:56 +0100 Subject: [PATCH] feat: add mobile-responsive CSS with breakpoints and safe areas --- src/index.css | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/src/index.css b/src/index.css index 70e13c59..e6d43659 100644 --- a/src/index.css +++ b/src/index.css @@ -22,12 +22,40 @@ --highlights-collapsed-width: 56px; --main-max-width: 900px; --main-horizontal-padding: 1rem; + + /* Mobile breakpoints */ + --mobile-breakpoint: 768px; + --tablet-breakpoint: 1024px; + + /* Mobile touch target minimum */ + --min-touch-target: 44px; + + /* Safe area insets for notched devices */ + --safe-area-top: env(safe-area-inset-top, 0px); + --safe-area-bottom: env(safe-area-inset-bottom, 0px); + --safe-area-left: env(safe-area-inset-left, 0px); + --safe-area-right: env(safe-area-inset-right, 0px); } body { margin: 0; min-width: 320px; min-height: 100vh; + overscroll-behavior: none; + -webkit-overflow-scrolling: touch; +} + +/* Use dynamic viewport height if supported */ +@supports (height: 100dvh) { + body { + min-height: 100dvh; + } +} + +body.mobile-sidebar-open { + overflow: hidden; + position: fixed; + width: 100%; } #root { @@ -36,6 +64,12 @@ body { padding: 1rem; } +@media (max-width: 768px) { + #root { + padding: 0; + } +} + .app { text-align: center; position: relative; @@ -106,6 +140,47 @@ body { margin-left: auto; } +.mobile-hamburger-btn { + display: none; + position: fixed; + top: 1rem; + left: 1rem; + z-index: 900; + background: #2a2a2a; + border: 1px solid #444; + border-radius: 8px; + color: #ddd; + width: var(--min-touch-target); + height: var(--min-touch-target); + align-items: center; + justify-content: center; + cursor: pointer; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + transition: all 0.2s ease; +} + +.mobile-hamburger-btn:active { + transform: scale(0.95); +} + +.mobile-close-btn { + display: none; +} + +@media (max-width: 768px) { + .mobile-hamburger-btn { + display: flex; + } + + .sidebar-header-bar .toggle-sidebar-btn { + display: none; + } + + .mobile-close-btn { + display: flex; + } +} + .view-mode-controls { display: flex; align-items: center; @@ -301,6 +376,29 @@ body { .icon-button.ghost { background: #2a2a2a; } +/* Mobile touch target improvements */ +@media (max-width: 768px) { + .icon-button { + min-width: var(--min-touch-target); + min-height: var(--min-touch-target); + } +} + +/* Disable hover effects on touch devices */ +@media (pointer: coarse) { + .icon-button:hover { + background: #2a2a2a; + } + + .icon-button.ghost:hover { + background: #2a2a2a; + } + + .icon-button:active { + background: #333; + } +} + .bookmark-events { margin: 1rem 0; } @@ -428,6 +526,13 @@ body { column-gap: 0; height: calc(100vh - 2rem); transition: grid-template-columns 0.3s ease; + position: relative; +} + +@supports (height: 100dvh) { + .three-pane { + height: calc(100dvh - 2rem); + } } .three-pane.sidebar-collapsed { @@ -442,6 +547,22 @@ body { grid-template-columns: var(--sidebar-collapsed-width) 1fr var(--highlights-collapsed-width); } +/* Mobile three-pane layout */ +@media (max-width: 768px) { + .three-pane { + grid-template-columns: 1fr; + grid-template-rows: 1fr; + height: 100vh; + height: 100dvh; + } + + .three-pane.sidebar-collapsed, + .three-pane.highlights-collapsed, + .three-pane.sidebar-collapsed.highlights-collapsed { + grid-template-columns: 1fr; + } +} + .pane.sidebar { overflow-y: auto; height: 100%; @@ -471,6 +592,58 @@ body { height: 100%; } +/* Mobile pane styles */ +@media (max-width: 768px) { + .pane.sidebar { + position: fixed; + top: 0; + left: 0; + width: 85%; + max-width: 320px; + height: 100vh; + height: 100dvh; + background: #1a1a1a; + z-index: 1000; + transform: translateX(-100%); + transition: transform 0.3s ease; + box-shadow: none; + } + + .pane.sidebar.mobile-open { + transform: translateX(0); + box-shadow: 4px 0 12px rgba(0, 0, 0, 0.5); + } + + .pane.main { + grid-column: 1; + grid-row: 1; + padding: 0.5rem; + max-width: 100%; + } + + .pane.highlights { + display: none; + } + + .mobile-sidebar-backdrop { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.6); + z-index: 999; + opacity: 0; + transition: opacity 0.3s ease; + } + + .mobile-sidebar-backdrop.visible { + display: block; + opacity: 1; + } +} + .reader { background: #1a1a1a; border: 1px solid #333; @@ -742,6 +915,20 @@ body { gap: 1.5rem; } +@media (max-width: 768px) { + .bookmarks-grid { + gap: 0.75rem; + } + + .bookmarks-grid.bookmarks-compact { + gap: 0.25rem; + } + + .bookmarks-grid.bookmarks-large { + gap: 1rem; + } +} + .individual-bookmark { background: transparent; padding: 1rem; @@ -2303,6 +2490,27 @@ body { font-size: 0.95rem; } +@media (max-width: 768px) { + .toast { + top: auto; + bottom: calc(1rem + var(--safe-area-bottom)); + right: 1rem; + left: 1rem; + max-width: calc(100% - 2rem); + } + + @keyframes toast-slide-in { + from { + transform: translateY(100px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } + } +} + .toast-success { border-color: #28a745; } @@ -2357,6 +2565,22 @@ body { box-sizing: border-box; } +@media (max-width: 768px) { + .modal-overlay { + padding: 0; + align-items: flex-end; + } + + .modal-content { + max-width: 100%; + max-height: 95vh; + max-height: 95dvh; + border-radius: 16px 16px 0 0; + margin: 0; + padding-bottom: var(--safe-area-bottom); + } +} + .modal-header { display: flex; align-items: center;