Fixes the Bill Bud invite cascade so the sea sub-btn actually lights + leads to the bud's my_sea, and gives the My Buds row tooltip viewport clamping + hover/lock styling. SeaInvite.invitee_access_open (gameboard/models.py): new invitee-facing access window — a non-terminal invite (PENDING/ACCEPTED) within 24h of being proffered OR within 24h of the invitee's last gate token deposit. Re-arms on each deposit; DECLINED/LEFT/EXPIRED stay shut. Distinct from is_expired (which only models the PENDING lapse). 8 UTs. bud_page (billboard/views.py): sea_btn_active / sea_first_draw_pending now key on invitee_access_open across PENDING + ACCEPTED, not PENDING-only. Old design darkened the btn the instant the user accepted, so they could never reach the bud's sea from here post-accept — that was the red .fa-ban the user saw. ITs updated: accepted-within-window now lights; added stale-accepted-dark + recent-deposit-relights cases. my_sea_visit (gameboard/views.py): accept-on-GET — a still-pending, non-expired invite from the owner to the visitor is accepted implicitly on arrival (the sea-btn cascade + @mailman post-attribution anchor both land here, so the click IS the acceptance). Previously PENDING → 403, so the cascade dead-ended. ITs: pending-invitee now auto-accepts (200); expired-pending still 403s; stranger still 403s. bud.html: burger → sea_btn glow-handoff machine (the my_sea.html cascade minus the spread-modal stage) so the glow rides the affordance chain to the click target; active sea click clears glow, preserves .active, navigates. my-buds-tooltip.js: clamp the position:fixed #id_tooltip_portal to the viewport on row-lock — same 1rem-inset shape as game-kit.js / sky-wheel.js / wallet.js (measure after .active, clamp left, prefer above / flip below). Reset on clear. _billboard.scss: .bud-entry hover + .row-locked highlight (rows aren't .row-3col so the existing rule missed them) — fill --secUser, flip the --terUser handle to --quiUser, trailing title to readable --priUser. 520 billboard+gameboard ITs/UTs green; affected sea-btn-cascade FT green. Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
98 lines
4.2 KiB
HTML
98 lines
4.2 KiB
HTML
{% extends "core/base.html" %}
|
||
{% load static %}
|
||
{% load lyric_extras %}
|
||
|
||
{% block title_text %}Billbud{% endblock title_text %}
|
||
{% block header_text %}<span>Bill</span><span>bud</span>{% endblock header_text %}
|
||
|
||
{% block content %}
|
||
{# note.js exposes window.Brief — needed by the auto-fired @mailman Brief #}
|
||
{# when this page is the destination of an invite cascade. #}
|
||
<script src="{% static 'apps/dashboard/note.js' %}"></script>
|
||
|
||
<div class="bud-page">
|
||
<header class="bud-page-header">
|
||
<h3>{{ bud|at_handle }} the {{ bud.active_title_display }}</h3>
|
||
<p class="bud-page-email">{{ bud.email }}</p>
|
||
</header>
|
||
|
||
<form id="id_bud_shoptalk_form"
|
||
method="POST"
|
||
action="{% url 'billboard:save_bud_shoptalk' bud.id %}"
|
||
class="bud-shoptalk-form">
|
||
{% csrf_token %}
|
||
<label for="id_shoptalk" class="bud-shoptalk-label">Shoptalk</label>
|
||
<textarea id="id_shoptalk"
|
||
name="shoptalk"
|
||
maxlength="160"
|
||
class="form-control bud-shoptalk-input"
|
||
placeholder="Your personal note about this bud…">{{ shoptalk_text }}</textarea>
|
||
</form>
|
||
|
||
{# 4-btn apparatus mirrors my_sea.html: kit (from base.html) + bud + #}
|
||
{# gear + burger. Apparatus loads bud-btn.js (defines window. #}
|
||
{# bindBudBtn — does NOT auto-bind); the inline script below opens #}
|
||
{# the panel + stubs OK to disabled per the sprint plan. #}
|
||
{% include "apps/billboard/_partials/_bud_apparatus.html" with aria_label="Bud" include_suggestions=False %}
|
||
<script>
|
||
(function () {
|
||
var btn = document.getElementById('id_bud_btn');
|
||
var panel = document.getElementById('id_bud_panel');
|
||
var ok = document.getElementById('id_bud_ok');
|
||
if (!btn || !panel || !ok) return;
|
||
// bud-of-bud flow isn't wired yet — stub OK as disabled w. × text.
|
||
ok.classList.add('btn-disabled');
|
||
ok.textContent = '×';
|
||
ok.setAttribute('disabled', 'disabled');
|
||
btn.addEventListener('click', function () {
|
||
var open = document.documentElement.classList.toggle('bud-open');
|
||
btn.classList.toggle('active', open);
|
||
});
|
||
document.addEventListener('keydown', function (e) {
|
||
if (e.key === 'Escape' && document.documentElement.classList.contains('bud-open')) {
|
||
document.documentElement.classList.remove('bud-open');
|
||
btn.classList.remove('active');
|
||
}
|
||
});
|
||
}());
|
||
</script>
|
||
|
||
{% include "apps/billboard/_partials/_bud_gear.html" %}
|
||
|
||
{# Burger fan — sea_btn_active + sea_first_draw_pending drive the #}
|
||
{# server-side .active / .glow-handoff classes (same vars my_sea + #}
|
||
{# room read). burger-btn.js auto-binds on DOMContentLoaded. #}
|
||
{% include "apps/gameboard/_partials/_burger.html" %}
|
||
</div>
|
||
|
||
<script src="{% static 'apps/epic/burger-btn.js' %}"></script>
|
||
{% if pending_invite %}
|
||
<script>
|
||
(function () {
|
||
var burger = document.getElementById('id_burger_btn');
|
||
var sea = document.getElementById('id_sea_btn');
|
||
if (!burger || !sea) return;
|
||
// Glow-handoff machine — the bud-page counterpart of my_sea.html's
|
||
// burger → sea_btn cascade, minus the spread-modal stage (the active
|
||
// sea sub-btn navigates away instead of opening a modal). The burger
|
||
// carries .glow-handoff server-side (sea_first_draw_pending); opening
|
||
// it hands the glow off to the sea sub-btn so the nudge rides the
|
||
// affordance chain to the click target.
|
||
burger.addEventListener('click', function () {
|
||
if (!burger.classList.contains('glow-handoff')) return;
|
||
burger.classList.remove('glow-handoff');
|
||
sea.classList.add('glow-handoff');
|
||
});
|
||
// Active sea sub-btn click → the bud's spectator my-sea (which accepts
|
||
// the invite on GET). Clears the glow but PRESERVES .active. Fires in
|
||
// the target phase, BEFORE burger-btn.js's delegated fan-close.
|
||
sea.addEventListener('click', function () {
|
||
if (!sea.classList.contains('active')) return;
|
||
sea.classList.remove('glow-handoff');
|
||
window.location.href = '/gameboard/my-sea/visit/{{ bud.id }}/';
|
||
});
|
||
}());
|
||
</script>
|
||
{% endif %}
|
||
{% endblock content %}
|