* feat(channels): add guided setup flows * test(channels): preserve setup config values * fix(channels): reflect saved setup state * refactor(channels): simplify setup state metadata * fix(channels): harden setup lifecycle * refactor(channels): centralize setup contracts * fix(channels): route setup actions through webui shim * fix(channels): adapt settings for compact screens * fix(models): preserve default preset display * feat(models): add curated Codex catalog * fix(webui): stop attached gateway on interrupt * fix(webui): simplify apps catalog * docs(webui): clarify apps and runtime features * feat(settings): add guided capability setup * fix(webui): harden setup and managed services * test: keep managed runtime checks portable * test: scope POSIX runtime coverage * fix(webui): simplify file settings * feat(files): bundle document reading * fix(webui): harden setup request boundaries * fix(webui): prevent channel setup status squeeze * fix(settings): group provider compatibility aliases * refactor(settings): remove redundant setup surfaces * fix(webui): harden guided setup lifecycle * fix(webui): preserve channel setup compatibility
31 lines
772 B
TypeScript
31 lines
772 B
TypeScript
import { useEffect, useState } from "react";
|
|
|
|
export function useMediaQuery(query: string, fallback = false): boolean {
|
|
const readMatch = () => {
|
|
if (
|
|
typeof window === "undefined" ||
|
|
typeof window.matchMedia !== "function"
|
|
) {
|
|
return fallback;
|
|
}
|
|
return window.matchMedia(query).matches;
|
|
};
|
|
|
|
const [matches, setMatches] = useState(readMatch);
|
|
|
|
useEffect(() => {
|
|
if (
|
|
typeof window === "undefined" ||
|
|
typeof window.matchMedia !== "function"
|
|
)
|
|
return;
|
|
const media = window.matchMedia(query);
|
|
const update = () => setMatches(media.matches);
|
|
update();
|
|
media.addEventListener("change", update);
|
|
return () => media.removeEventListener("change", update);
|
|
}, [query]);
|
|
|
|
return matches;
|
|
}
|