Keep the page you're on in the address
Each page has an address (#filament, #printers, #collection/12), so a refresh or bookmark returns to it and Back/Forward move between pages. The search and filter bar is hidden on the Filament page, where it did nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ff2b0bc11f
commit
2aff27cbdd
1 changed files with 32 additions and 2 deletions
|
|
@ -71,6 +71,7 @@ function startApp() {
|
|||
document.getElementById('authScreen').style.display = 'none';
|
||||
document.querySelector('.container').style.display = '';
|
||||
if (!appStarted) { setupEventListeners(); appStarted = true; }
|
||||
selectedScope = scopeFromHash();
|
||||
loadData();
|
||||
}
|
||||
|
||||
|
|
@ -460,8 +461,9 @@ function scopeTitle() {
|
|||
}
|
||||
|
||||
function updateScopeChrome() {
|
||||
syncAddress(); // e.g. a deleted collection falling back to All Models
|
||||
contentTitle.textContent = scopeTitle();
|
||||
const panel = ['duplicates', 'ai', 'watch', 'printers'].includes(selectedScope); // pages without the model grid
|
||||
const panel = ['duplicates', 'ai', 'watch', 'filament', 'printers'].includes(selectedScope); // pages without the model grid
|
||||
document.getElementById('filterBar').hidden = panel;
|
||||
document.querySelector('.view-options').hidden = panel;
|
||||
emptyTrashBtn.hidden = !(selectedScope === 'trash' && trashModels.length);
|
||||
|
|
@ -977,12 +979,40 @@ function setupEventListeners() {
|
|||
document.getElementById('addFilesInput').addEventListener('change', handleAddFiles);
|
||||
}
|
||||
|
||||
async function selectScope(scope) {
|
||||
// The page you're on lives in the address — #filament, #collection/12 — so a
|
||||
// refresh or a bookmark comes back to it, and Back and Forward move between pages.
|
||||
function scopeHash(scope) {
|
||||
if (scope === 'all') return '';
|
||||
return SPECIAL_SCOPES.includes(scope) ? `#${scope}` : `#collection/${scope}`;
|
||||
}
|
||||
|
||||
function scopeFromHash() {
|
||||
const h = decodeURIComponent(location.hash.slice(1));
|
||||
const collection = h.match(/^collection\/(\d+)$/);
|
||||
if (collection) return collection[1];
|
||||
return SPECIAL_SCOPES.includes(h) ? h : 'all';
|
||||
}
|
||||
|
||||
// Keeps the address in step with the page shown; `push` makes a Back step.
|
||||
function syncAddress(push = false) {
|
||||
const hash = scopeHash(String(selectedScope));
|
||||
if (location.hash === hash || (!hash && !location.hash)) return;
|
||||
history[push ? 'pushState' : 'replaceState'](null, '', `${location.pathname}${location.search}${hash}`);
|
||||
}
|
||||
|
||||
async function selectScope(scope, { push = true } = {}) {
|
||||
selectedScope = scope;
|
||||
syncAddress(push);
|
||||
if (scope === 'trash') await loadTrash();
|
||||
renderModels();
|
||||
}
|
||||
|
||||
window.addEventListener('popstate', () => {
|
||||
if (!appStarted) return;
|
||||
const scope = scopeFromHash();
|
||||
if (String(scope) !== String(selectedScope)) selectScope(scope, { push: false });
|
||||
});
|
||||
|
||||
// Tracks the file currently shown in the detail viewer (for thumbnail regen).
|
||||
let currentDetailFile = null;
|
||||
let currentDetailThumb = null; // model image, used as a viewer fallback
|
||||
|
|
|
|||
Loading…
Reference in a new issue