Files
wehub-resource-sync e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:00:43 +08:00

137 lines
4.0 KiB
TypeScript

"use client";
export type AppLanguage = "en" | "zh";
export const ACTIVE_SESSION_STORAGE_KEY = "deeptutor.activeSessionId.tab";
export const LANGUAGE_STORAGE_KEY = "deeptutor-language";
export const SIDEBAR_COLLAPSED_STORAGE_KEY = "deeptutor.sidebarCollapsed";
export const CHAT_RESPONSE_TIMEOUT_STORAGE_KEY =
"deeptutor.chatResponseTimeout";
// Mirror of the per-user ``chat_response_timeout`` UI preference. Cached in
// localStorage so the chat watchdog (a separate provider from Settings) can
// read it synchronously without its own fetch. Kept in sync on settings load.
export const DEFAULT_CHAT_RESPONSE_TIMEOUT_SECONDS = 180;
export const MIN_CHAT_RESPONSE_TIMEOUT_SECONDS = 30;
export const MAX_CHAT_RESPONSE_TIMEOUT_SECONDS = 1800;
export function clampChatResponseTimeout(seconds: number): number {
if (!Number.isFinite(seconds)) return DEFAULT_CHAT_RESPONSE_TIMEOUT_SECONDS;
return Math.min(
MAX_CHAT_RESPONSE_TIMEOUT_SECONDS,
Math.max(MIN_CHAT_RESPONSE_TIMEOUT_SECONDS, Math.round(seconds)),
);
}
export function readStoredChatResponseTimeout(): number {
if (typeof window === "undefined")
return DEFAULT_CHAT_RESPONSE_TIMEOUT_SECONDS;
try {
const raw = window.localStorage.getItem(CHAT_RESPONSE_TIMEOUT_STORAGE_KEY);
const parsed = raw ? Number.parseInt(raw, 10) : NaN;
return Number.isFinite(parsed) && parsed > 0
? clampChatResponseTimeout(parsed)
: DEFAULT_CHAT_RESPONSE_TIMEOUT_SECONDS;
} catch {
return DEFAULT_CHAT_RESPONSE_TIMEOUT_SECONDS;
}
}
export function writeStoredChatResponseTimeout(seconds: number): void {
if (typeof window === "undefined") return;
try {
window.localStorage.setItem(
CHAT_RESPONSE_TIMEOUT_STORAGE_KEY,
String(clampChatResponseTimeout(seconds)),
);
} catch {
// localStorage may be unavailable
}
}
export const ACTIVE_SESSION_EVENT = "deeptutor:active-session";
export const LANGUAGE_EVENT = "deeptutor:language";
export const SIDEBAR_COLLAPSED_EVENT = "deeptutor:sidebar-collapsed";
export function normalizeLanguage(
value: string | null | undefined,
): AppLanguage {
return value === "zh" ? "zh" : "en";
}
export function readStoredLanguage(): AppLanguage {
if (typeof window === "undefined") return "en";
try {
return normalizeLanguage(window.localStorage.getItem(LANGUAGE_STORAGE_KEY));
} catch {
return "en";
}
}
export function writeStoredLanguage(language: AppLanguage): void {
if (typeof window === "undefined") return;
try {
window.localStorage.setItem(LANGUAGE_STORAGE_KEY, language);
window.dispatchEvent(
new CustomEvent(LANGUAGE_EVENT, {
detail: { language },
}),
);
} catch {
// localStorage may be unavailable
}
}
export function readStoredActiveSessionId(): string | null {
if (typeof window === "undefined") return null;
try {
return window.sessionStorage.getItem(ACTIVE_SESSION_STORAGE_KEY);
} catch {
return null;
}
}
export function writeStoredActiveSessionId(sessionId: string | null): void {
if (typeof window === "undefined") return;
try {
if (sessionId) {
window.sessionStorage.setItem(ACTIVE_SESSION_STORAGE_KEY, sessionId);
} else {
window.sessionStorage.removeItem(ACTIVE_SESSION_STORAGE_KEY);
}
window.dispatchEvent(
new CustomEvent(ACTIVE_SESSION_EVENT, {
detail: { sessionId },
}),
);
} catch {
// sessionStorage may be unavailable
}
}
export function readStoredSidebarCollapsed(): boolean {
if (typeof window === "undefined") return false;
try {
return window.localStorage.getItem(SIDEBAR_COLLAPSED_STORAGE_KEY) === "1";
} catch {
return false;
}
}
export function writeStoredSidebarCollapsed(collapsed: boolean): void {
if (typeof window === "undefined") return;
try {
window.localStorage.setItem(
SIDEBAR_COLLAPSED_STORAGE_KEY,
collapsed ? "1" : "0",
);
window.dispatchEvent(
new CustomEvent(SIDEBAR_COLLAPSED_EVENT, {
detail: { collapsed },
}),
);
} catch {
// localStorage may be unavailable
}
}