diff --git a/frontend/src/lib/nav.ts b/frontend/src/lib/nav.ts new file mode 100644 index 0000000..bced4f0 --- /dev/null +++ b/frontend/src/lib/nav.ts @@ -0,0 +1,3 @@ +/** Sidebar page switch. Set from +page.svelte; views call it to jump. */ +export type Navigate = (page: string) => void; +export const NAVIGATE_KEY = "bos-settings-navigate"; diff --git a/frontend/src/lib/sidebar.ts b/frontend/src/lib/sidebar.ts index 7d98ce6..c9f6740 100644 --- a/frontend/src/lib/sidebar.ts +++ b/frontend/src/lib/sidebar.ts @@ -31,6 +31,16 @@ import Lock from "@lucide/svelte/icons/lock"; import Camera from "@lucide/svelte/icons/camera"; import AppWindow from "@lucide/svelte/icons/app-window"; import CircleHelp from "@lucide/svelte/icons/circle-help"; +import Download from "@lucide/svelte/icons/download"; +import Printer from "@lucide/svelte/icons/printer"; +import ShieldEllipsis from "@lucide/svelte/icons/shield-ellipsis"; +import Moon from "@lucide/svelte/icons/moon"; +import Languages from "@lucide/svelte/icons/languages"; +import Accessibility from "@lucide/svelte/icons/accessibility"; +import AppWindowMac from "@lucide/svelte/icons/app-window-mac"; +import GitBranch from "@lucide/svelte/icons/git-branch"; +import Archive from "@lucide/svelte/icons/archive"; +import Boxes from "@lucide/svelte/icons/boxes"; export interface SidebarItem { /** Must match a key in the view component map (see routing in +page.svelte). */ @@ -45,15 +55,20 @@ export interface SidebarItem { export const SYSTEM_ITEMS: SidebarItem[] = [ { id: "network", label: "Network", icon: Wifi }, { id: "breadcrumbs", label: "Wi-Fi Profiles", sublabel: "breadcrumbs", icon: Network }, + { id: "vpn", label: "VPN / WireGuard", sublabel: "NetworkManager", icon: ShieldEllipsis }, { id: "bluetooth", label: "Bluetooth", icon: Bluetooth }, + { id: "printing", label: "Printing", sublabel: "CUPS", icon: Printer }, { id: "firewall", label: "Firewall", icon: Shield }, { id: "sound", label: "Sound", icon: Volume2 }, { id: "power", label: "Power", icon: BatteryFull }, { id: "datetime", label: "Date & Time", icon: Clock }, { id: "hyprland", label: "Display", sublabel: "monitors.json", icon: Monitor }, + { id: "nightlight", label: "Night light", sublabel: "hyprsunset", icon: Moon }, { id: "breadmon", label: "Monitors", sublabel: "breadmon", icon: AppWindow }, { id: "breadlock", label: "Lock & greet", sublabel: "breadlock", icon: Lock }, { id: "keybinds", label: "Keybinds", sublabel: "binds.json", icon: Keyboard }, + { id: "ime", label: "Input method", sublabel: "fcitx5", icon: Languages }, + { id: "accessibility", label: "Accessibility", icon: Accessibility }, { id: "breadshot", label: "Screenshots", sublabel: "breadshot", icon: Camera }, { id: "autostart", label: "Startup Apps", sublabel: "autostart.json", icon: Rocket }, { id: "users", label: "Users", icon: Users }, @@ -67,14 +82,19 @@ export const PERSONALIZATION_ITEMS: SidebarItem[] = [ { id: "breadclip", label: "Clipboard", sublabel: "breadclipd", icon: Clipboard }, { id: "breadpad", label: "Notes", sublabel: "breadpad", icon: NotebookPen }, { id: "breadsearch", label: "File Search", sublabel: "breadsearch", icon: Search }, + { id: "defaults", label: "Default apps", sublabel: "mimeapps.list", icon: AppWindowMac }, { id: "bread", label: "Daemon", sublabel: "breadd", icon: Cog }, ]; export const MAINTENANCE_ITEMS: SidebarItem[] = [ + { id: "updates", label: "Updates", icon: Download }, { id: "packages", label: "Packages", icon: Package }, { id: "aur", label: "AUR", icon: Search }, { id: "firmware", label: "Firmware", icon: RefreshCw }, { id: "snapshots", label: "Snapshots", icon: History }, + { id: "channel", label: "Bakery channel", sublabel: "track", icon: GitBranch }, + { id: "backup", label: "Backup", sublabel: "restic", icon: Archive }, + { id: "optional", label: "Optional software", icon: Boxes }, ]; export const ABOUT_ITEMS: SidebarItem[] = [ diff --git a/frontend/src/lib/views/Accessibility.svelte b/frontend/src/lib/views/Accessibility.svelte new file mode 100644 index 0000000..02bb427 --- /dev/null +++ b/frontend/src/lib/views/Accessibility.svelte @@ -0,0 +1,197 @@ + + + + + {#if !st} + + {:else if !st.orca_installed} + + + {:else} +
+ Orca + +
+ {/if} +
+ + + {#if st} + + + + {#if !st.kmag_installed} + + + {:else} + + {/if} + {/if} + + + + {#if st} +
+ Sticky keys + +
+
+ Slow keys + +
+ + {/if} +
+ {#if message}{/if} + +
+ + diff --git a/frontend/src/lib/views/Backup.svelte b/frontend/src/lib/views/Backup.svelte new file mode 100644 index 0000000..b650c30 --- /dev/null +++ b/frontend/src/lib/views/Backup.svelte @@ -0,0 +1,254 @@ + + + + + {#if !st} + + {:else if !st.restic_installed} + + + {:else} + + + + + {/if} + + + +
+ + + +
+ {#if message}{/if} +
+ + + +
+ + +
+
+ + + {#if snapshots.length === 0} + + {:else} +
+ {#each snapshots as s (s.id)} + + {/each} +
+ {/if} +
+ +
+ + diff --git a/frontend/src/lib/views/Channel.svelte b/frontend/src/lib/views/Channel.svelte new file mode 100644 index 0000000..a49c439 --- /dev/null +++ b/frontend/src/lib/views/Channel.svelte @@ -0,0 +1,127 @@ + + + + + {#if !track} + + {:else} +
+ {#each track.tracks as name (name)} + + {/each} +
+ + {/if} + + {#if message}{/if} +
+ +
+ + diff --git a/frontend/src/lib/views/Defaults.svelte b/frontend/src/lib/views/Defaults.svelte new file mode 100644 index 0000000..0fd2927 --- /dev/null +++ b/frontend/src/lib/views/Defaults.svelte @@ -0,0 +1,104 @@ + + + + + {#if st} + {#each CATEGORIES as cat (cat.id)} +
+ {cat.label} + +
+ {/each} + + {:else} + + {/if} +
+
+ + diff --git a/frontend/src/lib/views/InputMethod.svelte b/frontend/src/lib/views/InputMethod.svelte new file mode 100644 index 0000000..ef99f54 --- /dev/null +++ b/frontend/src/lib/views/InputMethod.svelte @@ -0,0 +1,166 @@ + + + + + {#if !st} + + {:else} +
+ Enable fcitx5 for this session + +
+ + + {/if} + {#if message}{/if} +
+ + + {#if st} + + {/if} + {#if missing.length} + + {/if} + + +
+ + diff --git a/frontend/src/lib/views/NightLight.svelte b/frontend/src/lib/views/NightLight.svelte new file mode 100644 index 0000000..13ec93f --- /dev/null +++ b/frontend/src/lib/views/NightLight.svelte @@ -0,0 +1,145 @@ + + + + + {#if !st} + + {:else if !st.installed} + + + {:else} +
+ Night light + +
+ + + + {/if} + {#if message}{/if} +
+ +
+ + diff --git a/frontend/src/lib/views/Optional.svelte b/frontend/src/lib/views/Optional.svelte new file mode 100644 index 0000000..3fbfcf0 --- /dev/null +++ b/frontend/src/lib/views/Optional.svelte @@ -0,0 +1,149 @@ + + + + + {#if !st} + + {:else} + {#each st.items as item (item.id)} +
+
+ {item.title} +

{item.detail}

+ {item.via}{item.installed ? " · installed" : ""} +
+ {#if item.installed} + Installed + {:else} + + {/if} +
+ {/each} + {/if} + {#if message}{/if} +
+ +
+ + diff --git a/frontend/src/lib/views/Printing.svelte b/frontend/src/lib/views/Printing.svelte new file mode 100644 index 0000000..2fc3ac5 --- /dev/null +++ b/frontend/src/lib/views/Printing.svelte @@ -0,0 +1,147 @@ + + + + + {#if !status} + + {:else if status.error} + + {:else if status.printers.length === 0} + + {:else} +
+ {#each status.printers as p (p.name)} +
+
+ {p.name}{p.is_default ? " (default)" : ""} + {p.enabled ? p.status : "disabled"} +
+ +
+ {/each} +
+ {/if} +
+ + +
+ {#if message}{/if} +
+ + + + + + +
+ + diff --git a/frontend/src/lib/views/Snapshots.svelte b/frontend/src/lib/views/Snapshots.svelte index 8687a00..6834326 100644 --- a/frontend/src/lib/views/Snapshots.svelte +++ b/frontend/src/lib/views/Snapshots.svelte @@ -42,7 +42,7 @@ if (!selected) return; if ( confirm( - `Boot into snapshot #${selected}? Snapshots on BOS are booted directly from the GRUB menu (under "BOS snapshots"), not rolled back in place. Reboot now and pick this snapshot there.`, + `Reboot to pick snapshot #${selected} in GRUB? BOS boots snapshots from the GRUB “BOS snapshots” submenu. This does not run snapper rollback.`, ) ) { invoke("reboot_system"); @@ -62,9 +62,10 @@ +
@@ -75,6 +76,11 @@ {:else if snapshots.length === 0} {:else} + {#each snapshots as snap (snap.number)} - +
@@ -121,7 +127,15 @@ min-width: 0; } - .row:hover { + .row.header { + background: transparent; + cursor: default; + opacity: 0.55; + font-size: var(--font-size-secondary, 12px); + padding-top: 0; + } + + .row:hover:not(.header) { background-color: color-mix(in srgb, var(--surface), var(--on-surface) 8%); } diff --git a/frontend/src/lib/views/Updates.svelte b/frontend/src/lib/views/Updates.svelte new file mode 100644 index 0000000..7e16970 --- /dev/null +++ b/frontend/src/lib/views/Updates.svelte @@ -0,0 +1,253 @@ + + + + {#if status?.nvidia} + +
+ +
+ {status.nvidia.gpu} +

{status.nvidia.reason}

+ {#if status.nvidia.installed} + + {:else} + + {/if} +
+ +
+
+ {/if} + + + {#if !status} + + {:else if status.pacman_error} + + {:else if status.pacman.length === 0} + + {:else} +
+ {#each status.pacman as pkg (pkg.name)} +
+ {pkg.name} + {pkg.current} → {pkg.latest} +
+ {/each} +
+ {/if} +
+ + +
+
+ + + {#if !status} + + {:else if status.bakery_error} + + {:else if status.bakery.length === 0} + + {:else} +
+ {#each status.bakery as pkg (pkg.name)} +
+ {pkg.name} + {pkg.current ? `${pkg.current} → ` : ""}{pkg.latest} + +
+ {/each} +
+ {/if} +
+ +
+
+ + + {#if !status} + + {:else if status.firmware.length === 0} + + {:else} +
+ {#each status.firmware as dev (dev.name)} +
+ {dev.name} + {dev.version} +
+ {/each} +
+ {/if} +
+ + +
+
+ + + + +
+ +
+
+ + +
+ + diff --git a/frontend/src/lib/views/Vpn.svelte b/frontend/src/lib/views/Vpn.svelte new file mode 100644 index 0000000..7bf4102 --- /dev/null +++ b/frontend/src/lib/views/Vpn.svelte @@ -0,0 +1,148 @@ + + + + + {#if !status} + + {:else if status.error} + + {:else if status.connections.length === 0} + + {:else} +
+ {#each status.connections as c (c.name)} +
+
+ {c.name} + {c.kind}{c.active ? " · connected" : ""}{c.autoconnect ? " · autoconnect" : ""} +
+ {#if c.active} + + {:else} + + {/if} +
+ {/each} +
+ {/if} + + {#if message}{/if} +
+ + + + + +
+ + diff --git a/frontend/src/lib/views/registry.ts b/frontend/src/lib/views/registry.ts index ee0e5e4..6a87bbf 100644 --- a/frontend/src/lib/views/registry.ts +++ b/frontend/src/lib/views/registry.ts @@ -30,6 +30,16 @@ import Breadlock from "./Breadlock.svelte"; import Breadshot from "./Breadshot.svelte"; import Breadmon from "./Breadmon.svelte"; import Breadhelp from "./Breadhelp.svelte"; +import Updates from "./Updates.svelte"; +import Printing from "./Printing.svelte"; +import Vpn from "./Vpn.svelte"; +import NightLight from "./NightLight.svelte"; +import InputMethod from "./InputMethod.svelte"; +import Accessibility from "./Accessibility.svelte"; +import Defaults from "./Defaults.svelte"; +import Channel from "./Channel.svelte"; +import Backup from "./Backup.svelte"; +import Optional from "./Optional.svelte"; export const VIEWS: Record = { about: About, @@ -60,4 +70,14 @@ export const VIEWS: Record = { breadshot: Breadshot, breadmon: Breadmon, breadhelp: Breadhelp, + updates: Updates, + printing: Printing, + vpn: Vpn, + nightlight: NightLight, + ime: InputMethod, + accessibility: Accessibility, + defaults: Defaults, + channel: Channel, + backup: Backup, + optional: Optional, }; diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 22b7a6c..e43cb01 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -1,14 +1,18 @@