Each browser keeps its own theme, in a cookie (#69)
The theme was kept on the account, so every browser signed in as the same person got the same one: no Glass on the phone with Dracula on the desktop. It is now the ipx_theme cookie (<theme>.<mode>), written by theme.ts, and read by the server to draw the page in it from the first frame as before. /api/me no longer reports or takes a theme, and set_theme is gone. A browser with no cookie yet is sent the theme the account kept, and takes it as its cookie on that first load, so nobody loses their choice in the move. users.theme and theme_mode are only read now, for that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
/* ---------------- theme ---------------- */
|
||||
// A theme, and for those that come in both, light, dark or Auto, chosen in Settings and kept on
|
||||
// the account, so it follows you to another browser or computer. The server writes it onto the
|
||||
// page's <html> tag (data-theme, data-choice) so the page is drawn in it from the start. The
|
||||
// A theme, and for those that come in both, light, dark or Auto, chosen in Settings and kept in a
|
||||
// cookie, so each device has its own: Glass on a phone, Dracula on a desktop (issue #69). The
|
||||
// server reads it and writes it onto the page's <html> tag (data-theme, data-choice) so the page
|
||||
// is drawn in it from the start. The
|
||||
// page gets data-mode, light or dark, which is all the CSS reads: Auto is worked out here, from
|
||||
// the system, so no palette is written twice.
|
||||
const THEMES: Record<string, {name: string, modes: boolean}> = {
|
||||
@@ -25,7 +26,7 @@ const OLD_THEMES: Record<string, [string, string]> = {dark: ['modern', 'dark'],
|
||||
const systemDark = window.matchMedia?.('(prefers-color-scheme: dark)');
|
||||
const theme = {name: 'modern', mode: 'dark'};
|
||||
|
||||
/// `save` for a choice made in Settings, which goes to the account; not for applying one.
|
||||
/// `save` for a choice made in Settings, which goes to this browser's cookie; not for applying one.
|
||||
function setTheme(name = theme.name, mode = theme.mode, save = false){
|
||||
theme.name = THEMES[name] ? name : 'modern';
|
||||
theme.mode = MODES[mode] ? mode : 'dark';
|
||||
@@ -43,21 +44,18 @@ function setTheme(name = theme.name, mode = theme.mode, save = false){
|
||||
if(save) saveTheme();
|
||||
}
|
||||
|
||||
/// One save at a time, each sending the choice as it stands when it goes. Sent as they came,
|
||||
/// several at once, a quick run through the list could reach the server out of order and
|
||||
/// leave the account on a theme passed on the way.
|
||||
let themeSaving = Promise.resolve();
|
||||
/// Kept a year, for the whole site: the admin page is drawn in it too.
|
||||
function saveTheme(){
|
||||
themeSaving = themeSaving
|
||||
.then(() => api('/api/me', {method: 'PATCH', body: JSON.stringify({theme: theme.name, mode: theme.mode})}))
|
||||
.catch(e => toast(`Your theme was not saved: ${e.message}`, true));
|
||||
document.cookie = `ipx_theme=${theme.name}.${theme.mode}; Path=/; Max-Age=31536000; SameSite=Lax`;
|
||||
}
|
||||
systemDark?.addEventListener?.('change', () => { if(theme.mode === 'auto') setTheme(); });
|
||||
(() => {
|
||||
const root = document.documentElement;
|
||||
if(root.dataset.choice) return setTheme(root.dataset.theme, root.dataset.choice);
|
||||
// Nothing on the account yet. A theme this browser kept, from before themes were kept on the
|
||||
// account, goes up to it once, so nobody has to choose again.
|
||||
// Without a cookie, the server sent the theme the account kept from before; this browser takes
|
||||
// it as its own, once, so nobody has to choose again.
|
||||
if(root.dataset.choice) return setTheme(root.dataset.theme, root.dataset.choice, !/(^|; )ipx_theme=/.test(document.cookie));
|
||||
// Nothing on the account either. A theme this browser kept in localStorage, from before that,
|
||||
// becomes its cookie, once.
|
||||
let name: string | null = null, mode: string | null = null;
|
||||
try{ name = localStorage.getItem('ipx.theme'); mode = localStorage.getItem('ipx.mode'); }catch{}
|
||||
if(OLD_THEMES[name]) [name, mode] = OLD_THEMES[name];
|
||||
|
||||
Reference in New Issue
Block a user