XL landscape polish: btn-primary sizing, tray from right, footer bg, layout fixes
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- .btn-xl removed; .btn-primary absorbs 4rem sizing (same as PICK SIGS/PICK ROLES) - Landscape navbar .btn-primary: 3rem → 4rem to match base; XL stays 4rem (consistent) - _button-pad.scss XL: base .btn ×1.2 (2.4rem); .btn-xl block deleted - _tray.scss XL (≥1800px): portrait-style tray (slides from right, z-95) - tray.js: _isLandscape() returns false at ≥1800px; portrait code paths run throughout - Footer sidebar: background-color added so opaque footer masks tray sliding behind it - Copyright .footer-container: bottom → top in landscape sidebar - #id_room_menu: right: 2.5rem override in _room.scss XL block (cascade fix) - navbar-text XL: 0.65rem × 1.2 = 0.78rem - All landscape media queries: max-width: 1440px cutoff removed (already done prior) - btn-xl class stripped from all 5 templates; test_navbar.py assertion updated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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 #
|
||||
|
||||
@@ -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) ────
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
right: 0.5rem;
|
||||
|
||||
@media (orientation: landscape) {
|
||||
right: 0.5rem;
|
||||
right: 1rem;
|
||||
bottom: 0.5rem;
|
||||
top: auto;
|
||||
}
|
||||
|
||||
@@ -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 ─────────────────────────────────────────────
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-xl">Share</button>
|
||||
<button type="submit" class="btn btn-primary">Share</button>
|
||||
</form>
|
||||
<small>Note shared with:
|
||||
{% for user in note.shared_with.all %}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
{% if room.gate_status == 'OPEN' %}
|
||||
<form method="POST" action="{% url 'epic:pick_roles' room.id %}" style="display:contents">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="launch-game-btn btn btn-primary btn-xl">PICK ROLES</button>
|
||||
<button type="submit" class="launch-game-btn btn btn-primary">PICK ROLES</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<form method="POST" action="{% url 'epic:confirm_token' room.id %}">
|
||||
{% csrf_token %}
|
||||
{% if is_last_slot %}
|
||||
<button type="submit" class="btn btn-primary btn-xl">PICK ROLES</button>
|
||||
<button type="submit" class="btn btn-primary">PICK ROLES</button>
|
||||
{% else %}
|
||||
<button type="submit" class="btn btn-confirm">OK</button>
|
||||
{% endif %}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div id="id_pick_sigs_wrap"{% if starter_roles|length < 6 %} style="display:none"{% endif %}>
|
||||
<form method="POST" action="{% url 'epic:pick_sigs' room.id %}">
|
||||
{% csrf_token %}
|
||||
<button id="id_pick_sigs_btn" type="submit" class="btn btn-primary btn-xl">PICK<br>SIGS</button>
|
||||
<button id="id_pick_sigs_btn" type="submit" class="btn btn-primary">PICK<br>SIGS</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
{% if navbar_recent_room_url %}
|
||||
<button
|
||||
id="id_cont_game"
|
||||
class="btn btn-primary btn-xl"
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
data-confirm="Continue game?"
|
||||
data-href="{{ navbar_recent_room_url }}"
|
||||
|
||||
Reference in New Issue
Block a user