Continuation of the burger sprint into the my-sea gatekeeper + a couple companion cleanups the visual + CI runs surfaced.
## my_sea_gate.html burger
`templates/apps/gameboard/_partials/_room_burger.html` → `_burger.html` (git mv) — now lives at a non-room-scoped path since it's reused across templates. Updated room.html's include path.
`templates/apps/gameboard/my_sea_gate.html` — includes `_burger.html` + loads `burger-btn.js`. Burger renders unconditionally on the my-sea gatekeeper, same affordance as the room gatekeeper.
`apps/gameboard/tests/integrated/test_views.py::MySeaGateViewTest` — new `test_gate_view_renders_burger_btn_and_fan` IT asserts burger_btn + burger_fan + 5 sub-btns w. correct ids + burger-btn.js loaded on `/gameboard/my-sea/gate/`.
## Burger fade rule reinstated
`static_src/scss/_burger.scss` — `html.bud-open #id_burger_btn { opacity: 0; pointer-events: none; }` reinstated, scoped to landscape only. User-confirmed: even after the z-index drop the burger needs to disappear when bud_panel is open in landscape (panel + bud_ok races vs. burger pointer-events). Portrait keeps burger visible since the panel sits BELOW the burger w. no overlap.
## "friend@example.com" → "bud@example.com" placeholder
Renamed in 4 bud-panel templates + the FT asserting it:
- `templates/apps/gameboard/_partials/_my_sea_bud_panel.html`
- `templates/apps/billboard/_partials/_bud_panel.html`
- `templates/apps/billboard/_partials/_bud_invite_panel.html`
- `templates/apps/billboard/_partials/_bud_add_panel.html`
- `functional_tests/test_core_sharing.py`
"bud" matches the broader naming convention (bud_btn, my-buds, share-w.-a-bud, etc.) — `friend` was an outlier.
## _bud_apparatus.html shared shell refactor
New `templates/apps/billboard/_partials/_bud_apparatus.html` — single shared markup partial for the four bud-btn use cases. Contains btn + panel + input + OK + (optional) suggestions div + bud-btn.js script. Each of the 4 specific partials becomes a thin wrapper that `{% include %}`s the shell + renders its own `<script>bindBudBtn({...})</script>` block w. per-use-case submitUrl / onSuccess / duplicateTargetSelector.
Context vars accepted by the shell:
- `aria_label` — string for #id_bud_btn aria-label
- `sharer_name` — optional; renders `data-sharer-name=` on #id_bud_panel (post-share only)
- `include_suggestions` — bool; renders suggestions div + autocomplete script (false on my_buds where the pool == request.user.buds == nothing useful to suggest)
Per-call wrappers are now ~10-50 lines instead of 30-120 lines of duplicate markup. Behaviour is identical; only DRY-ed up.
## CI #344 tray-anchor regression fix
`apps/epic/static/apps/epic/tray.js` — `_computeBounds` in landscape used `id_gear_btn || id_kit_btn` as the bottom anchor (wrap height = anchor.top). After the burger sprint relocated kit_btn to the TOP of the right sidebar (top:0.5rem), kit_btn.top ≈ 8px → wrap.height collapsed to 8px → tray couldn't slide → `test_dragging_tray_btn_down_opens_tray_in_landscape` failed.
Fix: anchor fallback chain is now `id_burger_btn || id_bud_btn` (the new bottom-anchored btns) → `window.innerHeight - 3.5rem` reserved fallback (for pages that have neither). Burger renders unconditionally on room.html so the SIG_SELECT tray test now finds its anchor + lays out the wrap correctly.
## Verification
- IT+UT 1357 green (+1 from MySeaGateViewTest burger).
- Jasmine specs green.
- `test_dragging_tray_btn_down_opens_tray_in_landscape` green (was the CI #344 failure).
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
94 lines
4.1 KiB
HTML
94 lines
4.1 KiB
HTML
{% load lyric_extras %}
|
|
{# _bud_panel.html — bud btn + slide-out for the post-share flow on #}
|
|
{# post.html. On success: appends a Line to #id_post_table, fires #}
|
|
{# Brief.showBanner, + updates the .post-header shared-with prose. #}
|
|
{# `sharer_name` (rendered onto data-sharer-name) is the author of the #}
|
|
{# optimistically-appended Line so it matches the persisted post-refresh #}
|
|
{# state where Line.author == request.user. #}
|
|
{% include "apps/billboard/_partials/_bud_apparatus.html" with aria_label="Share with a bud" sharer_name=request.user|at_handle include_suggestions=True %}
|
|
<script>
|
|
(function () {
|
|
'use strict';
|
|
|
|
var panel = document.getElementById('id_bud_panel');
|
|
|
|
// Author = the sharer (rendered server-side as data-sharer-name) so the
|
|
// appended Line matches the post-refresh state, where the persisted
|
|
// Line.author is request.user.
|
|
function _appendLine(text) {
|
|
var list = document.getElementById('id_post_table');
|
|
if (!list) return;
|
|
var li = document.createElement('li');
|
|
li.className = 'post-line';
|
|
var author = document.createElement('span');
|
|
author.className = 'post-line-author';
|
|
author.textContent = panel.dataset.sharerName || '';
|
|
var body = document.createElement('span');
|
|
body.className = 'post-line-text';
|
|
body.textContent = text;
|
|
var time = document.createElement('time');
|
|
time.className = 'post-line-time';
|
|
var now = new Date();
|
|
time.dateTime = now.toISOString();
|
|
time.textContent = now.toLocaleTimeString([], {hour: 'numeric', minute: '2-digit'});
|
|
li.appendChild(author);
|
|
li.appendChild(body);
|
|
li.appendChild(time);
|
|
var buffer = list.querySelector('.post-line-buffer');
|
|
if (buffer) list.insertBefore(li, buffer);
|
|
else list.appendChild(li);
|
|
}
|
|
|
|
// The shared-with header lives outside #id_bud_panel — two <p> siblings
|
|
// under .post-header. State transitions:
|
|
// 0 → 1+ recipients : "just me, X" → "shared between {chip}" + "& me, X"
|
|
// ≥1 → +1 recipients: append chip + ", " separator before existing.
|
|
// `userId` is stamped onto the chip as data-user-id so a later duplicate-
|
|
// share attempt can highlight this same element via .bud-duplicate-flash.
|
|
function _appendRecipientChip(displayName, userId) {
|
|
if (!displayName) return;
|
|
var header = document.querySelector('.post-page .post-header');
|
|
if (!header) return;
|
|
var existingRecipients = header.querySelector('.post-shared-recipients');
|
|
var selfLine = header.querySelector('.post-shared-self');
|
|
|
|
var chip = document.createElement('span');
|
|
chip.className = 'post-recipient';
|
|
chip.textContent = displayName;
|
|
if (userId) chip.dataset.userId = userId;
|
|
|
|
if (existingRecipients) {
|
|
existingRecipients.appendChild(document.createTextNode(', '));
|
|
existingRecipients.appendChild(chip);
|
|
return;
|
|
}
|
|
|
|
var recipientsLine = document.createElement('p');
|
|
recipientsLine.className = 'post-shared-recipients';
|
|
recipientsLine.appendChild(document.createTextNode('shared between '));
|
|
recipientsLine.appendChild(chip);
|
|
if (selfLine) {
|
|
header.insertBefore(recipientsLine, selfLine);
|
|
selfLine.textContent = selfLine.textContent.replace(/^just me,/, '& me,');
|
|
} else {
|
|
header.appendChild(recipientsLine);
|
|
}
|
|
}
|
|
|
|
bindBudBtn({
|
|
submitUrl: '{% url "billboard:share_post" post.id %}',
|
|
autocompleteUrl: '{% url "billboard:search_buds" %}',
|
|
onSuccess: function (data) {
|
|
if (data.line_text) _appendLine(data.line_text);
|
|
if (window.Brief && data.brief) Brief.showBanner(data.brief);
|
|
if (data.recipient_display) {
|
|
_appendRecipientChip(data.recipient_display, data.recipient_user_id);
|
|
}
|
|
},
|
|
duplicateTargetSelector: function (data) {
|
|
return '.post-recipient[data-user-id="' + data.recipient_user_id + '"]';
|
|
},
|
|
});
|
|
}());
|
|
</script>
|