feat(settings): reorganize preferences pages
Split Settings into General, Media, Updates & Setup, Storage, and AI Workspace pages so update/setup and maintenance controls are easier to reach. Move runtime check results beside the model runtime controls instead of under model location.
This commit is contained in:
@@ -6,10 +6,13 @@ import { getChangelogForVersion } from "../changelog";
|
|||||||
import { Tooltip } from "./Tooltip";
|
import { Tooltip } from "./Tooltip";
|
||||||
import { TAGGER_MODELS } from "../taggerModels";
|
import { TAGGER_MODELS } from "../taggerModels";
|
||||||
|
|
||||||
type SettingsSection = "workspace" | "general";
|
type SettingsSection = "general" | "media" | "updates" | "storage" | "workspace";
|
||||||
|
|
||||||
const SECTIONS: { id: SettingsSection; label: string; detail: string }[] = [
|
const SECTIONS: { id: SettingsSection; label: string; detail: string }[] = [
|
||||||
{ id: "general", label: "General", detail: "App data and diagnostics" },
|
{ id: "general", label: "General", detail: "Theme and notifications" },
|
||||||
|
{ id: "media", label: "Media", detail: "Playback and slideshow" },
|
||||||
|
{ id: "updates", label: "Updates & Setup", detail: "Versions, setup, and tour" },
|
||||||
|
{ id: "storage", label: "Storage", detail: "App data and maintenance" },
|
||||||
{ id: "workspace", label: "AI Workspace", detail: "Tagging models and queue targets" },
|
{ id: "workspace", label: "AI Workspace", detail: "Tagging models and queue targets" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -267,7 +270,7 @@ export function SettingsModal() {
|
|||||||
}, [settingsOpen, loadTaggerModelStatus, loadTaggerModel, loadTaggerAcceleration, loadTaggerThreshold, loadTaggerBatchSize, loadTaggingQueueScope, loadTaggingQueueFolderIds, setSettingsOpen]);
|
}, [settingsOpen, loadTaggerModelStatus, loadTaggerModel, loadTaggerAcceleration, loadTaggerThreshold, loadTaggerBatchSize, loadTaggingQueueScope, loadTaggingQueueFolderIds, setSettingsOpen]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!settingsOpen || activeSection !== "general") return;
|
if (!settingsOpen || activeSection !== "storage") return;
|
||||||
setVacuumResult(null);
|
setVacuumResult(null);
|
||||||
setThumbnailCleanupResult(null);
|
setThumbnailCleanupResult(null);
|
||||||
void getDatabaseInfo().then(setDbInfo).catch(() => {});
|
void getDatabaseInfo().then(setDbInfo).catch(() => {});
|
||||||
@@ -289,6 +292,7 @@ export function SettingsModal() {
|
|||||||
|
|
||||||
if (!settingsOpen) return null;
|
if (!settingsOpen) return null;
|
||||||
|
|
||||||
|
const activeSectionMeta = SECTIONS.find((section) => section.id === activeSection) ?? SECTIONS[0];
|
||||||
const taggerReady = taggerModelStatus?.ready ?? false;
|
const taggerReady = taggerModelStatus?.ready ?? false;
|
||||||
const queueScopeLabel =
|
const queueScopeLabel =
|
||||||
taggingQueueScope === "all"
|
taggingQueueScope === "all"
|
||||||
@@ -445,8 +449,8 @@ export function SettingsModal() {
|
|||||||
|
|
||||||
<main className="min-w-0 flex-1 overflow-y-auto">
|
<main className="min-w-0 flex-1 overflow-y-auto">
|
||||||
<div className="px-10 py-8">
|
<div className="px-10 py-8">
|
||||||
<h3 className="text-lg font-semibold text-white">{activeSection === "workspace" ? "AI Workspace" : "General"}</h3>
|
<h3 className="text-lg font-semibold text-white">{activeSectionMeta.label}</h3>
|
||||||
<p className="mt-1 text-xs text-gray-600">{activeSection === "workspace" ? "Model setup and queue targets" : "App data and diagnostics"}</p>
|
<p className="mt-1 text-xs text-gray-600">{activeSectionMeta.detail}</p>
|
||||||
|
|
||||||
{activeSection === "workspace" ? (
|
{activeSection === "workspace" ? (
|
||||||
<div className="mt-8 space-y-9">
|
<div className="mt-8 space-y-9">
|
||||||
@@ -496,6 +500,7 @@ export function SettingsModal() {
|
|||||||
}
|
}
|
||||||
description={TAGGER_MODELS[taggerModel].description}
|
description={TAGGER_MODELS[taggerModel].description}
|
||||||
>
|
>
|
||||||
|
<div className="flex flex-col items-end gap-1.5">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{taggerReady ? (
|
{taggerReady ? (
|
||||||
<>
|
<>
|
||||||
@@ -525,6 +530,16 @@ export function SettingsModal() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{taggerRuntimeProbe ? (
|
||||||
|
<div className="text-right">
|
||||||
|
<p className="text-xs text-gray-400">
|
||||||
|
Runtime check <span className="ml-1.5 align-middle"><StatusPill tone="ready">Ready</StatusPill></span>
|
||||||
|
{" "}<span className="ml-2 text-gray-600">· acceleration: {taggerRuntimeProbe.acceleration}</span>
|
||||||
|
</p>
|
||||||
|
<p className="mt-1 break-all font-mono text-xs text-gray-600">{taggerRuntimeProbe.session.file}</p>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
|
|
||||||
<SettingsItem label="Tagger acceleration" description="Use DirectML when available, or fall back to CPU for reliability.">
|
<SettingsItem label="Tagger acceleration" description="Use DirectML when available, or fall back to CPU for reliability.">
|
||||||
@@ -636,15 +651,6 @@ export function SettingsModal() {
|
|||||||
</p>
|
</p>
|
||||||
{taggerModelProgress?.current_file ? <p className="mt-2 break-all text-xs text-gray-500">{taggerModelProgress.current_file}</p> : null}
|
{taggerModelProgress?.current_file ? <p className="mt-2 break-all text-xs text-gray-500">{taggerModelProgress.current_file}</p> : null}
|
||||||
{taggerModelError ? <p className="mt-2 text-xs text-amber-300">{taggerModelError}</p> : null}
|
{taggerModelError ? <p className="mt-2 text-xs text-amber-300">{taggerModelError}</p> : null}
|
||||||
{taggerRuntimeProbe ? (
|
|
||||||
<div className="mt-3">
|
|
||||||
<p className="text-xs text-gray-400">
|
|
||||||
Runtime check <span className="ml-1.5 align-middle"><StatusPill tone="ready">Ready</StatusPill></span>
|
|
||||||
<span className="ml-2 text-gray-600">acceleration: {taggerRuntimeProbe.acceleration}</span>
|
|
||||||
</p>
|
|
||||||
<p className="mt-1.5 break-all font-mono text-xs text-gray-600">{taggerRuntimeProbe.session.file}</p>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
@@ -766,6 +772,8 @@ export function SettingsModal() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-8 space-y-9">
|
<div className="mt-8 space-y-9">
|
||||||
|
{activeSection === "general" ? (
|
||||||
|
<>
|
||||||
<SettingsGroup title="Appearance">
|
<SettingsGroup title="Appearance">
|
||||||
<SettingsItem label="Theme" description="Choose the app palette. Subtle Light uses a warm, low-glare background.">
|
<SettingsItem label="Theme" description="Choose the app palette. Subtle Light uses a warm, low-glare background.">
|
||||||
<ThemedDropdown
|
<ThemedDropdown
|
||||||
@@ -781,6 +789,39 @@ export function SettingsModal() {
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<SettingsGroup title="Notifications">
|
||||||
|
<SettingsItem
|
||||||
|
label="Pause all notifications"
|
||||||
|
description="Notifications are batched per folder — a single alert fires once activity settles. Mute individual folders from their right-click menu."
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
role="switch"
|
||||||
|
aria-checked={notificationsPaused}
|
||||||
|
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none ${notificationsPaused ? "bg-sky-500" : "bg-white/15"}`}
|
||||||
|
onClick={() => setNotificationsPaused(!notificationsPaused)}
|
||||||
|
>
|
||||||
|
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${notificationsPaused ? "translate-x-4" : "translate-x-0"}`} />
|
||||||
|
</button>
|
||||||
|
</SettingsItem>
|
||||||
|
<SettingsItem
|
||||||
|
label="Keep background pauses after restart"
|
||||||
|
description="When enabled, folders you pause from the sidebar or background bar stay paused the next time Phokus opens."
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
role="switch"
|
||||||
|
aria-checked={workerPausesPersist}
|
||||||
|
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none ${workerPausesPersist ? "bg-sky-500" : "bg-white/15"}`}
|
||||||
|
onClick={() => setWorkerPausesPersist(!workerPausesPersist)}
|
||||||
|
>
|
||||||
|
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${workerPausesPersist ? "translate-x-4" : "translate-x-0"}`} />
|
||||||
|
</button>
|
||||||
|
</SettingsItem>
|
||||||
|
</SettingsGroup>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{activeSection === "media" ? (
|
||||||
|
<>
|
||||||
<SettingsGroup title="Video playback">
|
<SettingsGroup title="Video playback">
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
label="Autoplay in lightbox"
|
label="Autoplay in lightbox"
|
||||||
@@ -859,6 +900,11 @@ export function SettingsModal() {
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{activeSection === "updates" ? (
|
||||||
|
<>
|
||||||
<SettingsGroup title="Updates">
|
<SettingsGroup title="Updates">
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
label={
|
label={
|
||||||
@@ -953,7 +999,12 @@ export function SettingsModal() {
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup title="Storage & notifications">
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{activeSection === "storage" ? (
|
||||||
|
<>
|
||||||
|
<SettingsGroup title="App data">
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
label="App data folder"
|
label="App data folder"
|
||||||
description="Open the folder in Explorer to inspect or back up the database, thumbnails, and models."
|
description="Open the folder in Explorer to inspect or back up the database, thumbnails, and models."
|
||||||
@@ -969,32 +1020,6 @@ export function SettingsModal() {
|
|||||||
{openingDataFolder ? "Opening..." : "Open data folder"}
|
{openingDataFolder ? "Opening..." : "Open data folder"}
|
||||||
</button>
|
</button>
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
<SettingsItem
|
|
||||||
label="Pause all notifications"
|
|
||||||
description="Notifications are batched per folder — a single alert fires once activity settles. Mute individual folders from their right-click menu."
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
role="switch"
|
|
||||||
aria-checked={notificationsPaused}
|
|
||||||
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none ${notificationsPaused ? "bg-sky-500" : "bg-white/15"}`}
|
|
||||||
onClick={() => setNotificationsPaused(!notificationsPaused)}
|
|
||||||
>
|
|
||||||
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${notificationsPaused ? "translate-x-4" : "translate-x-0"}`} />
|
|
||||||
</button>
|
|
||||||
</SettingsItem>
|
|
||||||
<SettingsItem
|
|
||||||
label="Keep background pauses after restart"
|
|
||||||
description="When enabled, folders you pause from the sidebar or background bar stay paused the next time Phokus opens."
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
role="switch"
|
|
||||||
aria-checked={workerPausesPersist}
|
|
||||||
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none ${workerPausesPersist ? "bg-sky-500" : "bg-white/15"}`}
|
|
||||||
onClick={() => setWorkerPausesPersist(!workerPausesPersist)}
|
|
||||||
>
|
|
||||||
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${workerPausesPersist ? "translate-x-4" : "translate-x-0"}`} />
|
|
||||||
</button>
|
|
||||||
</SettingsItem>
|
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup title="Maintenance">
|
<SettingsGroup title="Maintenance">
|
||||||
@@ -1151,6 +1176,8 @@ export function SettingsModal() {
|
|||||||
</button>
|
</button>
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user