Corp/frontend/src/lib/mobileNavPlacement.ts

100 lines
3.1 KiB
TypeScript

export type MobileNavPlacement = "top" | "bottom";
export const MOBILE_NAV_PLACEMENT_STORAGE_KEY = "mobile-nav-placement";
export const DEFAULT_MOBILE_NAV_PLACEMENT: MobileNavPlacement = "top";
const VALID_MOBILE_NAV_PLACEMENTS = new Set<MobileNavPlacement>(["top", "bottom"]);
const MOBILE_NAV_PLACEMENT_EVENT = "eusrr-mobile-nav-placement-change";
function isMobileNavPlacement(value: string | null): value is MobileNavPlacement {
return Boolean(value) && VALID_MOBILE_NAV_PLACEMENTS.has(value as MobileNavPlacement);
}
export function readMobileNavPlacementPreference(): MobileNavPlacement {
if (typeof window === "undefined") {
return DEFAULT_MOBILE_NAV_PLACEMENT;
}
try {
const stored = window.localStorage.getItem(MOBILE_NAV_PLACEMENT_STORAGE_KEY);
return isMobileNavPlacement(stored) ? stored : DEFAULT_MOBILE_NAV_PLACEMENT;
} catch {
return DEFAULT_MOBILE_NAV_PLACEMENT;
}
}
export function applyMobileNavPlacement(preference: MobileNavPlacement): MobileNavPlacement {
if (typeof document === "undefined") {
return preference;
}
document.documentElement.setAttribute("data-mobile-nav-placement", preference);
return preference;
}
export function setMobileNavPlacementPreference(preference: MobileNavPlacement): MobileNavPlacement {
if (typeof window !== "undefined") {
try {
window.localStorage.setItem(MOBILE_NAV_PLACEMENT_STORAGE_KEY, preference);
} catch {
// Ignore storage failures.
}
}
applyMobileNavPlacement(preference);
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent(MOBILE_NAV_PLACEMENT_EVENT, { detail: { preference } }));
}
return preference;
}
export function initializeMobileNavPlacement(): MobileNavPlacement {
const preference = readMobileNavPlacementPreference();
applyMobileNavPlacement(preference);
return preference;
}
export function subscribeToMobileNavPlacementChanges(callback: () => void): () => void {
if (typeof window === "undefined") {
return () => {};
}
const onPlacementEvent = () => callback();
const onStorage = (event: StorageEvent) => {
if (!event.key || event.key === MOBILE_NAV_PLACEMENT_STORAGE_KEY) {
callback();
}
};
window.addEventListener(MOBILE_NAV_PLACEMENT_EVENT, onPlacementEvent);
window.addEventListener("storage", onStorage);
return () => {
window.removeEventListener(MOBILE_NAV_PLACEMENT_EVENT, onPlacementEvent);
window.removeEventListener("storage", onStorage);
};
}
export function getMobileNavPlacementInitScript(): string {
return `
(function () {
var storageKey = ${JSON.stringify(MOBILE_NAV_PLACEMENT_STORAGE_KEY)};
var defaultPreference = ${JSON.stringify(DEFAULT_MOBILE_NAV_PLACEMENT)};
var valid = { top: true, bottom: true };
var root = document.documentElement;
var preference = defaultPreference;
try {
var stored = window.localStorage.getItem(storageKey);
if (stored && valid[stored]) {
preference = stored;
}
} catch (error) {}
root.setAttribute("data-mobile-nav-placement", preference);
})();
`;
}