Style new series form with proper fields and layout
Replace the bare name input with a note textarea and interval
picker (count + unit). Clean up form CSS: smaller h1, more flow
space, grid layout for fields, hidden number spinners, full-width
submit button.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
diff --git a/lib/views/series/new.rb b/lib/views/series/new.rb
index 299bb96..e87f363 100644
--- a/lib/views/series/new.rb
+++ b/lib/views/series/new.rb
@@ -17,8 +17,26 @@ module Views
h1 { "New Series" }
form(method: "post", action: "/series") do
- label(for: "name") { "Name" }
- input(type: "text", id: "name", name: "name", required: true)
+ div(class: "field") do
+ label(for: "note") { "Note" }
+ textarea(id: "note", name: "note", rows: 3, required: true)
+ end
+
+ div(class: "field") do
+ label(for: "interval_count") { "Repeat every" }
+ div(class: "interval") do
+ input(
+ type: "number", id: "interval_count", name: "interval_count",
+ min: 1, value: 1, required: true
+ )
+ select(id: "interval_unit", name: "interval_unit", required: true) do
+ option(value: "day") { "day(s)" }
+ option(value: "week") { "week(s)" }
+ option(value: "month") { "month(s)" }
+ option(value: "year") { "year(s)" }
+ end
+ end
+ end
button(type: "submit") { "Create" }
end
diff --git a/public/css/app.css b/public/css/app.css
index 9c61cf4..0aba9cd 100644
--- a/public/css/app.css
+++ b/public/css/app.css
@@ -2,10 +2,8 @@
/* Utilities */
/* -------------------- */
-/* Flow — vertical rhythm via Utopia space tokens */
-/* @link https://piccalil.li/blog/my-favourite-3-lines-of-css/ */
.flow > * + * {
- margin-block-start: var(--flow-space, var(--space-s));
+ margin-block-start: var(--flow-space, var(--space-m));
}
.u-container {
@@ -14,11 +12,6 @@
margin-inline: auto;
}
-.u-grid {
- display: grid;
- gap: var(--grid-gutter);
-}
-
/* -------------------- */
/* Global styles */
/* -------------------- */
@@ -26,11 +19,12 @@
body {
font-family: system-ui, sans-serif;
font-size: var(--step-0);
+ line-height: 1.5;
color: #1a1a1a;
background: #fafafa;
}
-h1 { font-size: var(--step-3); }
+h1 { font-size: var(--step-2); }
/* -------------------- */
/* Site header */
@@ -58,7 +52,7 @@ h1 { font-size: var(--step-3); }
/* -------------------- */
.wrapper {
- max-width: 32rem;
+ max-width: 28rem;
margin-inline: auto;
padding: var(--space-l) var(--grid-gutter);
}
@@ -68,31 +62,70 @@ h1 { font-size: var(--step-3); }
/* -------------------- */
form {
- display: flex;
- flex-direction: column;
- gap: var(--space-2xs);
+ display: grid;
+ gap: var(--space-m);
+}
+
+.field {
+ display: grid;
+ gap: var(--space-3xs);
}
label {
+ font-size: var(--step--1);
font-weight: 600;
+ color: #444;
}
-input {
- padding: var(--space-3xs) var(--space-2xs);
+input,
+textarea,
+select {
+ padding: var(--space-2xs);
border: 1px solid #ccc;
- border-radius: 4px;
+ border-radius: 6px;
+ font: inherit;
+ background: #fff;
+}
+
+input[type="number"] {
+ -moz-appearance: textfield;
}
-button {
- align-self: start;
- padding: var(--space-3xs) var(--space-s);
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+
+input:focus,
+textarea:focus,
+select:focus {
+ outline: 2px solid #1a1a1a;
+ outline-offset: 1px;
+ border-color: #1a1a1a;
+}
+
+textarea {
+ resize: vertical;
+}
+
+.interval {
+ display: grid;
+ grid-template-columns: 5rem 1fr;
+ gap: var(--space-3xs);
+}
+
+button[type="submit"] {
+ padding: var(--space-2xs) var(--space-m);
border: none;
- border-radius: 4px;
+ border-radius: 6px;
background: #1a1a1a;
color: #fff;
+ font: inherit;
+ font-weight: 600;
cursor: pointer;
}
-button:hover {
+button[type="submit"]:hover {
background: #333;
}
diff --git a/test/test_web.rb b/test/test_web.rb
index 0fade8b..420b484 100644
--- a/test/test_web.rb
+++ b/test/test_web.rb
@@ -16,7 +16,9 @@ class TestWeb < Minitest::Test
get "/", {}, tailscale_headers
assert last_response.ok?
assert_includes last_response.body, '<form method="post" action="/series">'
- assert_includes last_response.body, 'name="name"'
+ assert_includes last_response.body, 'name="note"'
+ assert_includes last_response.body, 'name="interval_count"'
+ assert_includes last_response.body, 'name="interval_unit"'
end
def test_root_shows_current_user