mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-09-12 13:58:30 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21f54e6e2b |
@@ -44,6 +44,11 @@
|
|||||||
// blank before the next window render lands.
|
// blank before the next window render lands.
|
||||||
const OVERSCAN_ROWS = 2;
|
const OVERSCAN_ROWS = 2;
|
||||||
const SCROLL_STATE_KEY = 'v3:songs-scroll-state';
|
const SCROLL_STATE_KEY = 'v3:songs-scroll-state';
|
||||||
|
// Persisted "how I'm looking" prefs (sort / format / view / drawer filters).
|
||||||
|
// The tester ask: "most users pick one sort and leave it" + remember filters.
|
||||||
|
// The search query and the artist/album drill-down are navigational, so they
|
||||||
|
// are deliberately NOT persisted; cold start stays the neutral Artist A–Z.
|
||||||
|
const PREFS_KEY = 'v3:songs-prefs';
|
||||||
const btnCtrl = 'bg-gray-800/50 border border-gray-700 rounded-md px-3 py-2 text-sm text-fb-text outline-none focus:border-fb-primary';
|
const btnCtrl = 'bg-gray-800/50 border border-gray-700 rounded-md px-3 py-2 text-sm text-fb-text outline-none focus:border-fb-primary';
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
@@ -127,6 +132,45 @@
|
|||||||
|
|
||||||
function _libraryStateHash() { return buildLibraryStateHash(state); }
|
function _libraryStateHash() { return buildLibraryStateHash(state); }
|
||||||
|
|
||||||
|
// Restore the persisted view prefs once per page load, before the first
|
||||||
|
// toolbar build so the selects render with the saved values. Every value is
|
||||||
|
// validated against its known option list, so a stale/removed setting can
|
||||||
|
// never wedge the UI — it just falls back to the default.
|
||||||
|
let _prefsRestored = false;
|
||||||
|
function applySavedPrefs() {
|
||||||
|
let saved;
|
||||||
|
try { saved = JSON.parse(localStorage.getItem(PREFS_KEY)); } catch (_) { return; }
|
||||||
|
if (!saved || typeof saved !== 'object') return;
|
||||||
|
if (SORTS.some(([v]) => v === saved.sort)) state.sort = saved.sort;
|
||||||
|
if (FORMATS.some(([v]) => v === saved.format)) state.format = saved.format;
|
||||||
|
if (saved.view === 'grid' || saved.view === 'tree' || saved.view === 'folder') state.view = saved.view;
|
||||||
|
const f = saved.filters;
|
||||||
|
if (f && typeof f === 'object') {
|
||||||
|
const arr = (x) => (Array.isArray(x) ? x.slice() : []);
|
||||||
|
state.filters = {
|
||||||
|
arr_has: arr(f.arr_has), arr_lacks: arr(f.arr_lacks),
|
||||||
|
stem_has: arr(f.stem_has), stem_lacks: arr(f.stem_lacks),
|
||||||
|
lyrics: f.lyrics || '', tunings: arr(f.tunings),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Persist the current view prefs (best-effort; storage may be full/disabled).
|
||||||
|
// Called from reload(), which every sort/format/filter/view change funnels
|
||||||
|
// through — so this is the single write point.
|
||||||
|
function saveLibraryPrefs() {
|
||||||
|
try {
|
||||||
|
const f = state.filters;
|
||||||
|
localStorage.setItem(PREFS_KEY, JSON.stringify({
|
||||||
|
sort: state.sort, format: state.format, view: state.view,
|
||||||
|
filters: {
|
||||||
|
arr_has: [...f.arr_has], arr_lacks: [...f.arr_lacks],
|
||||||
|
stem_has: [...f.stem_has], stem_lacks: [...f.stem_lacks],
|
||||||
|
lyrics: f.lyrics || '', tunings: [...f.tunings],
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
} catch (_) { /* best-effort */ }
|
||||||
|
}
|
||||||
|
|
||||||
function _saveLibraryScrollSnapshot() {
|
function _saveLibraryScrollSnapshot() {
|
||||||
const main = _getV3MainScroller();
|
const main = _getV3MainScroller();
|
||||||
// Geometry is now stable (the sizer reserves the full scroll height
|
// Geometry is now stable (the sizer reserves the full scroll height
|
||||||
@@ -1489,6 +1533,7 @@
|
|||||||
// tell whether the grid is stale (e.g. an off-screen search changed
|
// tell whether the grid is stale (e.g. an off-screen search changed
|
||||||
// state.q) and needs a refresh rather than a scroll-preserving no-op.
|
// state.q) and needs a refresh rather than a scroll-preserving no-op.
|
||||||
state.renderedHash = _libraryStateHash();
|
state.renderedHash = _libraryStateHash();
|
||||||
|
saveLibraryPrefs();
|
||||||
updateFilterBadge();
|
updateFilterBadge();
|
||||||
// A sort/filter/search/view change rebuilds the grid from page 0, so any
|
// A sort/filter/search/view change rebuilds the grid from page 0, so any
|
||||||
// in-flight letter jump is now paging through a dataset that's about to
|
// in-flight letter jump is now paging through a dataset that's about to
|
||||||
@@ -1541,6 +1586,9 @@
|
|||||||
async function render() {
|
async function render() {
|
||||||
const root = document.getElementById('v3-songs');
|
const root = document.getElementById('v3-songs');
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
|
// Restore last-used sort/format/view/filters once, before building the
|
||||||
|
// toolbar so its selects reflect the saved choice (default: Artist A–Z).
|
||||||
|
if (!_prefsRestored) { applySavedPrefs(); _prefsRestored = true; }
|
||||||
const providers = await loadProviders();
|
const providers = await loadProviders();
|
||||||
const [, tn] = await Promise.all([
|
const [, tn] = await Promise.all([
|
||||||
(async () => { state.accuracy = (await jget('/api/stats/best')) || {}; })(),
|
(async () => { state.accuracy = (await jget('/api/stats/best')) || {}; })(),
|
||||||
|
|||||||
Reference in New Issue
Block a user