Phase B2: grouping pills + Explore-by-family (frontend)
The "wander" layer for the multi-tag model, sitting beneath the brief: - Cards show up to 3 tappable grouping pills (the article's tags), falling back to the primary topic for articles the re-tag hasn't reached. Tap a pill → that tag's lane. Tags read as little doorways, not metadata confetti. - New tag-lane view (select 'tag:<slug>' → /api/feed?tag=) with a calm heading and the parent family's description as subtitle. - Replace the flat "Explore by topic" strip with four calm family bands (Discovery & Wonder / People & Kindness / Solutions & Progress / Mind & Craft) from /api/families; zero-count tags hide until tagging fills them in. - Mood nav stays the primary emotional layer; the brief stays the front door. - /api/families fetch is non-fatal so the page degrades gracefully when the B1 backend isn't deployed yet. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
<script>
|
||||
let { article, onaction, onreplace, hero = false } = $props();
|
||||
let { article, onaction, onreplace, ontag, hero = false } = $props();
|
||||
|
||||
const humanize = (s) => (s || '').replace(/-/g, ' ');
|
||||
// Grouping tags are the doorways; cap at 3 so cards stay calm. Fall back to
|
||||
// the primary topic for articles the re-tag hasn't reached yet.
|
||||
let pills = $derived(
|
||||
(article.tags?.length ? article.tags : article.topic ? [article.topic] : []).slice(0, 3)
|
||||
);
|
||||
|
||||
// Reset image-failure when the article changes (cards swap in place).
|
||||
let failed = $state(false);
|
||||
@@ -34,8 +41,13 @@
|
||||
|
||||
<div class="body">
|
||||
<div class="tags">
|
||||
{#if article.topic}<span class="tag">{article.topic}</span>{/if}
|
||||
{#if article.flavor}<span class="tag soft">{article.flavor}</span>{/if}
|
||||
{#each pills as t, i (t)}
|
||||
{#if ontag}
|
||||
<button type="button" class="tag" class:soft={i > 0} onclick={() => ontag(t)}>{humanize(t)}</button>
|
||||
{:else}
|
||||
<span class="tag" class:soft={i > 0}>{humanize(t)}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<div class="src">{article.source}</div>
|
||||
|
||||
@@ -79,13 +91,17 @@
|
||||
}
|
||||
|
||||
.body { padding: 16px 18px 14px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
|
||||
.tags { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 0.66rem; }
|
||||
.tags { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
|
||||
.tag {
|
||||
background: var(--accent); color: #fff; border-radius: 999px;
|
||||
padding: 3px 11px 2px; font-family: var(--label); font-weight: 300;
|
||||
text-transform: uppercase; letter-spacing: 0.055em;
|
||||
background: var(--accent); color: #fff; border: none; border-radius: 999px;
|
||||
padding: 3px 11px 2px; font-family: var(--label); font-weight: 300; font-size: 0.66rem;
|
||||
text-transform: uppercase; letter-spacing: 0.055em; line-height: 1.5;
|
||||
transition: background 0.14s ease, color 0.14s ease;
|
||||
}
|
||||
.tag.soft { background: var(--accent-soft); color: var(--accent-deep); }
|
||||
button.tag { cursor: pointer; }
|
||||
button.tag:hover { background: var(--accent-deep); color: #fff; }
|
||||
button.tag.soft:hover { background: var(--accent); color: #fff; }
|
||||
/* Source on its own line below the tags, left-justified, for uniformity. */
|
||||
.src { color: var(--muted); font-size: 0.78rem; margin: -2px 0 2px; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user