Fix the settings tabs, and space a form from what follows it
**The Audio tab rendered nothing.** The tabs are radios plus sibling selectors, and the CSS named every tab twice -- once to highlight its label, once to show its panel. A tab added without also adding those two rules gets a label that selects nothing, which is not something anyone catches in review; it looks like a blank page. Replaced with rules that derive what they can. The active label is `input:checked + .tabs__tab`, which needs to know nothing at all. The panel is matched by position -- CSS cannot compare a radio's id with a panel's data-tab -- so the Nth radio shows the Nth panel. Both lists render in the same order and a conditional tab drops out of both at once, so they cannot drift. There is a test asserting the two orders match, including with Audio absent. **A card following a form sat flush against Save.** The "Try it" panel on the search page read as another field of the settings form. The gap belongs to the form rather than to its action row: the action row is always its form's last child, so a bottom margin there has nothing to push away from. Adds `.form-actions` and a bottom margin on a form that is a direct child of an admin page. Also says plainly in the dictation settings that a server hosting one model ignores the model field, so `whisper-1` there is a label rather than a selection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -298,6 +298,43 @@ def test_the_audio_tab_appears_only_once_audio_is_configured(
|
||||
assert "tab-audio" in client.get("/settings").text
|
||||
|
||||
|
||||
def _tab_lists(html: str) -> tuple[list[str], list[str]]:
|
||||
import re
|
||||
|
||||
return (
|
||||
re.findall(r'<input[^>]*name="settings-tab"[^>]*id="(tab-[a-z]+)"', html),
|
||||
re.findall(r'<section class="tabs__panel" data-tab="(tab-[a-z]+)"', html),
|
||||
)
|
||||
|
||||
|
||||
def test_every_settings_tab_has_a_panel_in_the_same_position(
|
||||
client: TestClient, db, registered
|
||||
):
|
||||
"""The tabs are radios plus sibling selectors, and CSS cannot compare a
|
||||
radio's id with a panel's data-tab -- the link is positional. A tab whose
|
||||
panel is somewhere else in the order silently shows the wrong one, and a tab
|
||||
with no panel shows a blank page. Neither is visible in review."""
|
||||
settings_store.update(
|
||||
db,
|
||||
{"tts_enabled": True, "tts_base_url": "http://tts", "stt_enabled": True},
|
||||
key=settings_store.AUDIO,
|
||||
)
|
||||
tabs, panels = _tab_lists(client.get("/settings").text)
|
||||
|
||||
assert tabs, "no tabs were found; the markup must have changed"
|
||||
assert tabs == panels
|
||||
|
||||
|
||||
def test_the_positions_still_line_up_when_a_conditional_tab_is_absent(
|
||||
client: TestClient, registered
|
||||
):
|
||||
"""Audio only appears once it is configured. It has to drop out of both
|
||||
lists at once or everything after it shifts by one."""
|
||||
tabs, panels = _tab_lists(client.get("/settings").text)
|
||||
assert "tab-audio" not in tabs
|
||||
assert tabs == panels
|
||||
|
||||
|
||||
def test_saving_audio_preferences(client: TestClient, db, registered):
|
||||
client.post(
|
||||
"/api/preferences/audio",
|
||||
|
||||
Reference in New Issue
Block a user