0.4.0 convex及界面修改
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useAppPreferencesStore } from "@/store/app-preferences";
|
||||
|
||||
const applyTheme = (theme: "system" | "light" | "dark") => {
|
||||
if (typeof document === "undefined") return;
|
||||
const root = document.documentElement;
|
||||
const prefersDark =
|
||||
typeof window !== "undefined" &&
|
||||
typeof window.matchMedia === "function" &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
const shouldDark = theme === "dark" || (theme === "system" && prefersDark);
|
||||
root.classList.toggle("dark", shouldDark);
|
||||
};
|
||||
|
||||
export function AppPreferencesHydrator() {
|
||||
const hydrated = useAppPreferencesStore((s) => s.hydrated);
|
||||
const hydrate = useAppPreferencesStore((s) => s.hydrate);
|
||||
const theme = useAppPreferencesStore((s) => s.theme);
|
||||
const setTheme = useAppPreferencesStore((s) => s.setTheme);
|
||||
const setShowStructure = useAppPreferencesStore((s) => s.setShowStructure);
|
||||
|
||||
useEffect(() => {
|
||||
hydrate();
|
||||
}, [hydrate]);
|
||||
|
||||
useEffect(() => {
|
||||
applyTheme(theme);
|
||||
}, [theme]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
||||
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
const onChange = () => {
|
||||
const current = useAppPreferencesStore.getState().theme;
|
||||
if (current === "system") {
|
||||
applyTheme("system");
|
||||
}
|
||||
};
|
||||
mq.addEventListener?.("change", onChange);
|
||||
return () => mq.removeEventListener?.("change", onChange);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const isEditableTarget = (target: EventTarget | null) => {
|
||||
const el = target as HTMLElement | null;
|
||||
if (!el) return false;
|
||||
const tag = String(el.tagName ?? "").toLowerCase();
|
||||
if (tag === "input" || tag === "textarea" || tag === "select") return true;
|
||||
return Boolean(el.isContentEditable);
|
||||
};
|
||||
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
if (isEditableTarget(event.target)) {
|
||||
// 保留 Wolai 的快捷键体验,但不打断输入法/编辑器输入。
|
||||
return;
|
||||
}
|
||||
const ctrlOrMeta = event.ctrlKey || event.metaKey;
|
||||
const key = String(event.key ?? "").toLowerCase();
|
||||
|
||||
// Wolai:ctrl/cmd + shift + U 显示/隐藏块结构虚线框
|
||||
if (ctrlOrMeta && event.shiftKey && key === "u") {
|
||||
event.preventDefault();
|
||||
const { showStructure } = useAppPreferencesStore.getState();
|
||||
setShowStructure(!showStructure);
|
||||
return;
|
||||
}
|
||||
|
||||
// Wolai:ctrl/cmd + alt/opt + G 打开/关闭 Good Night 模式
|
||||
if (ctrlOrMeta && event.altKey && key === "g") {
|
||||
event.preventDefault();
|
||||
const current = useAppPreferencesStore.getState().theme;
|
||||
setTheme(current === "dark" ? "light" : "dark");
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
return () => window.removeEventListener("keydown", onKeyDown);
|
||||
}, [setShowStructure, setTheme]);
|
||||
|
||||
// hydrated 仅用于触发一次 render,避免被 tree-shaking 误删
|
||||
if (!hydrated) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user