Files
python-tdd/src/static_src/scss/_burger.scss

122 lines
4.2 KiB
SCSS
Raw Normal View History

room.html burger btn + 5-fan; universal landscape btn refactor; kit_bag_dialog vertical bar — TDD Major feature push staging room.html for sprint A.8 — adds the burger btn + fan-of-five sub-btns affordance, then rotates the whole landscape btn layout to make room for it. The landscape refactor is universal (not .room-page-scoped) so every page that hosts these btns reads consistently. ## Burger btn + fan-of-five (room.html only) `templates/apps/gameboard/_partials/_room_burger.html` (NEW) — `#id_burger_btn` (.fa-burger) + `#id_burger_fan` containing 5 sub-btns: `#id_voice_btn` (headset), `#id_sky_btn` (cloud), `#id_earth_btn` (earth-americas), `#id_sea_btn` (bridge-water), `#id_text_btn` (keyboard). Pure scaffolding — no click handlers in this sprint; wire-up lands later as each surface matures. `apps/epic/static/apps/epic/burger-btn.js` (NEW) — toggle `.active` on click; Escape + click-outside close; opening burger auto-closes the kit dialog (`#id_kit_bag_dialog`) + the bud slide-out panel (`html.bud-open`) by dispatching a click to the owning btn (routes through that btn's own toggle/close path — no fetch on close). `bindBurger()` returns an `AbortController` so test code (+ any future re-bind callers) can detach all listeners cleanly via `ac.abort()`. `static_src/scss/_burger.scss` (NEW) — burger sits parallel to gear-above-kit but on the bud-side. Portrait: bottom:4.2rem; left:0.5rem (above #id_bud_btn). Landscape: bottom:0.5rem; right:4.2rem (to the LEFT of #id_bud_btn). Fan is a CSS radial menu w. each sub-btn's `--angle = --base + --i * 30deg`. Portrait `--base: 0deg` (arc 12→4 o'clock), landscape `--base: -90deg` (arc 9→1 o'clock). Sub-btn radius `--r: 7.75rem`. Indices: voice=0, sky=1, earth=2, sea=3, text=4 (user-spec'd clockwise order). room.html includes the partial + the script; the burger renders unconditionally regardless of `gate_status` / `table_status`. ## Universal landscape btn refactor Sprint replaces the prior centred-in-sidebar landscape arrangement w. a kit-at-top + bud-at-bottom + gear/burger as horizontal partners. Applies to every page in landscape (was scoped to .room-page in the first iteration). `_game-kit.scss` — kit_btn landscape moves to top:0.5rem; right:0.5rem (was bottom:0.5rem centred in sidebar). The 0.5rem right literal (not the calc((--sidebar-w - 3rem)/2)=1rem) produces a 0.7rem edge-to-edge gap w. gear at right:4.2rem — matching the portrait gear-above-kit gap exactly. `_bud.scss` — bud_btn landscape moves to bottom:0.5rem; right:0.5rem (was top:0.5rem centred in sidebar). Same 0.5rem literal as kit_btn. bud_panel #id_recipient relocates to bottom:0.5rem (was top:0.5rem) + transform-origin flips to right center. .bud-suggestions rise upward from above the panel (bottom:4rem) instead of dropping from below. `_applets.scss` — .gear-btn landscape moves to top:0.5rem; right:4.2rem (was centred bottom:3.95rem). All applet menus anchor at top:2.6rem; right:4.2rem (beneath the gear's leftward arc) extending DOWN-LEFT into the viewport. #id_room_menu joins the shared portrait position list (was bespoke in _room.scss). `_room.scss` — bespoke #id_room_menu rule deleted entirely. The menu now inherits %applet-menu + the shared portrait position list — same chrome + behaviour as #id_post_menu / #id_billscroll_menu. Earlier iteration tried flex-direction:row in landscape; reverted per user request — "lose all scss specificity" wins. `_card-deck.scss` — obsolete `#id_room_menu { right: 2.5rem; }` override in the XL+landscape block deleted. Was a same-specificity hack to beat _applets.scss's old centred position; no longer needed w. the consolidated rule. ## kit_bag_dialog vertical bar in landscape `_game-kit.scss` — when open in landscape, dialog covers the right sidebar (top:0; bottom:0; right:0; width: var(--sidebar-w)). Slides in from off-viewport right by animating max-width 0 → var(--sidebar-w). Opaque bg (rgba(--priUser, 1) — was 0.97). z-index: 319 (above burger at 318) so it lands in front of the burger btn when open. Top-edge border → left-edge border. Inner content flips to `flex-direction: column-reverse` so DOM order Deck→Dice→Trinket→Tokens paints visually bottom→top. .kit-bag-section also column-reverse → icon row above label. .kit-bag-label drops vertical-rl + the rotate(180deg) scaleX(1.3) transform, reads horizontally. .kit-bag-row--scroll flips to column + overflow-y for the Tokens scrollable row. `game-kit.js attachTooltip()` — 2-axis tooltip clamp matching sky-wheel.js + wallet.js's pattern. Horizontal: left edge stays within [1rem, viewport-ttW-1rem]. Vertical: prefer ABOVE the element; flip BELOW when tooltip is too tall to fit above (e.g. landscape kit bar w. Tokens row near top). Resets top/bottom on mouseleave so next show measures fresh. ## Tests `apps/epic/tests/integrated/test_views.py` (+1 class, 6 ITs) — RoomBurgerBtnRenderTest: burger_btn renders, fan container renders, 5 sub-btns w. correct ids, icons match spec, burger-btn.js loaded, burger persists thru table_status. `static_src/tests/BurgerSpec.js` (NEW, 19 Jasmine specs) — bindBurger() returns AbortController; click toggle; Escape close; click-outside close; opening burger closes kit dialog + bud panel when set; AbortController teardown removes listeners. All 1356 IT+UT green (+6 new from RoomBurgerBtnRenderTest, was 1350). Jasmine suite green (was 220-something specs, +19 BurgerSpec). Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 20:40:33 -04:00
// ── Burger btn + fan-of-5 (room.html only) ───────────────────────────
//
// Sits parallel to .gear-btn-above-#id_kit_btn, but on the bud-side:
// portrait : bottom-left, above #id_bud_btn
// landscape: right sidebar, to the LEFT of #id_bud_btn (same horizontal
// pair as gear ← kit at the top)
//
// Active state opens a fanning arc of 5 sub-btns 30deg apart, each
// centred --r from the burger centre. R=7.75rem reads as a comfortable
// spread w. ~0.4rem edge-to-edge gaps between adjacent sub-btns.
// portrait : arc 12→4 o'clock (sky, earth, sea, voice, text)
// landscape: arc 9→1 o'clock (same icon order, rotated CCW 90°)
//
// Sub-btns are pure scaffolding — no click handlers in this sprint.
//
// Landscape btn relocation rules for kit / gear / bud / kit_dialog / bud
// panel / applet menus DON'T live in this partial — they're owned by
// their respective `_game-kit.scss`, `_bud.scss`, `_applets.scss`,
// `_room.scss` partials. _burger.scss only owns burger-specific styling.
#id_burger_btn {
position: fixed;
bottom: 4.2rem;
left: 0.5rem;
z-index: 318;
font-size: 1.75rem;
cursor: pointer;
color: rgba(var(--secUser), 1);
display: inline-flex;
align-items: center;
justify-content: center;
width: 3rem;
height: 3rem;
border-radius: 50%;
background-color: rgba(var(--priUser), 1);
border: 0.15rem solid rgba(var(--secUser), 1);
transition: opacity 0.15s ease;
&.active {
color: rgba(var(--quaUser), 1);
border-color: rgba(var(--quaUser), 1);
}
// Landscape: burger sits to the LEFT of #id_bud_btn (same bottom
// anchor as bud). Mirrors gear-to-the-LEFT-of-kit at the top of the
// right sidebar (see _applets.scss for the gear placement).
@media (orientation: landscape) {
left: auto;
right: 4.2rem; // bud_btn right (0.5) + 3.7rem centre-to-centre delta
bottom: 0.5rem;
top: auto;
}
}
// Fan anchor — sits at the burger centre. Sub-btns inside translate
// outward radially when #id_burger_btn carries the .active class.
#id_burger_fan {
position: fixed;
bottom: 5.7rem; // burger bottom (4.2) + half-btn (1.5)
left: 2rem; // burger left (0.5) + half-btn (1.5)
width: 0;
height: 0;
z-index: 317; // below #id_burger_btn so the burger stays clickable
pointer-events: none;
@media (orientation: landscape) {
left: auto;
right: 5.7rem; // burger right (4.2) + half-btn (1.5) → burger centre
bottom: 2rem; // burger bottom (0.5) + half-btn (1.5) → burger centre
top: auto;
}
}
.burger-fan-btn {
--r: 7.75rem;
--i: 0;
--base: 0deg; // portrait: arc starts at 12 o'clock
--angle: calc(var(--base) + var(--i) * 30deg);
position: absolute;
left: -1.5rem; // centre 3rem btn on parent's 0,0 origin
top: -1.5rem;
width: 3rem;
height: 3rem;
border-radius: 50%;
background-color: rgba(var(--priUser), 1);
border: 0.15rem solid rgba(var(--secUser), 1);
color: rgba(var(--secUser), 1);
font-size: 1.25rem;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
// Closed state — collapsed onto burger centre, invisible
transform: rotate(var(--angle)) translateY(0) rotate(calc(-1 * var(--angle)));
opacity: 0;
pointer-events: none;
transition: transform 0.25s ease-out, opacity 0.2s ease;
// Landscape: arc rotates CCW 90° — start at 9 o'clock instead of 12.
@media (orientation: landscape) {
--base: -90deg;
}
}
// Per-btn arc index (clockwise from arc start) — voice leads, then sky,
// earth, sea, text. Portrait arc: voice at 12, text at 4 o'clock.
// Landscape arc: voice at 9, text at 1 o'clock.
#id_voice_btn { --i: 0; }
#id_sky_btn { --i: 1; }
#id_earth_btn { --i: 2; }
#id_sea_btn { --i: 3; }
#id_text_btn { --i: 4; }
// Open state — sub-btns swing out to their arc positions.
#id_burger_btn.active ~ #id_burger_fan .burger-fan-btn {
transform: rotate(var(--angle)) translateY(calc(-1 * var(--r))) rotate(calc(-1 * var(--angle)));
opacity: 1;
pointer-events: auto;
}