feat(host): user-defined custom display presets

Save named bundles of the display-management policy (the six behavior axes
plus the game-session axis) as custom presets, alongside the built-ins. A
custom preset is data — stored in <config>/display-presets.json — not a Preset
enum variant, so DisplayPolicy::effective() stays pure and the built-in set is
untouched; applying one writes a Custom policy via the existing PUT
/display/settings.

- policy.rs: CustomPreset/CustomPresetInput + load/add/update/delete store
- mgmt.rs: GET/POST /display/presets + PUT/DELETE /display/presets/{id},
  surfaced on GET /display/settings
- web console: custom-preset cards with save-as / edit / delete + i18n
- regenerated api/openapi.json; docs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 10:33:16 +00:00
parent 077d8f85ca
commit a4f81dec48
7 changed files with 796 additions and 4 deletions
+7
View File
@@ -108,6 +108,13 @@
"display_layout_help": "Auto lays displays out side by side, left to right. Manual: you position each one yourself — a per-display X/Y editor appears in the Live displays section below once two or more are streaming.",
"display_layout_auto_row": "Auto (side by side)",
"display_layout_manual": "Manual",
"display_preset_custom_label": "Custom presets",
"display_preset_save_as": "Save as preset…",
"display_preset_name": "Preset name",
"display_preset_edit": "Rename",
"display_preset_update": "Update to current settings",
"display_preset_delete": "Delete",
"display_preset_delete_confirm": "Delete this custom preset?",
"clients_title": "Paired clients",
"clients_empty": "No paired clients yet.",
"clients_name": "Name",