* Increase header and sidebar icon scale on web and mobile Raise shared --icon-sm/md/lg tokens (~25%) for web shell chrome, widen chat header action controls, and align Expo home/thread header glyphs with 44pt tap targets. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * ci: retrigger checks after flaky evo-deploy test Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
import {
|
|
type AppearancePreference,
|
|
normalizeAppearancePreference,
|
|
type ResolvedAppearance,
|
|
resolveAppearance,
|
|
tokensForAppearance,
|
|
UI_APPEARANCE_STORAGE_KEY,
|
|
} from "@rakazo/ui-tokens";
|
|
import * as SecureStore from "expo-secure-store";
|
|
import { Appearance, type ColorSchemeName } from "react-native";
|
|
|
|
export type { AppearancePreference, ResolvedAppearance };
|
|
|
|
let memoryPreference: AppearancePreference | null = null;
|
|
const listeners = new Set<() => void>();
|
|
|
|
function systemAppearance(scheme?: ColorSchemeName | null): ResolvedAppearance {
|
|
return (scheme ?? Appearance.getColorScheme()) === "light" ? "light" : "dark";
|
|
}
|
|
|
|
export function getCachedAppearancePreference(): AppearancePreference {
|
|
return memoryPreference ?? "system";
|
|
}
|
|
|
|
export async function loadAppearancePreference(): Promise<AppearancePreference> {
|
|
try {
|
|
const stored = await SecureStore.getItemAsync(UI_APPEARANCE_STORAGE_KEY);
|
|
memoryPreference = normalizeAppearancePreference(stored);
|
|
} catch {
|
|
memoryPreference = memoryPreference ?? "system";
|
|
}
|
|
notify();
|
|
return memoryPreference;
|
|
}
|
|
|
|
export async function setAppearancePreference(
|
|
preference: AppearancePreference,
|
|
): Promise<AppearancePreference> {
|
|
memoryPreference = preference;
|
|
try {
|
|
await SecureStore.setItemAsync(UI_APPEARANCE_STORAGE_KEY, preference);
|
|
} catch {
|
|
// Keep the in-memory preference when SecureStore is unavailable.
|
|
}
|
|
notify();
|
|
return preference;
|
|
}
|
|
|
|
export function resolveMobileAppearance(
|
|
preference: AppearancePreference = getCachedAppearancePreference(),
|
|
scheme?: ColorSchemeName | null,
|
|
): ResolvedAppearance {
|
|
return resolveAppearance(preference, systemAppearance(scheme));
|
|
}
|
|
|
|
export function mobileTokens(
|
|
preference: AppearancePreference = getCachedAppearancePreference(),
|
|
scheme?: ColorSchemeName | null,
|
|
) {
|
|
return tokensForAppearance(resolveMobileAppearance(preference, scheme));
|
|
}
|
|
|
|
/** Header and inbox nav glyphs — aligned with web `--icon-*` scale (~25% larger). */
|
|
export const mobileShellIconSizes = {
|
|
md: 22,
|
|
lg: 26,
|
|
} as const;
|
|
|
|
export function subscribeAppearance(listener: () => void): () => void {
|
|
listeners.add(listener);
|
|
return () => {
|
|
listeners.delete(listener);
|
|
};
|
|
}
|
|
|
|
function notify() {
|
|
for (const listener of listeners) listener();
|
|
}
|
|
|
|
Appearance.addChangeListener(() => {
|
|
if (getCachedAppearancePreference() === "system") notify();
|
|
});
|