From e1cacde543338558ceb45006b530d8c4ab4d9497 Mon Sep 17 00:00:00 2001 From: Antigravity Date: Thu, 8 Oct 2026 11:46:44 +0300 Subject: [PATCH] fix(reader): keep word translation popup as compact block on desktop without full-width stretch --- app/static/css/components.css | 11 +++++++ app/static/css/dictionary.css | 50 ---------------------------- app/static/css/reader.css | 58 +++++++++++++++++++++++++++++++-- app/static/index.html | 4 +-- app/static/js/modules/reader.js | 25 +++++++++----- app/static/sw.js | 2 +- 6 files changed, 86 insertions(+), 64 deletions(-) diff --git a/app/static/css/components.css b/app/static/css/components.css index fd7a865..e28d0a0 100644 --- a/app/static/css/components.css +++ b/app/static/css/components.css @@ -40,6 +40,17 @@ } } +@keyframes slideUpSheet { + from { + transform: translateY(100%); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} + .auth-header, .login-header { text-align: center; diff --git a/app/static/css/dictionary.css b/app/static/css/dictionary.css index d276528..c1b4d4e 100644 --- a/app/static/css/dictionary.css +++ b/app/static/css/dictionary.css @@ -757,56 +757,6 @@ } - /* 7. Bottom Sheet for Word Translation Popup on Mobile */ - .reader-word-popup { - position: fixed !important; - top: auto !important; - bottom: calc(58px + env(safe-area-inset-bottom, 0px)) !important; - left: 8px !important; - right: 8px !important; - width: auto !important; - max-width: none !important; - border-radius: 18px !important; - box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.5) !important; - border: 1px solid var(--border-focus) !important; - background-color: var(--bg-surface) !important; - z-index: 10005 !important; - padding: 14px 16px !important; - animation: slideUpSheet 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important; - } - - .reader-settings-panel { - position: fixed !important; - top: auto !important; - bottom: calc(58px + env(safe-area-inset-bottom, 0px)) !important; - left: 8px !important; - right: 8px !important; - width: auto !important; - max-height: calc(85dvh - 60px) !important; - overflow-y: auto !important; - -webkit-overflow-scrolling: touch !important; - border-radius: 20px !important; - box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.55) !important; - border: 1px solid var(--border-focus) !important; - background-color: var(--bg-surface) !important; - color: var(--text-main) !important; - padding: 16px 18px 24px !important; - z-index: 10006 !important; - animation: slideUpSheet 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important; - } - - @keyframes slideUpSheet { - from { - transform: translateY(100%); - opacity: 0; - } - to { - transform: translateY(0); - opacity: 1; - } - } - - /* --- Responsive Mobile Overrides (max-width: 768px) --- */ @media (max-width: 768px) { /* 4. Dictionary & Search */ diff --git a/app/static/css/reader.css b/app/static/css/reader.css index 34f037b..f59b0e2 100644 --- a/app/static/css/reader.css +++ b/app/static/css/reader.css @@ -1549,9 +1549,11 @@ background-color: var(--bg-surface); border: 1px solid var(--border-focus); border-radius: var(--radius-lg); - box-shadow: 0 12px 24px -4px rgba(0, 0, 0, 0.5); - width: 320px; - max-width: calc(100vw - 32px); + box-shadow: 0 12px 28px -4px rgba(0, 0, 0, 0.55); + width: 340px; + max-width: 360px; + max-height: calc(100vh - 40px); + overflow-y: auto; padding: 16px; animation: fadeInScale 0.15s ease-out; } @@ -2061,6 +2063,56 @@ font-size: 17px; line-height: 1.65; } + + /* Mobile Bottom Sheet for Word Translation Popup */ + .reader-word-popup { + position: fixed !important; + top: auto !important; + bottom: calc(58px + env(safe-area-inset-bottom, 0px)) !important; + left: 8px !important; + right: 8px !important; + width: auto !important; + max-width: none !important; + max-height: calc(85dvh - 60px) !important; + overflow-y: auto !important; + border-radius: 18px !important; + box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.5) !important; + border: 1px solid var(--border-focus) !important; + background-color: var(--bg-surface) !important; + z-index: 10005 !important; + padding: 14px 16px !important; + animation: slideUpSheet 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important; + } + + body.zen-mode-active .reader-word-popup { + bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important; + } + + /* Mobile Bottom Sheet for Reader Settings */ + .reader-settings-panel { + position: fixed !important; + top: auto !important; + bottom: calc(58px + env(safe-area-inset-bottom, 0px)) !important; + left: 8px !important; + right: 8px !important; + width: auto !important; + max-width: none !important; + max-height: calc(85dvh - 60px) !important; + overflow-y: auto !important; + -webkit-overflow-scrolling: touch !important; + border-radius: 20px !important; + box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.55) !important; + border: 1px solid var(--border-focus) !important; + background-color: var(--bg-surface) !important; + color: var(--text-main) !important; + padding: 16px 18px 24px !important; + z-index: 10006 !important; + animation: slideUpSheet 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important; + } + + body.zen-mode-active .reader-settings-panel { + bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important; + } } /* ========================================================================== diff --git a/app/static/index.html b/app/static/index.html index f7c964a..51aee9d 100644 --- a/app/static/index.html +++ b/app/static/index.html @@ -5,7 +5,7 @@ Notes — Персональный тренажер и словарь английского языка - + @@ -2049,7 +2049,7 @@ - + diff --git a/app/static/js/modules/reader.js b/app/static/js/modules/reader.js index c3b204a..71a2e35 100644 --- a/app/static/js/modules/reader.js +++ b/app/static/js/modules/reader.js @@ -1309,31 +1309,40 @@ export function positionWordPopup(targetElement) { if (window.innerWidth <= 768) { readerWordPopup.style.top = ''; readerWordPopup.style.left = ''; + readerWordPopup.style.right = ''; + readerWordPopup.style.bottom = ''; + readerWordPopup.style.width = ''; return; } const rect = targetElement.getBoundingClientRect(); - const popupWidth = 320; + const popupWidth = (readerWordPopup.offsetWidth && readerWordPopup.offsetWidth >= 280 && readerWordPopup.offsetWidth <= 380) + ? readerWordPopup.offsetWidth + : 340; const popupHeight = readerWordPopup.offsetHeight || 220; const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; let left = rect.left + (rect.width / 2) - (popupWidth / 2); - if (left + popupWidth > viewportWidth - 12) { - left = viewportWidth - popupWidth - 12; + if (left + popupWidth > viewportWidth - 16) { + left = viewportWidth - popupWidth - 16; } - if (left < 12) { - left = 12; + if (left < 16) { + left = 16; } + const minTop = isZenMode ? 16 : 65; let top = rect.bottom + 8; - if (top + popupHeight > viewportHeight - 12) { - if (rect.top - popupHeight - 8 >= 65 || rect.top > viewportHeight / 2) { - top = Math.max(65, rect.top - popupHeight - 8); + if (top + popupHeight > viewportHeight - 16) { + if (rect.top - popupHeight - 8 >= minTop || rect.top > viewportHeight / 2) { + top = Math.max(minTop, rect.top - popupHeight - 8); } } readerWordPopup.style.top = `${Math.round(top)}px`; readerWordPopup.style.left = `${Math.round(left)}px`; + readerWordPopup.style.right = 'auto'; + readerWordPopup.style.bottom = 'auto'; + readerWordPopup.style.width = `${popupWidth}px`; } export async function openWordPopup(term, contextSentence, targetElement, paragraphContext = '') { diff --git a/app/static/sw.js b/app/static/sw.js index e6c7412..29c18b8 100644 --- a/app/static/sw.js +++ b/app/static/sw.js @@ -1,7 +1,7 @@ // Service Worker for Notes English PWA (Stage 2) // Strategy: Cache-first for static assets, Network-first for API calls. -const CACHE_NAME = 'notes-v6.7'; +const CACHE_NAME = 'notes-v6.8'; const OFFLINE_URL = '/'; const PRECACHE_URLS = [