Settings: db-viewer redesign, theme/accent wiring, macOS overlay titlebar (#6)
* feat: settings back button returns to origin view (push/pop nav) * feat: redesign settings screen with db-viewer border styling * fix: settings sidebar — icon+text tabs, back at top, top border (PR feedback) * fix: tighten settings sidebar — back and tabs in one group * fix: settings header shows active tab name instead of duplicated title * fix: settings — accent back button, header shows active tab; fix App test * fix: tags settings — no create label, no card chrome (bg/border/padding) * feat: drag-and-drop tag reordering in settings tags tab * fix: general settings — remove section card chrome (bg/border/padding) * fix: merge Appearance and Interface into one settings section * fix: remove row separators between settings items within sections * fix: settings rows use gap spacing instead of per-row padding * feat: strip section cards from all settings tabs; delete SettingsSection * feat: apply theme and font size settings (appearance wiring) * feat: honor default folder setting on startup * feat: confirm_before_delete setting now skips delete confirmations * feat: default_ports setting prefills new connection forms * fix: light theme — text colors, native window chrome, ThemePicker preview * fix: sync window background color with theme so title bar follows light mode * fix: window-sync test uses microtask flush instead of vi.waitFor * fix: app root carries canvas bg so home-screen parent matches theme * fix: grant window set-theme/set-background-color permissions so title bar follows theme * fix: overlay title bar — webview paints under traffic lights, flat canvas color in both themes * fix: compact 28px overlay titlebar with visible bottom border * fix: in-flow titlebar strip (draggable via allowed permission); screens fill remaining height, no bottom clipping * fix: top border only on settings + db viewer pages, not the titlebar strip * fix: db viewer sidebar h-screen -> h-full (28px overflow clipped bottom icons) * fix: system theme resets window to OS before reading matchMedia (was polluted by forced window theme) * fix: theme switcher labels moved below previews for readability * feat: configurable accent color setting (circle palette in Appearance) * docs: update AGENTS.md + README for settings redesign, wired settings, accent color
This commit is contained in:
+68
-33
@@ -9,6 +9,7 @@ import { NewConnectionScreen } from "./components/connections/NewConnectionScree
|
||||
import { ErrorBanner } from "./components/ui/ErrorBanner";
|
||||
import { ToastContainer } from "./components/ui/Toast";
|
||||
import { DbViewerScreen } from "./components/db-viewer/DbViewerScreen";
|
||||
import { useAppearance } from "./hooks/useAppearance";
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
|
||||
const VIEW_TITLES: Record<string, string> = {
|
||||
@@ -21,8 +22,11 @@ const VIEW_TITLES: Record<string, string> = {
|
||||
export default function App() {
|
||||
const activeView = useUiStore((s) => s.activeView);
|
||||
const setActiveView = useUiStore((s) => s.setActiveView);
|
||||
const settingsReturnView = useUiStore((s) => s.settingsReturnView);
|
||||
const openSettings = useUiStore((s) => s.openSettings);
|
||||
const loadConnections = useConnectionStore((s) => s.loadAll);
|
||||
const loadSettings = useSettingsStore((s) => s.load);
|
||||
const settings = useSettingsStore((s) => s.settings);
|
||||
const connectionError = useConnectionStore((s) => s.error);
|
||||
const activeFolderId = useUiStore((s) => s.activeFolderId);
|
||||
const folders = useConnectionStore((s) => s.folders);
|
||||
@@ -30,6 +34,8 @@ export default function App() {
|
||||
const prefilledConnectionString = useUiStore((s) => s.prefilledConnectionString);
|
||||
const clearPrefilledConnectionString = useUiStore((s) => s.clearPrefilledConnectionString);
|
||||
|
||||
useAppearance(settings?.theme ?? "system", settings?.font_size ?? "medium", settings?.accent_color ?? "#2563EB");
|
||||
|
||||
useEffect(() => {
|
||||
loadConnections();
|
||||
loadSettings();
|
||||
@@ -37,6 +43,16 @@ export default function App() {
|
||||
useBackupStore.getState().initListener().catch(() => {});
|
||||
}, [loadConnections, loadSettings]);
|
||||
|
||||
// If the user hasn't navigated anywhere yet, start in the configured default folder
|
||||
const setActiveFolderId = useUiStore((s) => s.setActiveFolderId);
|
||||
const defaultFolderId = settings?.default_folder_id;
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultFolderId && useUiStore.getState().activeFolderId === null) {
|
||||
setActiveFolderId(defaultFolderId);
|
||||
}
|
||||
}, [defaultFolderId, setActiveFolderId]);
|
||||
|
||||
useEffect(() => {
|
||||
let title = VIEW_TITLES[activeView] ?? "Gridline";
|
||||
if (activeView === "db-viewer") {
|
||||
@@ -55,41 +71,60 @@ export default function App() {
|
||||
}
|
||||
}, [activeView]);
|
||||
|
||||
const keepDbViewerMounted =
|
||||
activeView === "db-viewer" ||
|
||||
(activeView === "settings" && settingsReturnView === "db-viewer");
|
||||
const dbViewerVisible = activeView === "db-viewer";
|
||||
|
||||
return (
|
||||
<div className="min-h-svh select-none">
|
||||
{connectionError && (
|
||||
<div className="px-6 pt-4">
|
||||
<ErrorBanner
|
||||
error={connectionError}
|
||||
onRetry={loadConnections}
|
||||
<div className="h-svh bg-canvas select-none flex flex-col overflow-hidden">
|
||||
{typeof window !== "undefined" &&
|
||||
"__TAURI_INTERNALS__" in window && (
|
||||
// macOS "Overlay" title bar: in-flow strip the window can be
|
||||
// dragged by; traffic lights float over it. Only in Tauri.
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
aria-hidden
|
||||
className="h-7 shrink-0 bg-canvas select-none"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{activeView === "settings" && <SettingsPage />}
|
||||
{activeView === "new-connection" && (
|
||||
<NewConnectionScreen
|
||||
defaultFolderId={activeFolderId}
|
||||
prefilledConnectionString={prefilledConnectionString ?? ""}
|
||||
folders={folders}
|
||||
tags={tags}
|
||||
onSaved={() => {
|
||||
clearPrefilledConnectionString();
|
||||
setActiveView("home");
|
||||
}}
|
||||
onCancel={() => {
|
||||
clearPrefilledConnectionString();
|
||||
setActiveView("home");
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{activeView === "home" && <HomeScreen />}
|
||||
{activeView === "db-viewer" && (
|
||||
<DbViewerScreen
|
||||
connectionId={useUiStore.getState().activeConnectionId ?? ""}
|
||||
onHome={() => setActiveView("home")}
|
||||
onSettings={() => setActiveView("settings")}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
<div className="flex-1 min-h-0">
|
||||
{connectionError && (
|
||||
<div className="px-6 pt-4">
|
||||
<ErrorBanner
|
||||
error={connectionError}
|
||||
onRetry={loadConnections}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{activeView === "settings" && <SettingsPage />}
|
||||
{activeView === "new-connection" && (
|
||||
<NewConnectionScreen
|
||||
defaultFolderId={activeFolderId}
|
||||
prefilledConnectionString={prefilledConnectionString ?? ""}
|
||||
folders={folders}
|
||||
tags={tags}
|
||||
onSaved={() => {
|
||||
clearPrefilledConnectionString();
|
||||
setActiveView("home");
|
||||
}}
|
||||
onCancel={() => {
|
||||
clearPrefilledConnectionString();
|
||||
setActiveView("home");
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{activeView === "home" && <HomeScreen />}
|
||||
{keepDbViewerMounted && (
|
||||
<div className={dbViewerVisible ? "contents" : "hidden"}>
|
||||
<DbViewerScreen
|
||||
connectionId={useUiStore.getState().activeConnectionId ?? ""}
|
||||
onHome={() => setActiveView("home")}
|
||||
onSettings={openSettings}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ToastContainer />
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user