Skip to content

Commit c25dceb

Browse files
ChristineThamclaude
andcommitted
feat(tags): redesign the tags page as a word cloud
Replaces the grid of patterned chips with a proper clickable cloud: serif tags flowing inline, sized and coloured by article count on a log scale over seven steps of the standard type scale, ordered alphabetically so a specific tag is still findable by scanning. Drops the 40-odd hero-pattern imports the old chips needed — the file is 168 lines down to 110. Each tag carries a screen-reader-only and title article count, since size alone does not convey it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 1414683 commit c25dceb

1 file changed

Lines changed: 57 additions & 115 deletions

File tree

src/pages/tags.astro

Lines changed: 57 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -6,91 +6,6 @@ import PageHero from '../components/pagehero.astro'
66
import coverSVG from '../assets/svg/rosely/undraw_add_notes-light.svg'
77
import coverSVGDark from '../assets/svg/rosely/undraw_add_notes-dark.svg'
88
import socialImage from '../assets/social/add_notes.png'
9-
import {
10-
jupiter,
11-
cutout,
12-
pianoMan,
13-
pieFactory,
14-
graphPaper,
15-
charlieBrown,
16-
autumn,
17-
temple,
18-
deathStar,
19-
churchOnSunday,
20-
overlappingHexagons,
21-
bamboo,
22-
bathroomFloor,
23-
corkScrew,
24-
happyIntersection,
25-
kiwi,
26-
lips,
27-
lisbon,
28-
steelBeams,
29-
tinyCheckers,
30-
fancyRectangles,
31-
heavyRain,
32-
cage,
33-
connections,
34-
flippedDiamonds,
35-
houndstooth,
36-
morphingDiamonds,
37-
zigZag,
38-
aztec,
39-
bankNote,
40-
boxes,
41-
diagonalLines,
42-
endlessClouds,
43-
eyes,
44-
groovy,
45-
melt,
46-
parkayFloor,
47-
pixelDots,
48-
signal,
49-
wallpaper
50-
} from 'hero-patterns'
51-
52-
const patterns = [
53-
steelBeams('#9c92ac', 0.5),
54-
jupiter('#9c92ac', 0.5),
55-
cutout('#9c92ac', 0.5),
56-
pianoMan('#9c92ac', 0.5),
57-
pieFactory('#9c92ac', 0.5),
58-
graphPaper('#9c92ac', 0.5),
59-
charlieBrown('#9c92ac', 0.5),
60-
autumn('#9c92ac', 0.5),
61-
temple('#9c92ac', 0.5),
62-
deathStar('#9c92ac', 0.5),
63-
churchOnSunday('#9c92ac', 0.5),
64-
overlappingHexagons('#9c92ac', 0.5),
65-
bamboo('#9c92ac', 0.5),
66-
bathroomFloor('#9c92ac', 0.5),
67-
corkScrew('#9c92ac', 0.5),
68-
happyIntersection('#9c92ac', 0.5),
69-
kiwi('#9c92ac', 0.5),
70-
lips('#9c92ac', 0.5),
71-
lisbon('#9c92ac', 0.5),
72-
tinyCheckers('#9c92ac', 0.5),
73-
fancyRectangles('#9c92ac', 0.5),
74-
heavyRain('#9c92ac', 0.5),
75-
cage('#9c92ac', 0.5),
76-
connections('#9c92ac', 0.5),
77-
flippedDiamonds('#9c92ac', 0.5),
78-
houndstooth('#9c92ac', 0.5),
79-
morphingDiamonds('#9c92ac', 0.5),
80-
zigZag('#9c92ac', 0.5),
81-
aztec('#9c92ac', 0.5),
82-
bankNote('#9c92ac', 0.5),
83-
boxes('#9c92ac', 0.5),
84-
diagonalLines('#9c92ac', 0.5),
85-
endlessClouds('#9c92ac', 0.5),
86-
eyes('#9c92ac', 0.5),
87-
groovy('#9c92ac', 0.5),
88-
melt('#9c92ac', 0.5),
89-
parkayFloor('#9c92ac', 0.5),
90-
pixelDots('#9c92ac', 0.5),
91-
signal('#9c92ac', 0.5),
92-
wallpaper('#9c92ac', 0.5)
93-
]
949
9510
const frontmatter: CollectionEntry<'page'>['data'] = {
9611
title: 'Tags',
@@ -118,6 +33,35 @@ posts.forEach((post) => {
11833
11934
const tags = Array.from(tagmap.values())
12035
36+
// Frequency is encoded in size and colour; the cloud itself reads
37+
// alphabetically, so a particular tag can still be found by scanning.
38+
const counts = tags.map((t) => t.count)
39+
const min = Math.min(...counts)
40+
const max = Math.max(...counts)
41+
42+
// Seven steps, heaviest first — standard type scale, no arbitrary sizes.
43+
const steps = [
44+
{ size: 'text-5xl', tone: 'text-ink dark:text-cream', weight: 'font-medium' },
45+
{ size: 'text-4xl', tone: 'text-ink dark:text-cream', weight: 'font-medium' },
46+
{ size: 'text-3xl', tone: 'text-mulberry dark:text-quartz', weight: 'font-medium' },
47+
{ size: 'text-2xl', tone: 'text-mulberry dark:text-quartz', weight: 'font-normal' },
48+
{ size: 'text-xl', tone: 'text-slate dark:text-fog', weight: 'font-normal' },
49+
{ size: 'text-lg', tone: 'text-slate dark:text-fog', weight: 'font-normal' },
50+
{ size: 'text-base', tone: 'text-slate dark:text-fog', weight: 'font-normal' }
51+
]
52+
53+
const stepFor = (count: number) => {
54+
if (max === min) return steps[3]
55+
// Log scale, so one very frequent tag doesn't flatten all the others.
56+
const t = (Math.log(count) - Math.log(min)) / (Math.log(max) - Math.log(min))
57+
return steps[Math.round((1 - t) * (steps.length - 1))]
58+
}
59+
60+
const cloud = tags
61+
.slice()
62+
.sort((a, b) => a.tag.toLowerCase().localeCompare(b.tag.toLowerCase()))
63+
.map((t) => ({ ...t, ...stepFor(t.count) }))
64+
12165
const baseUrl = import.meta.env.BASE_URL
12266
---
12367

@@ -131,38 +75,36 @@ const baseUrl = import.meta.env.BASE_URL
13175
socialImage={frontmatter.socialImage}
13276
/>
13377
</header>
134-
<div itemprop="mainContentOfPage" class="dark:bg-ink mt-10">
135-
<div
136-
itemprop="mainEntity"
137-
itemscope
138-
itemtype="https://schema.org/CollectionPage"
139-
class="mx-4 mt-6 mb-24 grid grid-cols-2 gap-x-4 gap-y-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 xl:gap-x-6 xl:gap-y-6"
140-
>
141-
{
142-
tags
143-
.sort((a, b) => b.count - a.count)
144-
.map((tag, i) => (
145-
<a href={`${baseUrl}tag/${tag.tag}/`} class="group">
146-
<section
147-
class="group relative h-24 w-full overflow-hidden rounded-lg bg-cover bg-center shadow-lg transition duration-300 ease-in-out hover:shadow-2xl"
148-
style={{
149-
backgroundColor: '#dfdbe5',
150-
// backgroundImage: `url(${OGImage})`,
151-
backgroundImage: patterns[i % patterns.length]
152-
}}
78+
79+
<div itemprop="mainContentOfPage" class="dark:bg-ink-deep bg-cream">
80+
<div class="mx-auto max-w-5xl px-6 py-14 sm:px-10 lg:py-16">
81+
<p class="text-mulberry dark:text-grape mb-10 font-mono text-xs tracking-widest uppercase">
82+
{tags.length} tags · larger means more articles
83+
</p>
84+
85+
<ul
86+
itemprop="mainEntity"
87+
itemscope
88+
itemtype="https://schema.org/CollectionPage"
89+
class="flex flex-wrap items-baseline justify-center gap-x-6 gap-y-3"
90+
>
91+
{
92+
cloud.map((tag) => (
93+
<li class="leading-tight">
94+
<a
95+
href={`${baseUrl}tag/${tag.tag}/`}
96+
title={`${tag.count} ${tag.count === 1 ? 'article' : 'articles'}`}
97+
class={`hover:text-rose font-serif transition-colors dark:hover:text-white ${tag.size} ${tag.tone} ${tag.weight}`}
15398
>
154-
<div class="absolute inset-0 bg-black/50 transition duration-300 ease-in-out group-hover:opacity-75" />
155-
<div class="relative flex h-full w-full items-center justify-center px-4 sm:px-6 lg:px-4">
156-
<h3 class="text-center text-2xl font-bold text-white">
157-
<span class="absolute inset-0" />
158-
{tag.tag}
159-
</h3>
160-
<p class="text-center text-sm font-medium text-gray-200">&nbsp;({tag.count})</p>
161-
</div>
162-
</section>
163-
</a>
99+
{tag.tag}
100+
<span class="sr-only">
101+
, {tag.count} {tag.count === 1 ? 'article' : 'articles'}
102+
</span>
103+
</a>
104+
</li>
164105
))
165-
}
106+
}
107+
</ul>
166108
</div>
167109
</div>
168110
</Base>

0 commit comments

Comments
 (0)