ecbbb4dd8f
- Chat view: an attached image's path is pasted on its own after the text (promptForPane). claude turns a paste that is only an image path into [Image #n], but left a Windows path inside a paste of text as a plain path. Other files and @-mentions stay in the text as before. - Plugin bootstrap: depsHash covers only what npm installs (no release version), so a version bump no longer reinstalls runtime deps; the client's installed tree is kept while its manifests are unchanged (no npm ci per update); the user-side build runs vite only (tsc -b cost ~25 s / ~900 MB); clientBuild is recorded only after a build that did not fail, so a failed one is retried; npm output goes to runtime/npm-install.log. - Server: a port held by another program ends with a clear message and exit 1 instead of an uncaught 'error' stack trace. - Client: the onboarding wizard is lazy and rendered only before onboarding; usePrefersReducedMotion moved to hooks/ so PetSettings no longer pulls the Sagi chat/pane stack into the entry chunk (884 KB -> 431 KB, gzip 268 -> 133 KB).
28 lines
996 B
TypeScript
28 lines
996 B
TypeScript
/**
|
|
* @file usePrefersReducedMotion.ts
|
|
* @description The OS "reduce motion" preference, followed live. Its own
|
|
* module so a settings screen can read it without importing the pet overlay
|
|
* (`components/Sagi/Sagi.tsx`), whose chat and pane UI would otherwise be
|
|
* pulled into every page's first bundle.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
/** The OS "reduce motion" preference, followed live. */
|
|
export function usePrefersReducedMotion(): boolean {
|
|
const [reduced, setReduced] = useState(
|
|
() =>
|
|
typeof window !== "undefined" &&
|
|
window.matchMedia?.("(prefers-reduced-motion: reduce)").matches
|
|
);
|
|
useEffect(() => {
|
|
const mq = window.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
if (!mq) return;
|
|
const onChange = () => setReduced(mq.matches);
|
|
mq.addEventListener?.("change", onChange);
|
|
return () => mq.removeEventListener?.("change", onChange);
|
|
}, []);
|
|
return reduced;
|
|
}
|