feat(webui): add performance profile selector to config page
- commit
- 74a67e9ae5d4eb254b9d844247c08ee53808d39d
- author
- brice · · 2025-12-28 19:23 UTC
- committer
- brice · · 2025-12-29 17:28 UTC
- parent
- cf39998
- signature
- unsigned
1 file · +68 -0
M webui/src/pages/ConfigPage.svelte +68 -0
| @@ -26,6 +26,10 @@ | |||
| 26 | 26 | description: string; | |
| 27 | 27 | }; | |
| 28 | 28 | ||
| 29 | + | type PerformanceConfig = { | |
| 30 | + | profile: string; | |
| 31 | + | }; | |
| 32 | + | ||
| 29 | 33 | type ConfigDTO = { | |
| 30 | 34 | appearance: { | |
| 31 | 35 | sans_font: string; | |
| @@ -36,11 +40,19 @@ | |||
| 36 | 40 | light_palette: ColorPalette; | |
| 37 | 41 | dark_palette: ColorPalette; | |
| 38 | 42 | }; | |
| 43 | + | performance: PerformanceConfig; | |
| 39 | 44 | default_ui_scale: number; | |
| 40 | 45 | default_search_engine: string; | |
| 41 | 46 | search_shortcuts: Record<string, SearchShortcut>; | |
| 42 | 47 | }; | |
| 43 | 48 | ||
| 49 | + | const PERFORMANCE_PROFILES = [ | |
| 50 | + | { value: "default", label: "Default", description: "No tuning, uses WebKit defaults. Recommended for most users." }, | |
| 51 | + | { value: "lite", label: "Lite", description: "Reduced resource usage for low-RAM systems (< 4GB) or battery saving." }, | |
| 52 | + | { value: "max", label: "Max", description: "Maximum responsiveness for heavy pages (GitHub PRs, complex SPAs)." }, | |
| 53 | + | { value: "custom", label: "Custom", description: "Manual control via config file. Edit config.toml to set individual values." }, | |
| 54 | + | ]; | |
| 55 | + | ||
| 44 | 56 | const PALETTE_FIELDS: Array<{ key: keyof ColorPalette; label: string }> = [ | |
| 45 | 57 | { key: "background", label: "Background" }, | |
| 46 | 58 | { key: "surface", label: "Surface" }, | |
| @@ -250,6 +262,7 @@ | |||
| 250 | 262 | <Tabs.List class="bg-muted/60"> | |
| 251 | 263 | <Tabs.Trigger value="appearance">Appearance</Tabs.Trigger> | |
| 252 | 264 | <Tabs.Trigger value="search">Search</Tabs.Trigger> | |
| 265 | + | <Tabs.Trigger value="performance">Performance</Tabs.Trigger> | |
| 253 | 266 | </Tabs.List> | |
| 254 | 267 | </div> | |
| 255 | 268 | ||
| @@ -374,6 +387,61 @@ | |||
| 374 | 387 | </Card.Content> | |
| 375 | 388 | </Card.Root> | |
| 376 | 389 | </Tabs.Content> | |
| 390 | + | ||
| 391 | + | <Tabs.Content value="performance"> | |
| 392 | + | <Card.Root class="rounded-none border-0 bg-transparent py-0 shadow-none"> | |
| 393 | + | <Card.Header> | |
| 394 | + | <Card.Title>Performance Profile</Card.Title> | |
| 395 | + | <Card.Description> | |
| 396 | + | WebKitGTK rendering and memory tuning presets. | |
| 397 | + | </Card.Description> | |
| 398 | + | </Card.Header> | |
| 399 | + | <Card.Content class="space-y-6"> | |
| 400 | + | <!-- Restart warning banner --> | |
| 401 | + | <div class="flex items-start gap-3 rounded-md border border-amber-500/30 bg-amber-500/10 px-4 py-3"> | |
| 402 | + | <span class="text-amber-500">⚠</span> | |
| 403 | + | <div class="space-y-1"> | |
| 404 | + | <p class="text-sm font-medium text-amber-500">Restart Required</p> | |
| 405 | + | <p class="text-xs text-muted-foreground"> | |
| 406 | + | Performance settings are applied at browser startup. Changes will take effect after restarting Dumber. | |
| 407 | + | </p> | |
| 408 | + | </div> | |
| 409 | + | </div> | |
| 410 | + | ||
| 411 | + | <!-- Profile selector --> | |
| 412 | + | <div class="space-y-4"> | |
| 413 | + | {#each PERFORMANCE_PROFILES as profile (profile.value)} | |
| 414 | + | <label | |
| 415 | + | class="flex cursor-pointer items-start gap-4 rounded-md border p-4 transition-colors hover:bg-muted/50 {config.performance.profile === profile.value ? 'border-primary bg-primary/5' : ''}" | |
| 416 | + | > | |
| 417 | + | <input | |
| 418 | + | type="radio" | |
| 419 | + | name="performance_profile" | |
| 420 | + | value={profile.value} | |
| 421 | + | checked={config.performance.profile === profile.value} | |
| 422 | + | onchange={() => config!.performance.profile = profile.value} | |
| 423 | + | class="mt-1 accent-primary" | |
| 424 | + | /> | |
| 425 | + | <div class="space-y-1"> | |
| 426 | + | <div class="font-medium">{profile.label}</div> | |
| 427 | + | <div class="text-sm text-muted-foreground">{profile.description}</div> | |
| 428 | + | </div> | |
| 429 | + | </label> | |
| 430 | + | {/each} | |
| 431 | + | </div> | |
| 432 | + | ||
| 433 | + | <!-- Custom profile note --> | |
| 434 | + | {#if config.performance.profile === "custom"} | |
| 435 | + | <div class="rounded-md border border-border bg-muted/30 px-4 py-3 text-sm text-muted-foreground"> | |
| 436 | + | <p> | |
| 437 | + | Custom profile settings are configured in your <code class="rounded bg-muted px-1 py-0.5">config.toml</code> file. | |
| 438 | + | See the <a href="https://github.com/bnema/dumber/blob/main/docs/CONFIG.md#performance-profiles" target="_blank" class="text-primary underline">documentation</a> for available options. | |
| 439 | + | </p> | |
| 440 | + | </div> | |
| 441 | + | {/if} | |
| 442 | + | </Card.Content> | |
| 443 | + | </Card.Root> | |
| 444 | + | </Tabs.Content> | |
| 377 | 445 | </Tabs.Root> | |
| 378 | 446 | ||
| 379 | 447 | <div class="flex flex-wrap items-center justify-between gap-4 border-t border-border px-6 py-4"> | |
| @@ -26,6 +26,10 @@ | |||||
| 26 | description: string; | 26 | description: string; | ||
| 27 | }; | 27 | }; | ||
| 28 | 28 | ||||
| 29 | + | type PerformanceConfig = { | |||
| 30 | + | profile: string; | |||
| 31 | + | }; | |||
| 32 | + | ||||
| 29 | type ConfigDTO = { | 33 | type ConfigDTO = { | ||
| 30 | appearance: { | 34 | appearance: { | ||
| 31 | sans_font: string; | 35 | sans_font: string; | ||
| @@ -36,11 +40,19 @@ | |||||
| 36 | light_palette: ColorPalette; | 40 | light_palette: ColorPalette; | ||
| 37 | dark_palette: ColorPalette; | 41 | dark_palette: ColorPalette; | ||
| 38 | }; | 42 | }; | ||
| 43 | + | performance: PerformanceConfig; | |||
| 39 | default_ui_scale: number; | 44 | default_ui_scale: number; | ||
| 40 | default_search_engine: string; | 45 | default_search_engine: string; | ||
| 41 | search_shortcuts: Record<string, SearchShortcut>; | 46 | search_shortcuts: Record<string, SearchShortcut>; | ||
| 42 | }; | 47 | }; | ||
| 43 | 48 | ||||
| 49 | + | const PERFORMANCE_PROFILES = [ | |||
| 50 | + | { value: "default", label: "Default", description: "No tuning, uses WebKit defaults. Recommended for most users." }, | |||
| 51 | + | { value: "lite", label: "Lite", description: "Reduced resource usage for low-RAM systems (< 4GB) or battery saving." }, | |||
| 52 | + | { value: "max", label: "Max", description: "Maximum responsiveness for heavy pages (GitHub PRs, complex SPAs)." }, | |||
| 53 | + | { value: "custom", label: "Custom", description: "Manual control via config file. Edit config.toml to set individual values." }, | |||
| 54 | + | ]; | |||
| 55 | + | ||||
| 44 | const PALETTE_FIELDS: Array<{ key: keyof ColorPalette; label: string }> = [ | 56 | const PALETTE_FIELDS: Array<{ key: keyof ColorPalette; label: string }> = [ | ||
| 45 | { key: "background", label: "Background" }, | 57 | { key: "background", label: "Background" }, | ||
| 46 | { key: "surface", label: "Surface" }, | 58 | { key: "surface", label: "Surface" }, | ||
| @@ -250,6 +262,7 @@ | |||||
| 250 | <Tabs.List class="bg-muted/60"> | 262 | <Tabs.List class="bg-muted/60"> | ||
| 251 | <Tabs.Trigger value="appearance">Appearance</Tabs.Trigger> | 263 | <Tabs.Trigger value="appearance">Appearance</Tabs.Trigger> | ||
| 252 | <Tabs.Trigger value="search">Search</Tabs.Trigger> | 264 | <Tabs.Trigger value="search">Search</Tabs.Trigger> | ||
| 265 | + | <Tabs.Trigger value="performance">Performance</Tabs.Trigger> | |||
| 253 | </Tabs.List> | 266 | </Tabs.List> | ||
| 254 | </div> | 267 | </div> | ||
| 255 | 268 | ||||
| @@ -374,6 +387,61 @@ | |||||
| 374 | </Card.Content> | 387 | </Card.Content> | ||
| 375 | </Card.Root> | 388 | </Card.Root> | ||
| 376 | </Tabs.Content> | 389 | </Tabs.Content> | ||
| 390 | + | ||||
| 391 | + | <Tabs.Content value="performance"> | |||
| 392 | + | <Card.Root class="rounded-none border-0 bg-transparent py-0 shadow-none"> | |||
| 393 | + | <Card.Header> | |||
| 394 | + | <Card.Title>Performance Profile</Card.Title> | |||
| 395 | + | <Card.Description> | |||
| 396 | + | WebKitGTK rendering and memory tuning presets. | |||
| 397 | + | </Card.Description> | |||
| 398 | + | </Card.Header> | |||
| 399 | + | <Card.Content class="space-y-6"> | |||
| 400 | + | <!-- Restart warning banner --> | |||
| 401 | + | <div class="flex items-start gap-3 rounded-md border border-amber-500/30 bg-amber-500/10 px-4 py-3"> | |||
| 402 | + | <span class="text-amber-500">⚠</span> | |||
| 403 | + | <div class="space-y-1"> | |||
| 404 | + | <p class="text-sm font-medium text-amber-500">Restart Required</p> | |||
| 405 | + | <p class="text-xs text-muted-foreground"> | |||
| 406 | + | Performance settings are applied at browser startup. Changes will take effect after restarting Dumber. | |||
| 407 | + | </p> | |||
| 408 | + | </div> | |||
| 409 | + | </div> | |||
| 410 | + | ||||
| 411 | + | <!-- Profile selector --> | |||
| 412 | + | <div class="space-y-4"> | |||
| 413 | + | {#each PERFORMANCE_PROFILES as profile (profile.value)} | |||
| 414 | + | <label | |||
| 415 | + | class="flex cursor-pointer items-start gap-4 rounded-md border p-4 transition-colors hover:bg-muted/50 {config.performance.profile === profile.value ? 'border-primary bg-primary/5' : ''}" | |||
| 416 | + | > | |||
| 417 | + | <input | |||
| 418 | + | type="radio" | |||
| 419 | + | name="performance_profile" | |||
| 420 | + | value={profile.value} | |||
| 421 | + | checked={config.performance.profile === profile.value} | |||
| 422 | + | onchange={() => config!.performance.profile = profile.value} | |||
| 423 | + | class="mt-1 accent-primary" | |||
| 424 | + | /> | |||
| 425 | + | <div class="space-y-1"> | |||
| 426 | + | <div class="font-medium">{profile.label}</div> | |||
| 427 | + | <div class="text-sm text-muted-foreground">{profile.description}</div> | |||
| 428 | + | </div> | |||
| 429 | + | </label> | |||
| 430 | + | {/each} | |||
| 431 | + | </div> | |||
| 432 | + | ||||
| 433 | + | <!-- Custom profile note --> | |||
| 434 | + | {#if config.performance.profile === "custom"} | |||
| 435 | + | <div class="rounded-md border border-border bg-muted/30 px-4 py-3 text-sm text-muted-foreground"> | |||
| 436 | + | <p> | |||
| 437 | + | Custom profile settings are configured in your <code class="rounded bg-muted px-1 py-0.5">config.toml</code> file. | |||
| 438 | + | See the <a href="https://github.com/bnema/dumber/blob/main/docs/CONFIG.md#performance-profiles" target="_blank" class="text-primary underline">documentation</a> for available options. | |||
| 439 | + | </p> | |||
| 440 | + | </div> | |||
| 441 | + | {/if} | |||
| 442 | + | </Card.Content> | |||
| 443 | + | </Card.Root> | |||
| 444 | + | </Tabs.Content> | |||
| 377 | </Tabs.Root> | 445 | </Tabs.Root> | ||
| 378 | 446 | ||||
| 379 | <div class="flex flex-wrap items-center justify-between gap-4 border-t border-border px-6 py-4"> | 447 | <div class="flex flex-wrap items-center justify-between gap-4 border-t border-border px-6 py-4"> | ||