feat(design): Phase 3 — home page layout (#194)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Juan Manuel Servera committed May 25, 2026 at 21:50 UTC 63a4417ce658443992ddc29e0b59dbebb307610a
6 files changed +229 -99
.squad/agents/amy/history.md
+2
@@ -14,3 +14,5 @@
14 - 2026-05-25 Inter and JetBrains Mono are loaded with preload + stylesheet links; existing PaperMod variables are mapped to new `--color-*`, `--text-*`, and `--space-*` tokens for compatibility.
15 - 2026-05-25 Phase 2 chrome: `layouts/partials/header.html` now owns the tokenized brand/nav/GitHub/theme-toggle header, and `layouts/partials/footer.html` overrides PaperMod's footer while preserving its scroll/theme/copy-code scripts.
16 - 2026-05-25 PaperMod gotcha: adding a skip-to-content link requires overriding `layouts/_default/baseof.html`; keep the theme submodule untouched and place site-level chrome overrides in root `layouts/partials/`.
17 +- 2026-05-25 Phase 3 homepage: use `layouts/index.html` for editorial entry-point structure; keep home-specific styling in `assets/css/extended/squadscope.css` and reuse token variables only.
18 +- 2026-05-25 Home visual verification runs through `node scripts/design/verify-visual.mjs --base http://localhost:1313/SquadScope/` after starting `/tmp/hugo server -D --bind 0.0.0.0 --port 1313 --baseURL http://localhost:1313/SquadScope/`.
assets/css/extended/squadscope.css
+143 -33
@@ -7,23 +7,31 @@
7 .home-latest,
8 .home-empty-state,
9 .home-report-card,
10 -.home-nav-card,
10 +.home-quick-links,
11 .metric-card,
12 .report-shortcuts {
13 - border: var(--size-border-thin) solid var(--color-border);
13 + border: 1px solid var(--color-border);
14 border-radius: var(--radius-md);
15 background: var(--color-surface);
16 }
17
18 .home-hero,
19 .home-latest,
20 -.home-empty-state {
20 +.home-empty-state,
21 +.home-quick-links {
22 padding: var(--space-4);
23 }
24
25 +.home-hero {
26 + display: grid;
27 + gap: var(--space-4);
28 +}
29 +
30 .home-eyebrow,
31 .section-topline,
26 -.metric-label {
32 +.metric-label,
33 +.home-report-week,
34 +.home-tag-label {
35 display: block;
36 color: var(--color-text-muted);
37 font-size: var(--text-sm);
@@ -31,42 +39,100 @@
39 text-transform: uppercase;
40 }
41
34 -.home-description {
42 +.home-hero h1 {
43 + margin: var(--space-2) 0;
44 + font-size: clamp(var(--text-3xl), 10vw, var(--text-4xl));
45 + line-height: var(--leading-tight);
46 +}
47 +
48 +.home-description,
49 +.home-latest-hook {
50 + max-width: var(--prose-measure);
51 + color: var(--color-text);
52 font-size: var(--text-lg);
36 - margin: var(--space-2) 0 var(--space-3);
53 + line-height: var(--leading-relaxed);
54 }
55
39 -.home-nav-grid,
40 -.report-metrics,
41 -.home-report-list {
42 - display: grid;
43 - gap: var(--space-3);
56 +.home-copy {
57 + max-width: var(--prose-measure);
58 + color: var(--color-text-muted);
59 }
60
46 -.home-nav-grid {
47 - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
61 +.home-cadence {
62 + display: grid;
63 + gap: var(--space-3);
64 + align-content: start;
65 + padding: var(--space-3);
66 + border: 1px solid var(--color-border);
67 + border-radius: var(--radius-md);
68 + background: var(--color-bg);
69 }
70
50 -.home-nav-card {
71 +.home-cadence ul,
72 +.home-cadence dl {
73 display: grid;
74 gap: var(--space-2);
53 - padding: var(--space-3);
54 - text-decoration: none;
75 + margin: 0;
76 }
77
57 -.home-nav-title {
78 +.home-cadence ul {
79 + padding-inline-start: var(--space-4);
80 +}
81 +
82 +.home-cadence dt,
83 +.home-report-title,
84 +.home-quick-links a,
85 +.home-tag-strip a {
86 color: var(--color-text);
87 font-weight: 700;
88 }
89
62 -.home-nav-copy {
90 +.home-cadence dd {
91 + margin: var(--space-1) 0 0;
92 + color: var(--color-text-muted);
93 +}
94 +
95 +.home-latest {
96 + display: grid;
97 + gap: var(--space-3);
98 +}
99 +
100 +.home-latest-kicker,
101 +.home-report-meta,
102 +.home-tag-strip {
103 + display: flex;
104 + flex-wrap: wrap;
105 + gap: var(--space-2);
106 + align-items: center;
107 color: var(--color-text-muted);
108 font-size: var(--text-sm);
109 }
110
111 +.home-latest h2 {
112 + max-width: var(--prose-measure);
113 + margin: 0;
114 + font-size: clamp(var(--text-2xl), 6vw, var(--text-3xl));
115 + line-height: var(--leading-tight);
116 +}
117 +
118 +.home-latest h2 a,
119 +.home-report-title,
120 +.home-quick-links a,
121 +.home-tag-strip a {
122 + text-decoration-thickness: 1px;
123 + text-underline-offset: var(--space-1);
124 +}
125 +
126 +.report-metrics,
127 +.home-report-list,
128 +.home-content-grid,
129 +.home-quick-links {
130 + display: grid;
131 + gap: var(--space-3);
132 +}
133 +
134 .report-metrics {
68 - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
69 - margin: var(--space-4) 0;
135 + grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(var(--space-15) + var(--space-3))), 1fr));
136 }
137
138 .metric-card {
@@ -79,8 +145,9 @@
145
146 .metric-value {
147 display: block;
82 - font-size: var(--text-lg);
148 margin-top: var(--space-1);
149 + font-size: var(--text-lg);
150 + line-height: var(--leading-tight);
151 }
152
153 .home-actions,
@@ -97,7 +164,7 @@
164 display: inline-flex;
165 align-items: center;
166 justify-content: center;
100 - min-height: 2.5rem;
167 + min-height: calc(var(--space-5) + var(--space-2));
168 padding: 0 var(--space-3);
169 border-radius: var(--radius-full);
170 text-decoration: none;
@@ -110,11 +177,24 @@
177
178 .home-action-secondary,
179 .report-shortcuts a {
113 - border: var(--size-border-thin) solid var(--color-border);
180 + border: 1px solid var(--color-border);
181 +}
182 +
183 +.home-tag-strip {
184 + padding: var(--space-2) var(--space-3);
185 + border-block: 1px solid var(--color-border);
186 +}
187 +
188 +.home-tag-strip a {
189 + padding: var(--space-1) var(--space-2);
190 + border-radius: var(--radius-full);
191 + background: var(--color-accent-muted);
192 + color: var(--color-accent);
193 + text-decoration: none;
194 }
195
196 .home-report-list {
117 - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
197 + margin-top: var(--space-3);
198 }
199
200 .home-report-card,
@@ -122,18 +202,41 @@
202 padding: var(--space-3);
203 }
204
125 -.home-report-card h3,
126 -.squad-archive-entry h4 {
127 - margin-top: 0;
128 - margin-bottom: 0.5rem;
205 +.home-report-card {
206 + display: grid;
207 + gap: var(--space-2);
208 }
209
131 -.home-report-meta {
132 - display: flex;
133 - flex-wrap: wrap;
134 - gap: var(--space-2);
210 +.home-report-title {
211 + display: grid;
212 + gap: var(--space-1);
213 + text-decoration: none;
214 +}
215 +
216 +.home-report-card p {
217 + margin: 0;
218 color: var(--color-text-muted);
136 - font-size: var(--text-sm);
219 +}
220 +
221 +.home-quick-links {
222 + align-content: start;
223 +}
224 +
225 +.home-quick-links a {
226 + display: flex;
227 + justify-content: space-between;
228 + gap: var(--space-3);
229 + padding: var(--space-2) 0;
230 + border-bottom: 1px solid var(--color-border);
231 +}
232 +
233 +.home-quick-links a::after {
234 + content: "→";
235 + color: var(--color-accent);
236 +}
237 +
238 +.home-quick-links a:last-child {
239 + border-bottom: 0;
240 }
241
242 .squad-report .report-shortcuts {
@@ -349,6 +452,13 @@ summary:focus-visible,
452 }
453 }
454
455 +@media (min-width: 769px) {
456 + .home-hero,
457 + .home-content-grid {
458 + grid-template-columns: minmax(0, 2fr) minmax(calc(var(--space-16) + var(--space-10)), 1fr);
459 + }
460 +}
461 +
462 @media (max-width: 640px) {
463 .metric-card-wide {
464 grid-column: span 1;
layouts/index.html
+84 -66
@@ -1,84 +1,102 @@
1 {{- define "main" -}}
2 {{- $weeklyPages := (where site.RegularPages "Type" "weekly").ByDate.Reverse -}}
3 +{{- $latest := cond (gt (len $weeklyPages) 0) (index $weeklyPages 0) nil -}}
4
5 <div class="home-shell">
5 - <section class="home-hero">
6 - <p class="home-eyebrow">Weekly tech signal from GitHub</p>
7 - <h1>{{ .Title }}</h1>
8 - {{- with .Params.description }}
9 - <p class="home-description">{{ . }}</p>
10 - {{- end }}
11 - <div class="post-content md-content">
12 - {{ .Content }}
6 + <section class="home-hero" aria-labelledby="home-title">
7 + <div class="home-hero-main">
8 + <p class="home-eyebrow">Weekly tech signal from GitHub</p>
9 + <h1 id="home-title">{{ .Title }}</h1>
10 + <p class="home-description">
11 + {{- with .Params.description -}}
12 + {{ . }}
13 + {{- else -}}
14 + {{ site.Params.homeInfoParams.Content }}
15 + {{- end -}}
16 + </p>
17 + <div class="home-copy md-content">
18 + {{ .Content }}
19 + </div>
20 </div>
14 - </section>
21
16 - <section class="home-nav-grid" aria-label="Primary views">
17 - <a class="home-nav-card" href="{{ `archive/` | absLangURL }}">
18 - <span class="home-nav-title">Archive</span>
19 - <span class="home-nav-copy">Browse every weekly summary in reverse chronological order.</span>
20 - </a>
21 - <a class="home-nav-card" href="{{ `monthly/` | absLangURL }}">
22 - <span class="home-nav-title">Monthly</span>
23 - <span class="home-nav-copy">Step back and review the strongest themes across each month.</span>
24 - </a>
25 - <a class="home-nav-card" href="{{ `yearly/` | absLangURL }}">
26 - <span class="home-nav-title">Yearly</span>
27 - <span class="home-nav-copy">Follow broader platform shifts and long-running trend lines.</span>
28 - </a>
29 - <a class="home-nav-card" href="{{ `tags/` | absLangURL }}">
30 - <span class="home-nav-title">Tags</span>
31 - <span class="home-nav-copy">Jump into recurring topics like AI, security, and developer tooling.</span>
32 - </a>
33 - <a class="home-nav-card" href="{{ `categories/` | absLangURL }}">
34 - <span class="home-nav-title">Categories</span>
35 - <span class="home-nav-copy">Move between weekly, monthly, and yearly reporting cadences.</span>
36 - </a>
37 - <a class="home-nav-card" href="{{ `search/` | absLangURL }}">
38 - <span class="home-nav-title">Search</span>
39 - <span class="home-nav-copy">Use Pagefind to search by keyword, filter, date, or repository name.</span>
40 - </a>
41 - <a class="home-nav-card" href="{{ `index.xml` | absLangURL }}">
42 - <span class="home-nav-title">RSS</span>
43 - <span class="home-nav-copy">Subscribe to the newest reports in your feed reader.</span>
44 - </a>
22 + <aside class="home-cadence" aria-label="What readers get">
23 + <p class="section-topline">What readers get</p>
24 + <ul>
25 + <li>Signal-first weekly GitHub trend analysis.</li>
26 + <li>Monthly and yearly rollups for longer arcs.</li>
27 + <li>Noise calls on spam, star farming, and blind spots.</li>
28 + </ul>
29 + <dl>
30 + <div>
31 + <dt>Cadence</dt>
32 + <dd>Weekly on Mondays, with rollups as the archive grows.</dd>
33 + </div>
34 + </dl>
35 + </aside>
36 </section>
37
47 - {{- if gt (len $weeklyPages) 0 -}}
48 - {{- $latest := index $weeklyPages 0 -}}
49 - <section class="home-latest" aria-labelledby="latest-report-heading">
50 - <div class="section-topline">Latest weekly summary</div>
38 + {{- if $latest -}}
39 + <article class="home-latest" aria-labelledby="latest-report-heading">
40 + <div class="home-latest-kicker">
41 + <span class="section-topline">Latest report</span>
42 + {{- with $latest.Params.week }}<span>{{ . }}</span>{{- end }}
43 + </div>
44 <h2 id="latest-report-heading"><a href="{{ $latest.RelPermalink }}">{{ $latest.Title }}</a></h2>
52 - <p>{{ $latest.Params.summary | default $latest.Summary }}</p>
45 + <p class="home-latest-hook">{{ $latest.Params.summary | default $latest.Summary }}</p>
46 {{ partial "report-metrics.html" $latest }}
47 <div class="home-actions">
55 - <a class="home-action-primary" href="{{ $latest.RelPermalink }}">Read summary</a>
56 - <a class="home-action-secondary" href="{{ `archive/` | absLangURL }}">Open archive</a>
48 + <a class="home-action-primary" href="{{ $latest.RelPermalink }}">Read this week</a>
49 + <a class="home-action-secondary" href="{{ `archive/` | absLangURL }}">Browse archive</a>
50 </div>
58 - </section>
51 + </article>
52 {{- else -}}
60 - <section class="home-empty-state">
61 - <div class="section-topline">Latest weekly summary</div>
62 - <h2>No weekly report published yet</h2>
63 - <p>The homepage will automatically feature the newest report as soon as the first weekly summary lands in <code>content/weekly/</code>.</p>
53 + <section class="home-empty-state" aria-labelledby="latest-report-heading">
54 + <div class="section-topline">Latest report</div>
55 + <h2 id="latest-report-heading">No weekly report published yet</h2>
56 + <p>The homepage will feature the newest report as soon as the first weekly summary lands in <code>content/weekly/</code>.</p>
57 </section>
58 {{- end -}}
59
67 - <section class="home-recent" aria-labelledby="recent-reports-heading">
68 - <div class="section-topline">Recent weekly reports</div>
69 - <h2 id="recent-reports-heading">Browse the latest entries</h2>
70 - <div class="home-report-list">
71 - {{- range first 5 $weeklyPages -}}
72 - <article class="home-report-card">
73 - <h3><a href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
74 - <p>{{ .Params.summary | default .Summary }}</p>
75 - <div class="home-report-meta">
76 - <span>{{ .Date.Format "2006-01-02" }}</span>
77 - {{- with .Params.categories }}<span>{{ delimit . ", " }}</span>{{- end }}
78 - </div>
79 - </article>
80 - {{- end -}}
81 - </div>
82 - </section>
60 + {{- if site.Taxonomies.tags -}}
61 + <nav class="home-tag-strip" aria-label="Top tags">
62 + <span class="home-tag-label">Track</span>
63 + {{- range first 6 site.Taxonomies.tags.ByCount }}
64 + <a href="{{ printf "tags/%s/" (.Name | urlize) | absLangURL }}">{{ .Name }}</a>
65 + {{- end }}
66 + </nav>
67 + {{- end -}}
68 +
69 + <div class="home-content-grid">
70 + <section class="home-recent" aria-labelledby="recent-reports-heading">
71 + <div class="section-topline">Recent issues</div>
72 + <h2 id="recent-reports-heading">Weekly archive</h2>
73 + <div class="home-report-list">
74 + {{- range first 6 $weeklyPages -}}
75 + <article class="home-report-card">
76 + <a class="home-report-title" href="{{ .RelPermalink }}">
77 + <span class="home-report-week">{{ .Params.week | default (.Date.Format "2006-01-02") }}</span>
78 + <span>{{ .Title }}</span>
79 + </a>
80 + <p>{{ .Params.summary | default .Summary }}</p>
81 + <div class="home-report-meta">
82 + <span>{{ .Date.Format "Jan 2, 2006" }}</span>
83 + {{- with .Params.repos_featured }}<span>{{ . }} repos featured</span>{{- end }}
84 + </div>
85 + </article>
86 + {{- end -}}
87 + </div>
88 + </section>
89 +
90 + <nav class="home-quick-links" aria-labelledby="quick-links-heading">
91 + <div class="section-topline">Quick links</div>
92 + <h2 id="quick-links-heading">Move through the report</h2>
93 + <a href="{{ `weekly/` | absLangURL }}">Weekly reports</a>
94 + <a href="{{ `monthly/` | absLangURL }}">Monthly rollups</a>
95 + <a href="{{ `yearly/` | absLangURL }}">Yearly rollups</a>
96 + <a href="{{ `archive/` | absLangURL }}">Full archive</a>
97 + <a href="{{ `search/` | absLangURL }}">Search</a>
98 + <a href="{{ `index.xml` | absLangURL }}">RSS feed</a>
99 + </nav>
100 + </div>
101 </div>
102 {{- end -}}
screenshots/design-verification/2026-05-25/home-desktop-light.png
Binary files a/screenshots/design-verification/2026-05-25/home-desktop-light.png and b/screenshots/design-verification/2026-05-25/home-desktop-light.png differ
screenshots/design-verification/2026-05-25/home-mobile-dark.png
Binary files /dev/null and b/screenshots/design-verification/2026-05-25/home-mobile-dark.png differ
screenshots/design-verification/2026-05-25/home-wide-light.png
Binary files /dev/null and b/screenshots/design-verification/2026-05-25/home-wide-light.png differ