From 1290122e5762c881758906723b495991b674cb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kacprzak?= Date: Mon, 3 Aug 2026 01:11:22 +0200 Subject: [PATCH] Improve single camera GUI layout --- frigate_camera_control_bridge/static/app.css | 42 ++++++++++++++++++- .../templates/index.html | 2 +- frigate_camera_control_bridge/ui.py | 2 + tests/test_ui_render.py | 1 + 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/frigate_camera_control_bridge/static/app.css b/frigate_camera_control_bridge/static/app.css index 7c3d4d3..34e15ab 100644 --- a/frigate_camera_control_bridge/static/app.css +++ b/frigate_camera_control_bridge/static/app.css @@ -99,8 +99,14 @@ select { .control-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, 310px), 1fr)); + grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 420px)); gap: 16px; + justify-content: center; + align-items: start; +} + +.grid-single { + grid-template-columns: minmax(0, 860px); } .camera-card { @@ -114,6 +120,17 @@ select { box-shadow: var(--shadow); } +.grid-single .camera-card { + display: grid; + grid-template-columns: minmax(320px, 1.1fr) minmax(300px, 0.9fr); +} + +.grid-single .media { + height: 100%; + min-height: 320px; + aspect-ratio: auto; +} + .media { position: relative; aspect-ratio: 16 / 9; @@ -209,6 +226,11 @@ select { padding: 15px; } +.grid-single .card-body { + justify-content: center; + padding: 18px; +} + .card-main { min-width: 0; } @@ -232,6 +254,10 @@ h2 { gap: 11px; } +.grid-single .control-stack { + gap: 12px; +} + .action-control { display: grid; gap: 10px; @@ -491,6 +517,20 @@ h3 { width: 100%; } + .grid-single, + .control-grid { + grid-template-columns: 1fr; + } + + .grid-single .camera-card { + display: flex; + } + + .grid-single .media { + min-height: 0; + aspect-ratio: 16 / 9; + } + select { max-width: 60%; } diff --git a/frigate_camera_control_bridge/templates/index.html b/frigate_camera_control_bridge/templates/index.html index ec2df91..644f239 100644 --- a/frigate_camera_control_bridge/templates/index.html +++ b/frigate_camera_control_bridge/templates/index.html @@ -25,7 +25,7 @@ -
+
{cards}
diff --git a/frigate_camera_control_bridge/ui.py b/frigate_camera_control_bridge/ui.py index 8bf0fd5..fcd53e9 100644 --- a/frigate_camera_control_bridge/ui.py +++ b/frigate_camera_control_bridge/ui.py @@ -293,6 +293,7 @@ def render_page(actions, lang, token_param=None): cards_markup = "".join(cards) if not cards_markup and not global_markup: cards_markup = f'
{html.escape(text_for(lang, "no_actions"))}
' + grid_class = "control-grid grid-single" if len(groups) == 1 else "control-grid" token_input = ( f'' if token_param @@ -308,5 +309,6 @@ def render_page(actions, lang, token_param=None): language_options=render_language_options(lang), token_input=token_input, global_actions=global_markup, + grid_class=html.escape(grid_class), cards=cards_markup, ) diff --git a/tests/test_ui_render.py b/tests/test_ui_render.py index 527240e..9e3f2a1 100644 --- a/tests/test_ui_render.py +++ b/tests/test_ui_render.py @@ -45,6 +45,7 @@ class UiRenderTest(unittest.TestCase): html = render_page(actions, "en") + self.assertIn('class="control-grid grid-single"', html) self.assertEqual(html.count('class="camera-card"'), 1) self.assertEqual(html.count('class="action-control"'), 3) self.assertIn("3 controls", html)