Skip to content

Commit fe543d7

Browse files
dvdksnclaude
andcommitted
guides: simplify landing rows and make the topic nav filter
- Guide rows are now plain title/summary links: drop the rounded-corner card, hover background, and hover arrow; the title is a regular hover:underline link. - Turn the left "Browse" rail into a topic filter. Clicking a topic shows only that topic's guides (with an "All guides" reset and a count + Clear bar); the default view still renders every guide, so in-page find and the text search keep working across the full list. Text search and topic filter are mutually exclusive and share the same flat-list view. - Drop the old jump-scroll/scrollspy nav behavior in favor of filtering. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent eb68604 commit fe543d7

1 file changed

Lines changed: 48 additions & 38 deletions

File tree

layouts/guides/landing.html

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,24 @@
88
<div
99
class="not-prose mx-auto flex min-h-[calc(100dvh-7rem)] max-w-7xl flex-col"
1010
x-data="{
11-
activeTag: 'languages',
1211
query: '',
12+
tagFilter: '',
1313
words() { return this.query.trim().toLowerCase().split(/\s+/).filter(Boolean) },
14-
filtering() { return this.query.trim().length > 0 },
14+
textFiltering() { return this.query.trim().length > 0 },
15+
filtering() { return this.textFiltering() || this.tagFilter !== '' },
1516
matchText(text) { return this.words().every(w => text.includes(w)) },
16-
rowVisible(el) { return !this.filtering() || this.matchText(el.dataset.search) },
17-
sectionVisible(el) { return !this.filtering() || Array.from(el.querySelectorAll('[data-guide]')).some(r => this.matchText(r.dataset.search)) },
18-
resultCount() { return Array.from(document.querySelectorAll('[data-guide]')).filter(r => this.matchText(r.dataset.search)).length },
19-
init() {
20-
const obs = new IntersectionObserver(
21-
entries => entries.forEach(e => { if (e.isIntersecting) this.activeTag = e.target.id }),
22-
{ rootMargin: '-20% 0px -70% 0px', threshold: 0 }
23-
);
24-
document.querySelectorAll('section[data-tag]').forEach(s => obs.observe(s));
25-
}
17+
rowVisible(el) { return !this.textFiltering() || this.matchText(el.dataset.search) },
18+
sectionVisible(el) {
19+
if (this.tagFilter) return el.dataset.tag === this.tagFilter;
20+
if (this.textFiltering()) return Array.from(el.querySelectorAll('[data-guide]')).some(r => this.matchText(r.dataset.search));
21+
return true;
22+
},
23+
resultCount() {
24+
if (this.tagFilter) return document.querySelectorAll('section[data-tag=' + this.tagFilter + '] [data-guide]').length;
25+
return Array.from(document.querySelectorAll('[data-guide]')).filter(r => this.matchText(r.dataset.search)).length;
26+
},
27+
selectTag(tag) { this.tagFilter = this.tagFilter === tag ? '' : tag; this.query = ''; window.scrollTo({ top: 0, behavior: 'smooth' }); },
28+
clear() { this.query = ''; this.tagFilter = ''; }
2629
}"
2730
>
2831
{{- partial "breadcrumbs.html" . }}
@@ -52,15 +55,16 @@
5255
<input
5356
type="search"
5457
x-model="query"
55-
@keydown.escape="query = ''"
58+
@input="tagFilter = ''"
59+
@keydown.escape="clear()"
5660
aria-label="Filter guides"
5761
placeholder="Filter guides by name, topic, or tag…"
5862
class="w-full rounded-xl border border-gray-300 bg-white py-2.5 pr-10 pl-11 text-sm text-gray-900 shadow-sm transition placeholder:text-gray-400 focus:border-blue-400 focus:ring-2 focus:ring-blue-400/40 focus:outline-none dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:placeholder:text-gray-500"
5963
/>
6064
<button
6165
x-show="query"
6266
x-cloak
63-
@click="query = ''"
67+
@click="clear()"
6468
aria-label="Clear filter"
6569
class="icon-svg icon-sm absolute top-1/2 right-2.5 -translate-y-1/2 rounded-md p-1 text-gray-400 transition hover:bg-gray-100 hover:text-gray-700 dark:hover:bg-gray-800 dark:hover:text-gray-200"
6670
>
@@ -69,23 +73,32 @@
6973
</div>
7074

