Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion assets/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
// Not on disk: resolved at runtime by the importmap in layouts/partials/head.html.
// Neither module is on disk: both are resolved at runtime by the importmap in
// layouts/partials/head.html, and listed as externals in its js.Build call.

// Untyped on purpose — the import is only there for bootstrap’s side effects.
declare module "bootstrap"

// Written by `npx pagefind` after the Hugo build. Only the surface main.ts uses.
declare module "pagefind" {
export function options(options: { excerptLength?: number }): Promise<void>
export function init(): Promise<void>
export function search(term: string): Promise<{ results: PagefindResult[] }>

export interface PagefindResult {
data(): Promise<PagefindDocument>
}

export interface PagefindDocument {
url: string
excerpt: string
meta: { title?: string }
}
}
64 changes: 41 additions & 23 deletions assets/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3373,35 +3373,53 @@ body {
height: 400px;
padding: 20px;
}
}

.dot {
position: absolute;
border-radius: 50%;
opacity: 0;
transform: scale(0);
transition:
transform 0.5s cubic-bezier(0.17, 0.67, 0.83, 0.67),
opacity 0.5s ease,
box-shadow 0.3s ease;
will-change: transform, opacity;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
cursor: pointer;
}
.dot {
position: absolute;
border-radius: 50%;
opacity: 0;
transform: scale(0);
transition:
transform 0.5s cubic-bezier(0.17, 0.67, 0.83, 0.67),
opacity 0.5s ease,
box-shadow 0.3s ease;
will-change: transform, opacity;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
cursor: pointer;

.animation-pulse {
animation: pulse 1.5s infinite;
&.is-visible {
opacity: 1;
transform: scale(1);
}
}

// main.ts wraps each cluster in a .cluster group, which is what hovering and clicking a dot act on:
// the group is a zero-height box, but :hover and :focus still reach it from the dot inside.
.cluster {
outline: none;

&:hover .dot.is-visible {
transform: scale(1.4);
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
z-index: 5;
}

// A click focuses the group (main.ts), so the cluster pulses once.
&:focus .dot {
animation: pulse 1.5s;
}
}

&:has(.cluster:hover) .cluster:not(:hover) .dot {
opacity: 0.4;
}
}

// Animates `scale`, not `transform`: the clicked cluster is always hovered too, and an individual
// transform property multiplies with the `transform: scale(1.4)` hover instead of replacing it.
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
scale: 1.3;
}
}

Expand Down
Loading