video discover: language preference UI (multi-select chips)

A 🌐 multi-select chip row in the Discover toolbar (EN/KO/JA/ES/FR/HI/DE/IT) to pick which
original languages appear in the general/curated rails. Loads the current preference from
/discover/languages, toggling a chip POSTs the new set and rebuilds the rails (never empty —
at least one stays on). Extracted reloadRails() (now shared by the hide-owned toggle + language
chips). Default EN, so the rails are English unless you opt more in.
This commit is contained in:
BoulderBadgeDad 2026-06-23 00:11:56 -07:00
parent 28fe3d2b0b
commit f1b6fd5e31
3 changed files with 53 additions and 6 deletions

View file

@ -1051,6 +1051,17 @@
<input type="checkbox" data-vdsc-hideowned>
<span>Hide owned</span>
</label>
<div class="vdsc-langs" data-vdsc-langs aria-label="Rail languages" title="Which original languages show in the general rails">
<span class="vdsc-langs-label">🌐</span>
<button class="vdsc-lang vdsc-lang--on" type="button" data-lang="en">EN</button>
<button class="vdsc-lang" type="button" data-lang="ko">KO</button>
<button class="vdsc-lang" type="button" data-lang="ja">JA</button>
<button class="vdsc-lang" type="button" data-lang="es">ES</button>
<button class="vdsc-lang" type="button" data-lang="fr">FR</button>
<button class="vdsc-lang" type="button" data-lang="hi">HI</button>
<button class="vdsc-lang" type="button" data-lang="de">DE</button>
<button class="vdsc-lang" type="button" data-lang="it">IT</button>
</div>
</div>
<div class="vdsc-chips" data-vdsc-chipset="genre" aria-label="Genre">
<button class="vdsc-chip vdsc-chip--on" type="button" data-val="">All genres</button>

View file

@ -333,6 +333,14 @@
.catch(function () { /* best-effort */ });
}
// Rebuild the whole rail stack (genre/curated shelves + the prepended personalized rows).
function reloadRails() {
renderShelves();
loadMoreLike();
loadGaps();
loadForYou();
}
// ── shelves (lazy rails) ──────────────────────────────────────────────────
function renderShelves() {
var host = $('[data-vdsc-shelves]'); if (!host) return;
@ -546,12 +554,30 @@
hide.addEventListener('change', function () {
page.classList.toggle('vdsc-hide-owned', hide.checked);
try { localStorage.setItem('vdsc_hideowned', hide.checked ? '1' : '0'); } catch (e) { /* ignore */ }
// The rails are now server-filtered for owned (and page deeper), so rebuild
// them with the new state instead of just CSS-hiding cards in place.
renderShelves();
loadMoreLike();
loadGaps();
loadForYou();
reloadRails(); // rails are server-filtered now (owned + paged deeper) — rebuild
});
}
// Rail language preference — multi-select chips, persisted server-side; rebuilds the rails.
var langWrap = $('[data-vdsc-langs]');
if (langWrap) {
fetch('/api/video/discover/languages', { headers: { Accept: 'application/json' } })
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (d) {
var set = {}; ((d && d.languages) || ['en']).forEach(function (c) { set[c] = 1; });
langWrap.querySelectorAll('.vdsc-lang').forEach(function (b) {
b.classList.toggle('vdsc-lang--on', !!set[b.getAttribute('data-lang')]);
});
}).catch(function () { /* default chip state stands */ });
langWrap.addEventListener('click', function (e) {
var btn = e.target.closest('.vdsc-lang'); if (!btn) return;
btn.classList.toggle('vdsc-lang--on');
var langs = Array.prototype.map.call(langWrap.querySelectorAll('.vdsc-lang--on'),
function (b) { return b.getAttribute('data-lang'); });
if (!langs.length) { btn.classList.add('vdsc-lang--on'); return; } // never allow empty
fetch('/api/video/discover/languages', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ languages: langs }),
}).then(function () { reloadRails(); }).catch(function () { /* ignore */ });
});
}
// Infinite scroll: a sentinel near the grid bottom pulls the next page.

View file

@ -2354,6 +2354,16 @@ body[data-side="video"] #soulsync-toggle { display: none; }
.vdsc-toggle input { accent-color: rgb(var(--accent-rgb, 88 101 242)); width: 16px; height: 16px; cursor: pointer; }
.vdsc-hide-owned .vsr-card--owned { display: none; }
/* rail-language preference chips — which original languages show in the general rails */
.vdsc-langs { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; margin-left: 14px; }
.vdsc-langs-label { font-size: 13px; opacity: 0.6; }
.vdsc-lang { font-size: 11px; font-weight: 700; letter-spacing: 0.3px; padding: 3px 8px; border-radius: 999px;
border: 1px solid rgba(255, 255, 255, 0.12); background: rgba(255, 255, 255, 0.04);
color: rgba(255, 255, 255, 0.5); cursor: pointer;
transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease; }
.vdsc-lang:hover { color: rgba(255, 255, 255, 0.85); }
.vdsc-lang--on { color: #fff; background: rgba(var(--accent-rgb, 88 101 242), 0.85); border-color: transparent; }
/* rails: a gentle fade-in when filled + per-title hue on hover */
.vdsc-shelf--in .vdsc-rail { animation: vdscFade 0.45s ease both; }
@keyframes vdscFade { from { opacity: 0.35; } to { opacity: 1; } }