Let the toggle come back to the theme you were on
The top-bar toggle went to light from anything dark, and back to plain "dark" -- which quietly moved an ihasmail user onto a theme they had never chosen, two clicks and no way to tell what had happened. It did the same to "match system", which the toggle could not restore at all; the comment above it conceded as much and sent people to Settings. There is more than one way to be dark now, so the way back is remembered: lastDarkTheme holds whichever non-light theme was last chosen, and the toggle returns to that. The remembering lives in update(), the single path every way of setting a theme goes through -- the toggle, Appearance, an imported settings file -- so a fourth way to choose one cannot forget to record it. Light never overwrites it, since light is the side being toggled away from. The button's label follows: "Switch to the ihasmail theme", "Switch to your system theme", rather than claiming everything dark is "dark mode". Confirmed in a browser, not only in tests: from a fresh profile the round trip ihasmail -> light -> ihasmail returns to ihasmail, and system -> light -> system returns to system, with the label naming the destination each time.
This commit is contained in:
@@ -88,6 +88,14 @@ export interface Settings {
|
||||
eventCategories: Array<{ name: string; color: string }>;
|
||||
/** Default sending identity per account (JMAP has no such flag). */
|
||||
defaultIdentityByAccount: Record<string, string>;
|
||||
/**
|
||||
* The theme the top-bar toggle goes back to from light. Remembered rather
|
||||
* than assumed, so flipping to light and back returns you to the theme you
|
||||
* were on — "ihasmail", "system" or plain "dark" — instead of dropping
|
||||
* everyone onto the same one. Never "light": that is the side being
|
||||
* toggled away from.
|
||||
*/
|
||||
lastDarkTheme: Exclude<Theme, "light">;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: Settings = {
|
||||
@@ -152,6 +160,7 @@ export const DEFAULT_SETTINGS: Settings = {
|
||||
{ name: "Family", color: "#9333ea" },
|
||||
],
|
||||
defaultIdentityByAccount: {},
|
||||
lastDarkTheme: "ihasmail",
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -215,14 +224,18 @@ applyDateTimePrefs(initialSettings);
|
||||
export const useSettings = create<SettingsState>((set, get) => ({
|
||||
settings: initialSettings,
|
||||
update(patch) {
|
||||
const settings = { ...get().settings, ...patch };
|
||||
// Picking a theme anywhere — the toggle, Appearance, an imported file —
|
||||
// is what teaches the toggle where to come back to. Doing it here rather
|
||||
// than at the call sites means a fourth way to set a theme cannot forget.
|
||||
const next = patch.theme && patch.theme !== "light" ? { ...patch, lastDarkTheme: patch.theme } : patch;
|
||||
const settings = { ...get().settings, ...next };
|
||||
saveJson("settings", settings);
|
||||
set({ settings });
|
||||
applyTheme(settings);
|
||||
applyDateTimePrefs(settings);
|
||||
// Dragging a splitter changes a device key on every frame and must not put
|
||||
// a request in the air; anything else is queued and coalesced.
|
||||
if (Object.keys(patch).some((k) => !DEVICE_KEYS.has(k as keyof Settings))) {
|
||||
if (Object.keys(next).some((k) => !DEVICE_KEYS.has(k as keyof Settings))) {
|
||||
queueSettingsPush(syncedPart(settings));
|
||||
}
|
||||
},
|
||||
@@ -278,6 +291,15 @@ export function applyTheme(s: Settings = useSettings.getState().settings): void
|
||||
if (meta) meta.content = s.theme === "ihasmail" ? THEME_COLOR.ihasmail : dark ? THEME_COLOR.dark : THEME_COLOR.light;
|
||||
}
|
||||
|
||||
/**
|
||||
* Where the top-bar toggle goes next. Away from dark is always light; back
|
||||
* from light is wherever you last were, which is the whole point of
|
||||
* remembering it.
|
||||
*/
|
||||
export function toggleTarget(effective: "light" | "dark", lastDarkTheme: Settings["lastDarkTheme"]): Theme {
|
||||
return effective === "dark" ? "light" : lastDarkTheme;
|
||||
}
|
||||
|
||||
/** Whether a theme paints dark, resolving "system" against the OS. */
|
||||
export function isDarkTheme(theme: Theme, prefersDark = false): boolean {
|
||||
return theme === "dark" || theme === "ihasmail" || (theme === "system" && prefersDark);
|
||||
|
||||
Reference in New Issue
Block a user