diff --git a/src/apps/epic/static/apps/epic/tray.js b/src/apps/epic/static/apps/epic/tray.js index febcc5b..74a4889 100644 --- a/src/apps/epic/static/apps/epic/tray.js +++ b/src/apps/epic/static/apps/epic/tray.js @@ -40,6 +40,9 @@ var Tray = (function () { function _isLandscape() { if (_landscapeOverride !== null) return _landscapeOverride; + // ≥1800px uses portrait-style tray (slides from right) to match the + // doubled sidebar widths and XL tray CSS reset. + if (window.innerWidth >= 1800) return false; return window.innerWidth > window.innerHeight; } @@ -94,12 +97,10 @@ var Tray = (function () { // Closed: tray hidden above viewport, handle visible at y=0. _maxTop = -(gearBtnTop - handleH); } else { - // Portrait: slide on X axis. - // Wrap width is pinned to viewportW (JS) so its right edge only - // reaches the viewport boundary when left = 0 (fully open). - // This mirrors landscape: the open edge appears only at the last moment. - // Open: left = 0 → wrap right = viewportW exactly. - // Closed: left = viewportW - handleW → tray fully off-screen right. + // Portrait (and XL landscape, which uses portrait-style tray): + // Wrap width = viewportW so the closed right edge reaches the viewport boundary. + // The footer sidebar (z-100) is above the wrap (z-95) and has a solid background, + // so the handle parks behind it and slides out from under it when opened. var handleW = _btn.offsetWidth || 48; if (_wrap) _wrap.style.width = window.innerWidth + 'px'; _minLeft = 0; @@ -313,7 +314,7 @@ var Tray = (function () { } } else { if (_tray) _tray.style.display = 'none'; - if (_wrap) { _wrap.style.top = ''; _wrap.style.height = ''; } + if (_wrap) { _wrap.style.top = ''; _wrap.style.height = ''; _wrap.style.width = ''; } _computeBounds(); _applyVerticalBounds(); _computeCellSize(); @@ -342,8 +343,8 @@ var Tray = (function () { if (_wrap) _wrap.style.top = _maxTop + 'px'; _computeCellSize(); } else { - // Clear landscape's inline top so portrait CSS applies. - if (_wrap) _wrap.style.top = ''; + // Clear landscape's inline top/height/width so portrait CSS applies. + if (_wrap) { _wrap.style.top = ''; _wrap.style.width = ''; } _applyVerticalBounds(); _computeCellSize(); // wrap has correct height after _applyVerticalBounds _computeBounds(); diff --git a/src/functional_tests/test_navbar.py b/src/functional_tests/test_navbar.py index 08a88b0..bdb0327 100644 --- a/src/functional_tests/test_navbar.py +++ b/src/functional_tests/test_navbar.py @@ -113,7 +113,7 @@ class NavbarByeTest(FunctionalTest): class NavbarContGameTest(FunctionalTest): """ When the authenticated user has at least one room with a game event the - CONT GAME btn-primary btn-xl appears in the navbar and navigates to that + CONT GAME btn-primary appears in the navbar and navigates to that room on confirmation. Its tooltip must also appear below the button. """ @@ -139,7 +139,6 @@ class NavbarContGameTest(FunctionalTest): ) btn = self.browser.find_element(By.ID, "id_cont_game") self.assertIn("btn-primary", btn.get_attribute("class")) - self.assertIn("btn-xl", btn.get_attribute("class")) # ------------------------------------------------------------------ # # T6 — CONT GAME tooltip appears below btn # diff --git a/src/static_src/scss/_applets.scss b/src/static_src/scss/_applets.scss index 43ffa06..3fb7e15 100644 --- a/src/static_src/scss/_applets.scss +++ b/src/static_src/scss/_applets.scss @@ -120,7 +120,7 @@ .room-page, .billboard-page { > .gear-btn { - right: 0.5rem; + right: 1rem; bottom: 3.95rem; // same gap above kit btn as portrait; no page-specific overrides needed top: auto; } @@ -132,7 +132,7 @@ #id_wallet_applet_menu, #id_room_menu, #id_billboard_applet_menu { - right: 0.5rem; + right: 1rem; bottom: 6.6rem; top: auto; } @@ -153,7 +153,7 @@ #id_game_kit_menu, #id_wallet_applet_menu, #id_room_menu, - #id_billboard_applet_menu { right: 2rem; } + #id_billboard_applet_menu { right: 2.5rem; } } // ── Applet box visual shell (reusable outside the grid) ──── diff --git a/src/static_src/scss/_base.scss b/src/static_src/scss/_base.scss index f746cd3..57ef40a 100644 --- a/src/static_src/scss/_base.scss +++ b/src/static_src/scss/_base.scss @@ -194,7 +194,7 @@ body { } @media (orientation: landscape) { - $sidebar-w: 4rem; + $sidebar-w: 5rem; // ── Sidebar layout: navbar ← left, footer → right ──────────────────────────── body { @@ -266,11 +266,10 @@ body { } .btn-primary { - width: 3rem; - height: 3rem; - font-size: 0.75rem; - border-width: 0.125rem; - // margin-left: 0.75rem; + width: 4rem; + height: 4rem; + font-size: 0.875rem; + border-width: 0.21rem; } // Login form: offset from fixed sidebars in landscape @@ -328,6 +327,7 @@ body { align-items: center; border-top: none; border-left: 0.1rem solid rgba(var(--secUser), 0.3); + background-color: rgba(var(--priUser), 1); // opaque: masks tray sliding behind it padding: 1rem 0; gap: 0; z-index: 100; @@ -348,11 +348,11 @@ body { .footer-container { position: absolute; - bottom: 0.75rem; + top: 0.75rem; text-align: center; - font-size: 0.55rem; + font-size: 1rem; line-height: 1.4; - color: rgba(var(--secUser), 0.5); + color: rgba(var(--secUser), 1); br { display: block; } } @@ -372,13 +372,8 @@ body { } .navbar-brand h1 { font-size: 2.4rem; } - .navbar-text { font-size: 1.3rem; } - - .btn-primary { - width: 5rem; - height: 5rem; - font-size: 1.125rem; - } + .navbar-text { font-size: 0.78rem; } // 0.65rem × 1.2 + .btn-primary { width: 4rem; height: 4rem; font-size: 0.875rem; } .input-group { left: $sidebar-xl; @@ -393,8 +388,8 @@ body { // h2 page title: portrait-style — centred and full-size on a wide canvas body .container .row .col-lg-6 h2 { - font-size: 2rem; - letter-spacing: 0.33em; + font-size: 4rem; + letter-spacing: 1em; text-align: center; text-align-last: center; } @@ -403,7 +398,7 @@ body { width: $sidebar-xl; #id_footer_nav { - gap: 4rem; + gap: 8rem; a { font-size: 3rem; } } @@ -419,13 +414,6 @@ body { .navbar-brand h1 { font-size: 1.2rem; } - - .btn-primary { - width: 3rem; - height: 3rem; - font-size: 0.75rem; - border-width: 0.125rem; - } } .row .col-lg-6 h2 { @@ -492,8 +480,8 @@ body { br { display: none; } small { - font-size: 0.7rem; - opacity: 0.6; + font-size: 0.75rem; + opacity: 1; } } } diff --git a/src/static_src/scss/_button-pad.scss b/src/static_src/scss/_button-pad.scss index f55b9b4..be45654 100644 --- a/src/static_src/scss/_button-pad.scss +++ b/src/static_src/scss/_button-pad.scss @@ -25,6 +25,10 @@ } &.btn-primary { + width: 4rem; + height: 4rem; + font-size: 0.875rem; + border-width: 0.21rem; color: rgba(var(--quaUser), 1); border-color: rgba(var(--quaUser), 1); background-color: rgba(var(--quiUser), 1); @@ -34,37 +38,6 @@ 0.25rem 0.25rem 0.25rem rgba(var(--quiUser), 0.12) ; - &:hover { - text-shadow: - 0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.25), - 0 0 1rem rgba(var(--quaUser), 1) - ; - box-shadow: - 0.12rem 0.12rem 0.5rem rgba(0, 0, 0, 0.25), - 0 0 0.5rem rgba(var(--quaUser), 0.12) - ; - } - - &:active { - border: 0.18rem solid rgba(var(--quaUser), 1); - text-shadow: - -0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 0.25), - 0 0 0.12rem rgba(var(--quaUser), 1) - ; - box-shadow: - -0.1rem -0.1rem 0.12rem rgba(var(--quiUser), 0.25), - -0.1rem -0.1rem 0.12rem rgba(0, 0, 0, 0.25), - 0 0 0.5rem rgba(var(--quaUser), 0.12) - ; - } - } - - &.btn-xl { - width: 4rem; - height: 4rem; - font-size: 0.875rem; - border-width: 0.21rem; - &:hover { text-shadow: 0.2rem 0.2rem 0.2rem rgba(0, 0, 0, 0.25), @@ -72,7 +45,7 @@ ; box-shadow: 0.24rem 0.24rem 0.5rem rgba(0, 0, 0, 0.25), - 0 0 0.5rem rgba(var(--quaUser), 22) + 0 0 0.5rem rgba(var(--quaUser), 0.22) ; } @@ -87,7 +60,7 @@ -0.2rem -0.2rem 0.24rem rgba(0, 0, 0, 0.25), 0 0 0.5rem rgba(var(--quaUser), 0.22) ; - } + } } &.btn-abandon { @@ -300,6 +273,12 @@ } } + @media (orientation: landscape) and (min-width: 1800px) { + width: 2.4rem; // 2rem × 1.2 + height: 2.4rem; + font-size: 0.75rem; // 0.63rem × 1.2 + } + &.btn-disabled { cursor: default !important; font-size: 1.2rem; diff --git a/src/static_src/scss/_game-kit.scss b/src/static_src/scss/_game-kit.scss index a484042..701faca 100644 --- a/src/static_src/scss/_game-kit.scss +++ b/src/static_src/scss/_game-kit.scss @@ -4,7 +4,7 @@ right: 0.5rem; @media (orientation: landscape) { - right: 0.5rem; + right: 1rem; bottom: 0.5rem; top: auto; } diff --git a/src/static_src/scss/_room.scss b/src/static_src/scss/_room.scss index ff54dd2..1b8a191 100644 --- a/src/static_src/scss/_room.scss +++ b/src/static_src/scss/_room.scss @@ -1101,6 +1101,10 @@ html:has(.sig-backdrop) { @media (orientation: landscape) and (min-width: 1800px) { // Sig overlay: clear doubled navbar sidebar (8rem instead of 4rem) .sig-overlay { padding-left: 8rem; } + + // Room menu: base right: 0.5rem (same-specificity ID rule) overrides _applets.scss + // XL block because _room.scss is imported later. Re-declare here to win the cascade. + #id_room_menu { right: 2.5rem; } } // ─── Seat tray — see _tray.scss ───────────────────────────────────────────── diff --git a/src/static_src/scss/_tray.scss b/src/static_src/scss/_tray.scss index 0a18971..5abd493 100644 --- a/src/static_src/scss/_tray.scss +++ b/src/static_src/scss/_tray.scss @@ -329,10 +329,76 @@ $handle-r: 1rem; } } -// ── XL landscape: tray spans between doubled 8rem sidebars ───────────────── +// ── XL landscape (≥1800px): portrait-style tray — slides in from right ───── +// Overrides all landscape rules above. JS also returns false from _isLandscape() +// at this width so portrait code paths run throughout. @media (orientation: landscape) and (min-width: 1800px) { #id_tray_wrap { - left: 8rem; - right: 8rem; + flex-direction: row; + top: 0; + bottom: 0; + left: auto; // JS controls left; width set to innerWidth so wrap fills viewport + right: auto; + height: auto; + width: auto; + z-index: 95; // below footer/nav sidebars (z-100) — opaque footer masks the tray + transition: left 0.35s cubic-bezier(0.4, 0, 0.2, 1); + + &.wobble { animation: tray-wobble 0.45s ease; } + &.snap { animation: tray-snap 0.30s ease; } + } + + #id_tray_handle { + width: $handle-exposed; // 48px portrait strip + height: auto; + } + + #id_tray_grip { + top: 50%; + bottom: auto; + left: calc(#{$handle-exposed} / 2 - 0.125rem); + transform: translateY(-50%); + width: $handle-rect-w; // 10000px extends leftward + height: $handle-rect-h; // 72px + } + + #id_tray { + border-left: 2.5rem solid rgba(var(--quaUser), 1); + border-top: 2.5rem solid rgba(var(--quaUser), 1); + border-bottom: 2.5rem solid rgba(var(--quaUser), 1); + border-right: none; + margin-left: 0.5rem; + margin-bottom: 0; + width: auto; + max-width: none; + align-self: auto; + flex: 1; + height: auto; + overflow: hidden; + box-shadow: + -0.25rem 0 0.5rem rgba(0, 0, 0, 0.55), + inset 0 0 0 0.3rem rgba(var(--quiUser), 0.45), + inset 0.6rem 0 1.5rem -0.5rem rgba(0, 0, 0, 1), + inset 0.6rem 0 1.5rem -0.5rem rgba(var(--quiUser), 0.5), + inset 0 0.6rem 1.5rem -0.5rem rgba(0, 0, 0, 1), + inset 0 0.6rem 1.5rem -0.5rem rgba(var(--quiUser), 0.5), + inset 0 -0.6rem 1.5rem -0.5rem rgba(0, 0, 0, 1), + inset 0 -0.6rem 1.5rem -0.5rem rgba(var(--quiUser), 0.5) + ; + } + + #id_tray_grid { + grid-template-columns: none; + grid-template-rows: repeat(8, var(--tray-cell-size, 48px)); + grid-auto-flow: column; + grid-auto-columns: var(--tray-cell-size, 48px); + grid-auto-rows: auto; + position: static; + } + + .tray-cell { + border-top: none; + border-right: 2px dotted rgba(var(--priUser), 0.35); + border-bottom: 2px dotted rgba(var(--priUser), 0.35); } } diff --git a/src/templates/apps/dashboard/note.html b/src/templates/apps/dashboard/note.html index 21a7c5c..1afbcd1 100644 --- a/src/templates/apps/dashboard/note.html +++ b/src/templates/apps/dashboard/note.html @@ -41,7 +41,7 @@ {% endif %} - + Note shared with: {% for user in note.shared_with.all %} diff --git a/src/templates/apps/gameboard/_partials/_gatekeeper.html b/src/templates/apps/gameboard/_partials/_gatekeeper.html index fbb3257..fddc27b 100644 --- a/src/templates/apps/gameboard/_partials/_gatekeeper.html +++ b/src/templates/apps/gameboard/_partials/_gatekeeper.html @@ -53,7 +53,7 @@ {% if room.gate_status == 'OPEN' %}
{% csrf_token %} - +
{% endif %} diff --git a/src/templates/apps/gameboard/_partials/_table_positions.html b/src/templates/apps/gameboard/_partials/_table_positions.html index 6580a41..6189c83 100644 --- a/src/templates/apps/gameboard/_partials/_table_positions.html +++ b/src/templates/apps/gameboard/_partials/_table_positions.html @@ -8,7 +8,7 @@
{% csrf_token %} {% if is_last_slot %} - + {% else %} {% endif %} diff --git a/src/templates/apps/gameboard/room.html b/src/templates/apps/gameboard/room.html index 9ea6335..16a5205 100644 --- a/src/templates/apps/gameboard/room.html +++ b/src/templates/apps/gameboard/room.html @@ -14,7 +14,7 @@
{% endif %} diff --git a/src/templates/core/_partials/_navbar.html b/src/templates/core/_partials/_navbar.html index c07088f..bff202d 100644 --- a/src/templates/core/_partials/_navbar.html +++ b/src/templates/core/_partials/_navbar.html @@ -24,7 +24,7 @@ {% if navbar_recent_room_url %}