fabrica

hanna/fabrica

fix(web): repo tabs, topbar search input, square avatars, form spacing

701baaf · hanna committed on 2026-07-25

Give .repo-tabs (and a shared .subnav) real tab styling — the rules were
scoped to .topbar .tabs a, so the repo sub-nav rendered as mashed-together
links. Replace the top-bar search icon with a growing search input, lay the
/search results box out inline (button to the right of the input), square
off avatars with rounded corners, and space card-form submit buttons.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed by hannaSSH key fingerprint: SHA256:4g9cWhkAAw8gwqhJUcVbSnGEvdGwklW+1Aa/fMUu59k
10 files changed · +109 −9UnifiedSplit
assets/base.css +81 −5
@@ -118,6 +118,24 @@ code, pre, .mono {
118 background: var(--fb-bg-inset);118 background: var(--fb-bg-inset);
119}119}
120120
121/* Top-bar search: a growing input with an inline submit icon. */
122.topbar-search {
123 display: flex;
124 align-items: center;
125 gap: 0.25rem;
126 flex: 1;
127 max-width: 34rem;
128 margin: 0 auto;
129}
130.topbar-search input[type="search"] {
131 width: 100%;
132 padding: 0.3rem 0.6rem;
133 background: var(--fb-bg-inset);
134 border: 1px solid var(--fb-border);
135 border-radius: var(--fb-radius);
136 color: var(--fb-fg);
137}
138
121.icon-btn {139.icon-btn {
122 display: inline-flex;140 display: inline-flex;
123 align-items: center;141 align-items: center;
@@ -274,6 +292,11 @@ select:focus {
274 outline: none;292 outline: none;
275}293}
276294
295/* Submit buttons in a card form get breathing room from the last field. */
296.card form button[type="submit"] {
297 margin-top: 1.1rem;
298}
299
277/* Centered auth card (sign in, invite activation). */300/* Centered auth card (sign in, invite activation). */
278.auth-wrap {301.auth-wrap {
279 display: flex;302 display: flex;
@@ -338,6 +361,20 @@ select:focus {
338 color: var(--fb-fg-muted);361 color: var(--fb-fg-muted);
339}362}
340363
364/* Inline search row: input grows, button sits to its right with margin. */
365.search-row {
366 display: flex;
367 align-items: stretch;
368 gap: 0.6rem;
369 margin: 0.75rem 0 1.25rem;
370}
371.search-row input[type="search"] {
372 flex: 1;
373}
374.search-row .btn {
375 flex: none;
376}
377
341/* ---- Repo/list rows ---- */378/* ---- Repo/list rows ---- */
342.listing {379.listing {
343 margin-bottom: 1.5rem;380 margin-bottom: 1.5rem;
@@ -397,18 +434,27 @@ select:focus {
397434
398/* ---- Avatars & profile header ---- */435/* ---- Avatars & profile header ---- */
399.avatar {436.avatar {
400 border-radius: 50%;437 border-radius: 6px;
401 object-fit: cover;438 object-fit: cover;
402 background: var(--fb-bg-inset);439 background: var(--fb-bg-inset);
403 border: 1px solid var(--fb-border);440 border: 1px solid var(--fb-border);
404}441}
442.avatar-sm {
443 width: 1.75rem;
444 height: 1.75rem;
445 border-radius: 5px;
446}
405.avatar-lg {447.avatar-lg {
406 width: 5rem;448 width: 5rem;
407 height: 5rem;449 height: 5rem;
450 border-radius: 8px;
408}451}
409.avatar-xl {452.avatar-xl {
410 width: 6rem;453 width: 100%;
411 height: 6rem;454 max-width: 16rem;
455 aspect-ratio: 1;
456 height: auto;
457 border-radius: 10px;
412}458}
413.profile-head {459.profile-head {
414 display: flex;460 display: flex;
@@ -531,8 +577,38 @@ pre.code {
531.repo-slug a {577.repo-slug a {
532 color: var(--fb-accent);578 color: var(--fb-accent);
533}579}
534.repo-tabs {580/* Horizontal tab strips (repo sub-nav, explore sub-nav). */
535 margin: 0.5rem 0;581.repo-tabs,
582.subnav {
583 display: flex;
584 gap: 0.25rem;
585 flex-wrap: wrap;
586 margin: 0.75rem 0;
587 border-bottom: 1px solid var(--fb-border);
588}
589.repo-tabs a,
590.subnav a {
591 display: inline-flex;
592 align-items: center;
593 gap: 0.4rem;
594 padding: 0.5rem 0.85rem;
595 color: var(--fb-fg-muted);
596 border-bottom: 2px solid transparent;
597 margin-bottom: -1px;
598}
599.repo-tabs a:hover,
600.subnav a:hover {
601 color: var(--fb-fg);
602 text-decoration: none;
603}
604.repo-tabs a[aria-current="page"],
605.subnav a[aria-current="page"] {
606 color: var(--fb-fg);
607 border-bottom-color: var(--fb-accent);
608 font-weight: 600;
609}
610.subnav {
611 justify-content: center;
536}612}
537.ref-row,613.ref-row,
538.clone-row {614.clone-row {
crates/web/src/layout.rs +4 −2
@@ -72,8 +72,10 @@ fn topbar(chrome: &Chrome) -> Markup {
72 button class="icon-btn" type="button" data-drawer-toggle aria-label="Menu"72 button class="icon-btn" type="button" data-drawer-toggle aria-label="Menu"
73 aria-controls="drawer" aria-expanded="false" { (icon(Icon::PanelLeft)) }73 aria-controls="drawer" aria-expanded="false" { (icon(Icon::PanelLeft)) }
74 span class="slug" { a href="/" { (chrome.instance_name) } }74 span class="slug" { a href="/" { (chrome.instance_name) } }
75 nav class="tabs" aria-label="Primary" {}75 form class="topbar-search" method="get" action="/search" role="search" {
76 a class="icon-btn" href="/search" aria-label="Search" { (icon(Icon::Search)) }76 input type="search" name="q" placeholder="Search…" aria-label="Search";
77 button class="icon-btn" type="submit" aria-label="Search" { (icon(Icon::Search)) }
78 }
77 a class="icon-btn" href="/" aria-label="Home" { (icon(Icon::House)) }79 a class="icon-btn" href="/" aria-label="Home" { (icon(Icon::House)) }
78 }80 }
79 }81 }
crates/web/src/search.rs +2 −2
@@ -388,10 +388,10 @@ pub async fn in_repo(
388/// The search input form.388/// The search input form.
389fn search_box(value: &str, action: Option<&str>) -> Markup {389fn search_box(value: &str, action: Option<&str>) -> Markup {
390 html! {390 html! {
391 form method="get" action=[action] {391 form class="search-row" method="get" action=[action] {
392 input type="search" name="q" value=(value) placeholder="Search…"392 input type="search" name="q" value=(value) placeholder="Search…"
393 data-search-input aria-label="Search query" autofocus;393 data-search-input aria-label="Search query" autofocus;
394 button class="btn" type="submit" { "Search" }394 button class="btn btn-primary" type="submit" { "Search" }
395 }395 }
396 }396 }
397}397}
data/repos/01/01kyc0j4dzrnx6afv3wwfvxgn4.git/HEAD +1 −0
@@ -0,0 +1 @@
1ref: refs/heads/main
data/repos/01/01kyc0j4dzrnx6afv3wwfvxgn4.git/config +9 −0
@@ -0,0 +1,9 @@
1[core]
2 bare = true
3 repositoryformatversion = 0
4 filemode = true
5 logallrefupdates = true
6[receive]
7 denyNonFastForwards = false
8[gc]
9 auto = 0
data/repos/01/01kyc0j4dzrnx6afv3wwfvxgn4.git/description +1 −0
@@ -0,0 +1 @@
1Unnamed repository; edit this file 'description' to name the repository.
data/repos/01/01kyc0j4dzrnx6afv3wwfvxgn4.git/hooks/README.sample +5 −0
@@ -0,0 +1,5 @@
1#!/bin/sh
2#
3# Place appropriately named executable hook scripts into this directory
4# to intercept various actions that git takes. See `git help hooks` for
5# more information.
data/repos/01/01kyc0j4dzrnx6afv3wwfvxgn4.git/hooks/post-receive +2 −0
@@ -0,0 +1,2 @@
1#!/bin/sh
2exec "/nix/store/ccirpbv8km7dv6iwq7zka65sy94xbh5v-fabrica-0.1.0/bin/.fabrica-wrapped" hook post-receive
data/repos/01/01kyc0j4dzrnx6afv3wwfvxgn4.git/hooks/pre-receive +2 −0
@@ -0,0 +1,2 @@
1#!/bin/sh
2exit 0
data/repos/01/01kyc0j4dzrnx6afv3wwfvxgn4.git/info/exclude +2 −0
@@ -0,0 +1,2 @@
1# File patterns to ignore; see `git help ignore` for more information.
2# Lines that start with '#' are comments.