mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-11-13 12:13:42 +01:00
182 lines
5.5 KiB
TypeScript
182 lines
5.5 KiB
TypeScript
import { useQuery } from "@tanstack/react-query";
|
|
import { getVersion } from "@tauri-apps/api/app";
|
|
import { appDataDir, appLogDir } from "@tauri-apps/api/path";
|
|
import {
|
|
Dialog,
|
|
EmptyStateText,
|
|
SETTINGS_TAB_GENERAL,
|
|
SETTINGS_TAB_INTERFACE,
|
|
SETTINGS_TAB_LICENSE,
|
|
SETTINGS_TAB_THEME,
|
|
type SettingsCallbacks,
|
|
SettingsDialog,
|
|
SettingsGeneral,
|
|
SettingsInterface,
|
|
SettingsTheme,
|
|
} from "@yaakapp-internal/ui";
|
|
import { atom, useAtom, useSetAtom } from "jotai";
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import { settingsValuesAtom } from "../lib/interfaceSettings";
|
|
import { openLink, revealPath } from "../lib/opener";
|
|
import { proxySettingsView } from "../lib/settings";
|
|
import { getOsType } from "../lib/tauri";
|
|
import { useShowToast } from "../lib/toast";
|
|
import { SettingsProxy } from "./SettingsProxy";
|
|
|
|
export const SETTINGS_TAB_PROXY = "proxy";
|
|
|
|
/** The settings window is open, on a tab, or closed */
|
|
export const settingsOpenAtom = atom<string | null>(null);
|
|
|
|
/**
|
|
* Yaak's settings, shared: its General, Theme, Interface and License tabs, plus the proxy's own
|
|
* Proxy tab. The header's gear and `⌘,` open it.
|
|
*/
|
|
export function SettingsWindow() {
|
|
const [tab, setTab] = useAtom(settingsOpenAtom);
|
|
useSettingsHotkey();
|
|
return (
|
|
<Dialog
|
|
open={tab != null}
|
|
onClose={() => setTab(null)}
|
|
size="lg"
|
|
noPadding
|
|
noScroll
|
|
className="h-[min(44rem,90vh)]"
|
|
>
|
|
{tab != null && <SettingsContent defaultTab={tab} />}
|
|
</Dialog>
|
|
);
|
|
}
|
|
|
|
/** The settings themselves, as the window holds them */
|
|
export function SettingsContent({ defaultTab }: { defaultTab: string }) {
|
|
const [values, change] = useAtom(settingsValuesAtom);
|
|
const app = useAppInfo();
|
|
const systemAppearance = useSystemAppearance();
|
|
const view = useMemo(
|
|
() => proxySettingsView(values, app, systemAppearance),
|
|
[values, app, systemAppearance],
|
|
);
|
|
const showToast = useShowToast();
|
|
const callbacks = useMemo<SettingsCallbacks>(() => {
|
|
const fail = (message: string) => showToast({ message, color: "danger" });
|
|
return {
|
|
onChange: (patch) => change(patch),
|
|
// The proxy draws its own title bar always; the row isn't shown
|
|
onApplyNativeTitlebar: (useNativeTitlebar) => change({ useNativeTitlebar }),
|
|
onCheckForUpdates: () => undefined,
|
|
onActivateLicense: async () => undefined,
|
|
onDeactivateLicense: () => undefined,
|
|
onOpenUrl: (url) => void openLink(url, fail),
|
|
onRevealPath: (path) => void revealPath(path, fail),
|
|
pricingUrl: (intent) => `https://yaak.app/pricing?intent=${encodeURIComponent(intent)}`,
|
|
};
|
|
}, [change, showToast]);
|
|
const props = { view, callbacks };
|
|
|
|
return (
|
|
<SettingsDialog
|
|
titlebar={null}
|
|
defaultTab={defaultTab}
|
|
tabs={[
|
|
{
|
|
value: SETTINGS_TAB_GENERAL,
|
|
label: "General",
|
|
icon: "settings",
|
|
content: <SettingsGeneral {...props} />,
|
|
},
|
|
{
|
|
value: SETTINGS_TAB_THEME,
|
|
label: "Theme",
|
|
icon: "palette",
|
|
content: <SettingsTheme {...props} />,
|
|
},
|
|
{
|
|
value: SETTINGS_TAB_INTERFACE,
|
|
label: "Interface",
|
|
icon: "columns_2",
|
|
content: <SettingsInterface {...props} />,
|
|
},
|
|
{
|
|
value: SETTINGS_TAB_PROXY,
|
|
label: "Proxy",
|
|
icon: "wifi",
|
|
content: <SettingsProxy />,
|
|
},
|
|
{
|
|
value: SETTINGS_TAB_LICENSE,
|
|
label: "License",
|
|
icon: "key_round",
|
|
content: <EmptyStateText>Coming soon</EmptyStateText>,
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
}
|
|
|
|
/** `⌘,`, or `Ctrl+,` off macOS, opens settings, as in Yaak */
|
|
function useSettingsHotkey() {
|
|
const setOpen = useSetAtom(settingsOpenAtom);
|
|
useEffect(() => {
|
|
const mac = getOsType() === "macos";
|
|
function onKeyDown(e: KeyboardEvent) {
|
|
if (e.key !== "," || e.shiftKey || e.altKey) return;
|
|
if (mac ? !e.metaKey || e.ctrlKey : !e.ctrlKey || e.metaKey) return;
|
|
e.preventDefault();
|
|
setOpen((tab) => tab ?? SETTINGS_TAB_GENERAL);
|
|
}
|
|
window.addEventListener("keydown", onKeyDown);
|
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
}, [setOpen]);
|
|
}
|
|
|
|
function useAppInfo() {
|
|
const os = getOsType();
|
|
const { data } = useQuery({
|
|
queryKey: ["settings_app_info"],
|
|
queryFn: async () => {
|
|
const [version, dataDir, logDir] = await Promise.all([
|
|
getVersion(),
|
|
appDataDir(),
|
|
appLogDir(),
|
|
]);
|
|
return { version, dataDir, logDir };
|
|
},
|
|
retry: false,
|
|
});
|
|
return useMemo(
|
|
() => ({
|
|
name: "Yaak Proxy",
|
|
version: data?.version ?? "",
|
|
dataDir: data?.dataDir ?? "",
|
|
logDir: data?.logDir ?? "",
|
|
revealPathLabel:
|
|
os === "macos"
|
|
? "Reveal in Finder"
|
|
: os === "windows"
|
|
? "Show in Explorer"
|
|
: "Show in Folder",
|
|
}),
|
|
[data, os],
|
|
);
|
|
}
|
|
|
|
function useSystemAppearance(): "light" | "dark" {
|
|
const query = "(prefers-color-scheme: dark)";
|
|
const [dark, setDark] = useState(() => window.matchMedia(query).matches);
|
|
useEffect(() => {
|
|
const media = window.matchMedia(query);
|
|
const onChange = () => setDark(media.matches);
|
|
media.addEventListener("change", onChange);
|
|
return () => media.removeEventListener("change", onChange);
|
|
}, []);
|
|
return dark ? "dark" : "light";
|
|
}
|
|
|
|
/** Opens settings on a tab */
|
|
export function useOpenSettings() {
|
|
const setOpen = useSetAtom(settingsOpenAtom);
|
|
return (tab: string = SETTINGS_TAB_GENERAL) => setOpen(tab);
|
|
}
|