/news utilities: label the pills + wrap the action row on phones (Codex)

- Saved/Boundaries are now labeled pills (icon + text), not bare circles — a
  shield alone doesn't read as "Boundaries" on touch. .vh-util is auto-width with
  padding; labels show on desktop and mobile.
- Fix the narrow-screen overflow: on a signed-in hub-chrome drill-in the row
  (Search+Saved+Boundaries+Follow+Back) exceeded ~320–375px. The view-head now
  wraps the action row below the heading — scoped to `.container.hub` so the
  frozen `/` feed (fewer controls; Saved/Boundaries in its Header) is untouched.

32 tests green; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-28 16:01:05 -04:00
parent 036e7ed7e8
commit 39b38f0cf1
+17 -5
View File
@@ -644,7 +644,7 @@
<LanePicker pool={lanePool} selected={pinnedLaneKeys} onsave={saveLanes} onclose={() => (showLanes = false)} /> <LanePicker pool={lanePool} selected={pinnedLaneKeys} onsave={saveLanes} onclose={() => (showLanes = false)} />
{/if} {/if}
<main class="container"> <main class="container" class:hub={chrome === 'hub'}>
{#if navLanes.length} {#if navLanes.length}
<MoodNav lanes={navLanes} {selected} onselect={navigate} oncustomize={() => (showLanes = true)} /> <MoodNav lanes={navLanes} {selected} onselect={navigate} oncustomize={() => (showLanes = true)} />
{/if} {/if}
@@ -672,11 +672,13 @@
{#if auth.user} {#if auth.user}
<button class="vh-util" onclick={() => (showSaved = true)} aria-label="Saved articles" title="Saved articles"> <button class="vh-util" onclick={() => (showSaved = true)} aria-label="Saved articles" title="Saved articles">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 3h12v18l-6-4-6 4z" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linejoin="round"/></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 3h12v18l-6-4-6 4z" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linejoin="round"/></svg>
<span class="lbl">Saved</span>
</button> </button>
{/if} {/if}
<a class="vh-util" class:on={filtersOn} href="/account?section=boundaries" <a class="vh-util" class:on={filtersOn} href="/account?section=boundaries"
aria-label={filtersOn ? 'Boundaries are on' : 'Your boundaries'} title={filtersOn ? 'Boundaries are on' : 'Your boundaries'}> aria-label={filtersOn ? 'Boundaries are on' : 'Your boundaries'} title={filtersOn ? 'Boundaries are on' : 'Your boundaries'}>
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3l7 3v5c0 4.4-3 7.6-7 9-4-1.4-7-4.6-7-9V6l7-3z" fill={filtersOn ? 'currentColor' : 'none'} stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3l7 3v5c0 4.4-3 7.6-7 9-4-1.4-7-4.6-7-9V6l7-3z" fill={filtersOn ? 'currentColor' : 'none'} stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg>
<span class="lbl">Boundaries</span>
</a> </a>
{/if} {/if}
{#if auth.user && followTarget} {#if auth.user && followTarget}
@@ -925,13 +927,23 @@
.searchtoggle:hover { border-color: var(--accent); } .searchtoggle:hover { border-color: var(--accent); }
.searchtoggle.on { background: var(--accent); border-color: var(--accent); color: #fff; } .searchtoggle.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.searchtoggle svg { width: 17px; height: 17px; display: block; } .searchtoggle svg { width: 17px; height: 17px; display: block; }
/* news-local Saved / Boundaries — same pill as the search toggle */ /* news-local Saved / Boundaries — labeled pills (a bare shield doesn't read as "Boundaries") */
.vh-util { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; .vh-util { display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 13px;
background: none; border: 1px solid var(--line); color: var(--accent-deep); border-radius: 999px; background: none; border: 1px solid var(--line); color: var(--accent-deep); border-radius: 999px;
cursor: pointer; text-decoration: none; transition: border-color 0.14s ease, background 0.14s ease; } font: inherit; font-size: 0.85rem; cursor: pointer; text-decoration: none; white-space: nowrap;
transition: border-color 0.14s ease, background 0.14s ease, color 0.14s ease; }
.vh-util:hover { border-color: var(--accent); } .vh-util:hover { border-color: var(--accent); }
.vh-util.on { background: var(--accent); border-color: var(--accent); color: #fff; } .vh-util.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.vh-util svg { width: 17px; height: 17px; display: block; } .vh-util svg { width: 16px; height: 16px; display: block; flex: none; }
/* Hub-chrome /news only: on a signed-in drill-in the action row (Search+Saved+Boundaries+
Follow+Back) overflows a phone — let it wrap below the heading. Scoped to .hub so the
frozen `/` feed (Saved/Boundaries live in its Header, fewer controls) is unaffected. */
@media (max-width: 560px) {
.container.hub .view-head { flex-wrap: wrap; }
.container.hub .vh-text { flex-basis: 100%; }
.container.hub .vh-actions { width: 100%; max-width: 100%; flex-wrap: wrap; justify-content: flex-start; margin-top: 10px; }
}
.searchbar { display: flex; gap: 8px; margin: 0 0 18px; } .searchbar { display: flex; gap: 8px; margin: 0 0 18px; }
.searchbar input { flex: 1; min-width: 0; font: inherit; font-size: 1rem; padding: 10px 14px; .searchbar input { flex: 1; min-width: 0; font: inherit; font-size: 1rem; padding: 10px 14px;
border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--ink); } border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--ink); }