mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-10-19 14:17:20 +02:00
fix: make dashboard UI consistent and compact on mobile
This commit is contained in:
1 parent
adc9dbd439
commit
282efdc16e
52 files changed
+2177
-712
No files matched your search
@@ -0,0 +1,77 @@
|
||||
// Drafts stay in this browser tab and are tied to the signed-in account.
|
||||
export function formDraft(state, fields, key) {
|
||||
let baseline;
|
||||
let watching = false;
|
||||
const storageKey = "form-draft:" + key;
|
||||
const values = () => Object.fromEntries(fields.map(field => [field, state[field]]));
|
||||
const serialize = () => JSON.stringify(values());
|
||||
const apply = (saved) => {
|
||||
for (const field of fields) {
|
||||
if (Object.prototype.hasOwnProperty.call(saved, field)) state[field] = saved[field];
|
||||
}
|
||||
if (state.options?.expirationDate) state.options.expirationDate = new Date(state.options.expirationDate);
|
||||
};
|
||||
const remove = () => { try { window.sessionStorage.removeItem(storageKey); } catch { /* Storage may be disabled. */ } };
|
||||
const save = (flush = false) => {
|
||||
if (baseline === undefined) return;
|
||||
if (flush) document.querySelectorAll("input, select, textarea").forEach(el => {
|
||||
if (el._field?.binding.state === state && el._field.timer) el._field.commit();
|
||||
});
|
||||
state.unsavedChanges = serialize() !== baseline;
|
||||
state.draftSaved = false;
|
||||
if (!state.unsavedChanges) { remove(); return; }
|
||||
try {
|
||||
window.sessionStorage.setItem(storageKey, JSON.stringify({
|
||||
account: state.user?.username || null, savedAt: Date.now(), values: values(),
|
||||
}));
|
||||
state.draftSaved = true;
|
||||
} catch { /* Keep the form usable when storage is disabled or full. */ }
|
||||
};
|
||||
const saveBeforeLeaving = () => save(true);
|
||||
state.on("routeLeave", saveBeforeLeaving);
|
||||
window.addEventListener("beforeunload", saveBeforeLeaving);
|
||||
state.on("dispose", () => window.removeEventListener("beforeunload", saveBeforeLeaving));
|
||||
return {
|
||||
restore() {
|
||||
baseline = serialize();
|
||||
let saved;
|
||||
try { saved = JSON.parse(window.sessionStorage.getItem(storageKey) || "null"); } catch { /* Ignore invalid drafts. */ }
|
||||
const restored = saved && saved.account === (state.user?.username || null)
|
||||
&& Date.now() - saved.savedAt < 30 * 60000 && saved.values;
|
||||
if (restored) {
|
||||
apply(saved.values);
|
||||
state.draftRestored = true;
|
||||
}
|
||||
if (!watching) {
|
||||
watching = true;
|
||||
state.watch(() => values(), () => save(), true);
|
||||
}
|
||||
state.unsavedChanges = serialize() !== baseline;
|
||||
return !!restored;
|
||||
},
|
||||
checkpoint() { return JSON.parse(serialize()); },
|
||||
accept(saved) {
|
||||
baseline = JSON.stringify(saved);
|
||||
state.draftRestored = false;
|
||||
save();
|
||||
},
|
||||
discard() {
|
||||
document.querySelectorAll("input, select, textarea").forEach(el => {
|
||||
if (el._field?.binding.state !== state || !el._field.timer) return;
|
||||
clearTimeout(el._field.timer);
|
||||
el._field.timer = null;
|
||||
el.value = el._field.binding.value ?? "";
|
||||
});
|
||||
if (baseline !== undefined) apply(JSON.parse(baseline));
|
||||
state.draftRestored = false;
|
||||
save();
|
||||
},
|
||||
clear() {
|
||||
baseline = serialize();
|
||||
state.unsavedChanges = false;
|
||||
state.draftRestored = false;
|
||||
state.draftSaved = false;
|
||||
remove();
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user