import { useEffect, useState } from "react";
import { LOCALE_OPTIONS, useI18n, type Locale } from "./i18n";
import { persistTheme, readTheme, THEME_PREFS, type ThemePref } from "./theme";
export const APP_NAME = "LazyBoy";
export const APP_VERSION = "0.1.0";
export type SettingsSectionId = "general" | "updates";
const SECTIONS: readonly { id: SettingsSectionId; icon: "gear" | "download" }[] = [
{ id: "general", icon: "gear" },
{ id: "updates", icon: "download" },
];
export type SettingsComputer = {
pending: "start" | "restart" | "update" | null;
working: boolean;
upToDate: boolean;
onUpdate: () => void;
onRestart: () => void;
};
function detectOs(): string {
const ua = navigator.userAgent;
if (/Mac/i.test(ua)) return "darwin";
if (/Win/i.test(ua)) return "win32";
if (/Linux/i.test(ua)) return "linux";
return navigator.platform || "unknown";
}
function GearIcon() {
return (
);
}
function DownloadIcon() {
return (
);
}
function CloseIcon() {
return (
);
}
function SettingsGroup({ title, children }: { title: string; children: React.ReactNode }) {
return (
);
}
function OverlayShell({
label,
className,
onClose,
children,
}: {
label: string;
className: string;
onClose: () => void;
children: React.ReactNode;
}) {
return (
event.stopPropagation()}
>
{children}
);
}
function GeneralPanel() {
const { locale, setLocale, t } = useI18n();
const [theme, setTheme] = useState(readTheme);
return (
GB
{t.localWorkspace}
{t.workspaceDetail}
);
}
function ComputerRow({
label,
description,
extra,
control,
}: {
label: string;
description: string;
extra: string | null;
control: React.ReactNode;
}) {
return (
{label}
{description}
{extra ? {extra} : null}
{control}
);
}
function UpdatesPanel({ computer }: { computer?: SettingsComputer }) {
const { t } = useI18n();
const pending = computer?.pending ?? null;
const disabled = Boolean(pending);
const busyCopy = computer?.working ? t.computerBusyCopy : null;
return (
{APP_NAME} {APP_VERSION}
{t.localBuild}
{computer ? (
{computer.upToDate ? (
{t.computerUpToDate}
{t.computerUpdateCopy}
{busyCopy ? {busyCopy} : null}
) : (
{pending === "update" ? t.computerUpdating : t.update}
}
/>
)}
{pending === "restart" ? t.computerRestarting : t.restart}
}
/>
) : null}
);
}
export function SettingsDialog({ onClose, computer }: { onClose: () => void; computer?: SettingsComputer }) {
const { t } = useI18n();
const [section, setSection] = useState("general");
const headingId = `lb-settings-heading-${section}`;
const panelId = `lb-settings-panel-${section}`;
const sectionLabel = section === "general" ? t.general : t.updates;
return (
{sectionLabel}
{section === "general" ? : }
);
}
export function AboutDialog({ onClose }: { onClose: () => void }) {
const { t, format } = useI18n();
const [copied, setCopied] = useState(false);
const [copyGeneration, setCopyGeneration] = useState(0);
useEffect(() => {
if (!copied) return;
const timeout = window.setTimeout(() => setCopied(false), 1200);
return () => window.clearTimeout(timeout);
}, [copied, copyGeneration]);
const copyVersion = async () => {
try {
await navigator.clipboard.writeText([
`Version: ${APP_VERSION}`,
`OS: ${detectOs()}`,
].join("\n"));
setCopied(true);
setCopyGeneration((n) => n + 1);
} catch {
/* leave the action idle, matching grok-bot */
}
};
return (
{APP_NAME}
{format("versionLine", { version: APP_VERSION })}
{t.copyright}
);
}