7175
<div class="flex flex-1 gap-16 xl:gap-24">
72-
<!-- Sticky jump nav (hidden while filtering) -->
73-
<nav
74-
x-show="!filtering()"
75-
class="sticky top-20 hidden w-52 flex-none flex-col self-start xl:flex"
76-
>
76+
<!-- Sticky topic filter -->
77+
<nav class="sticky top-20 hidden w-52 flex-none flex-col self-start xl:flex">
7778
<p class="mb-3 text-xs font-semibold tracking-widest text-gray-400 uppercase dark:text-gray-500">
78-
Jump to
79+
Browse
7980
</p>
81+
<button
82+
type="button"
83+
@click="clear()"
84+
class="flex items-center justify-between py-1.5 text-left text-sm transition-colors"
85+
:class="!filtering() ? 'text-black dark:text-white font-medium' : 'text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'"
86+
>
87+
<span class="flex items-center gap-2.5">
88+
<span class="w-5"></span>
89+
<span>All guides</span>
90+
</span>
91+
<span class="text-xs tabular-nums text-gray-300 dark:text-gray-600">{{ len .RegularPagesRecursive }}</span>
92+
</button>
8093
{{- range $i, $tag := $tagOrder }}
8194
{{- $tagData := index hugo.Data.tags $tag }}
8295
{{- $pages := where $.RegularPagesRecursive "Params.tags" "intersect" (slice $tag) }}
8396
{{- if $pages }}
84-
<a
85-
href="#{{ $tag }}"
86-
class="flex items-center justify-between py-1.5 text-sm transition-colors"
87-
:class="activeTag === '{{ $tag }}' ? 'text-black dark:text-white font-medium' : 'text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'"
88-
@click.prevent="activeTag = '{{ $tag }}'; document.getElementById('{{ $tag }}').scrollIntoView({ behavior: 'smooth' })"
97+
<button
98+
type="button"
99+
@click="selectTag('{{ $tag }}')"
100+
class="flex items-center justify-between py-1.5 text-left text-sm transition-colors"
101+
:class="tagFilter === '{{ $tag }}' ? 'text-black dark:text-white font-medium' : 'text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'"
89102
>
90103
<span class="flex items-center gap-2.5">
91104
<span class="w-5 text-xs tabular-nums text-gray-300 dark:text-gray-600">
@@ -94,7 +107,7 @@
94107
<span>{{ $tagData.title }}</span>
95108
</span>
96109
<span class="text-xs tabular-nums text-gray-300 dark:text-gray-600">{{ len $pages }}</span>
97-
</a>
110+
</button>
98111
{{- end }}
99112
{{- end }}
100113
</nav>
@@ -112,7 +125,7 @@
112125
of {{ len .RegularPagesRecursive }} guides
113126
</p>
114127
<button
115-
@click="query = ''"
128+
@click="clear()"
116129
class="text-sm font-medium text-blue-600 transition hover:underline dark:text-blue-400"
117130
>
118131
Clear filter
@@ -145,21 +158,18 @@ <h2 class="text-2xl font-bold">{{ $tagData.title }}</h2>
145158
{{- range .Params.tags }}{{ $tagTitles = $tagTitles | append (index hugo.Data.tags .).title }}{{ end }}
146159
{{- $search := lower (printf "%s %s %s %s" .Title .Summary (delimit .Params.tags " ") (delimit $tagTitles " ")) }}
147160
{{- $search = $search | replaceRE "\\s+" " " }}
148-
<a
149-
href="{{ .Permalink }}"
161+
<div
150162
data-guide
151163
data-search="{{ $search }}"
152164
x-show="rowVisible($el)"
153-
class="group -mx-3 grid grid-cols-[5fr_6fr_auto] items-start gap-6 rounded-lg px-3 py-4 transition-colors hover:bg-gray-50 dark:hover:bg-gray-900"
165+
class="grid grid-cols-[5fr_6fr] items-start gap-6 py-4"
154166
>
155-
<span class="font-medium leading-snug text-gray-900 transition-colors group-hover:text-blue-600 dark:text-gray-100 dark:group-hover:text-blue-400">{{ .Title }}</span>
167+
<a
168+
href="{{ .Permalink }}"
169+
class="font-medium leading-snug text-gray-900 hover:underline dark:text-gray-100"
170+
>{{ .Title }}</a>
156171
<span class="text-sm leading-relaxed text-gray-500 dark:text-gray-400">{{ .Summary }}</span>
157-
<span
158-
class="icon-svg icon-sm mt-0.5 self-center text-gray-300 opacity-0 transition-all duration-200 group-hover:translate-x-0.5 group-hover:text-blue-600 group-hover:opacity-100 dark:text-gray-600 dark:group-hover:text-blue-400"
159-
>
160-
{{ partialCached "icon" "arrow-right" "arrow-right" }}
161-
</span>
162-
</a>
172+
</div>
163173
{{- end }}
164174
</div>
165175
</section>
@@ -179,7 +189,7 @@ <h2 class="text-2xl font-bold">{{ $tagData.title }}</h2>
179189
No guides match “<span class="font-medium text-gray-700 dark:text-gray-200" x-text="query"></span>”.
180190
</p>
181191
<button
182-
@click="query = ''"
192+
@click="clear()"
183193
class="text-sm font-medium text-blue-600 transition hover:underline dark:text-blue-400"
184194
>
185195
Clear filter

0 commit comments

Comments
 (0)