webui: move video source out of Advanced, give lyrics a tall column

This commit is contained in:
2026-07-27 22:51:36 -07:00
parent a650c2f7ec
commit 5bc4855264
2 changed files with 58 additions and 20 deletions
+17 -5
View File
@@ -194,6 +194,9 @@ body {
}
#song-form { display: grid; gap: 18px; }
.song-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.song-form-main { display: grid; gap: 18px; align-content: start; }
.song-form-lyrics textarea { height: 100%; flex: 1 1 auto; }
.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field > span {
@@ -220,7 +223,6 @@ input:not([type="file"]):hover { border-bottom-color: var(--text-muted); }
input:not([type="file"]):focus { border-bottom-color: var(--aqua); }
textarea {
min-height: 8.5rem;
padding: 11px 13px;
line-height: 1.6;
background: var(--panel);
@@ -229,6 +231,7 @@ textarea {
}
textarea:hover { border-color: var(--text-muted); }
textarea:focus { border-color: var(--aqua); }
.song-form-lyrics textarea { min-height: 8.5rem; }
input[type="file"] {
font-size: 0.82rem;
@@ -464,6 +467,11 @@ button { cursor: pointer; }
#stage-track { margin-left: 0; flex-wrap: wrap; }
}
@media (max-width: 720px) {
.song-form-grid { grid-template-columns: 1fr; }
.song-form-lyrics textarea { height: auto; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation: none !important; transition: none !important; }
}
@@ -486,17 +494,18 @@ button { cursor: pointer; }
<section id="new-song">
<h2>NEW SONG</h2>
<form id="song-form">
<div class="song-form-grid">
<div class="song-form-main">
<div class="pair">
<label class="field"><span>Title</span><input name="title" required></label>
<label class="field"><span>Artist</span><input name="artist" required></label>
</div>
<label class="field"><span>Lyrics</span><textarea name="lyrics" required></textarea></label>
<details>
<summary>Advanced</summary>
<div class="stack">
<label class="field"><span>YouTube URL</span><input name="youtube_url"></label>
<label class="field"><span>Video file</span><input type="file" name="video"></label>
<p class="keep-note" data-keep="video" hidden></p>
<details>
<summary>Advanced</summary>
<div class="stack">
<div class="pair">
<label class="field"><span>Genre</span><input name="genre"></label>
<label class="field"><span>Year</span><input name="year" type="number"></label>
@@ -509,6 +518,9 @@ button { cursor: pointer; }
<p class="keep-note" data-keep="cover" hidden></p>
</div>
</details>
</div>
<label class="field song-form-lyrics"><span>Lyrics</span><textarea name="lyrics" required></textarea></label>
</div>
<div class="form-actions">
<button type="submit" class="primary">CREATE SONG</button>
<button type="button" id="cancel-rebuild" hidden>CANCEL</button>
+26
View File
@@ -359,6 +359,32 @@ def test_index_has_required_hooks():
assert f'name="{name}"' in html, name
def test_video_source_fields_are_outside_advanced_details():
html = _index_html()
form_start = html.index('id="song-form"')
details_start = html.index("<details>", form_start)
before = html[form_start:details_start]
assert 'name="youtube_url"' in before
assert 'name="video"' in before
after = html[details_start:]
for name in ("genre", "year", "language", "bpm", "cover"):
assert f'name="{name}"' in after
def test_song_form_lyrics_uses_a_two_column_grid():
css = _page_css(_index_html())
assert re.search(r"\.song-form-grid\s*\{[^}]*grid-template-columns:\s*1fr 1fr",
css, re.S)
def test_song_form_grid_stacks_on_narrow_screens():
css = _page_css(_index_html())
assert re.search(
r"@media \(max-width: 720px\)\s*\{[^}]*\.song-form-grid\s*\{[^}]*"
r"grid-template-columns:\s*1fr\s*;",
css, re.S)
def test_index_makes_no_external_requests():
import re as _re
html = _index_html()