Skip to content
Merged
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
9 changes: 8 additions & 1 deletion web/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ shipped belongs in the app's `CHANGELOG.md` only.
blocks over the custom properties in `src/styles/global.css`. Don't reach for
Tailwind, a component library, or a client-side framework — there is no
client-side JS framework here on purpose, and shared patterns (`.card`,
`.pill`, `.btn`, `.tok`) already exist in `global.css`.
`.frost`, `.pill`, `.btn`, `.tok`) already exist in `global.css` — `.frost` is
the blur every card carries, so reach for it rather than hand-rolling another
`backdrop-filter`.
- **Write `-webkit-backdrop-filter` before the unprefixed property**, here and in
`Nav.astro` / `DocsNav.astro`. esbuild's minifier treats the pair as one
property and keeps the one written last, so standard-first ships only the
prefix — which Chrome has removed and Firefox never had, silently killing the
blur outside Safari. `global.css` carries the long version of this note.
- **Colours, radii, and spacing come from tokens**, so a change lands in one
place. A hard-coded hex in a component is a mistake.
- **Motion is optional.** Scroll-reveal, parallax, and typing effects must stay
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/ChangelogEntry.astro
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const dot = featured ? "var(--green)" : dots[index] ?? "rgba(255,255,255,0.4)";
style={`--dot:${dot};--reveal-delay:${Math.min(index, 4) * 0.05}s`}
>
<span class="entry__dot"></span>
<div class="entry__card">
<div class="entry__card frost">
<div class="entry__head">
<h2 class="entry__version">{release.version}</h2>
{release.badge && <span class:list={["entry__tag", `entry__tag--${release.badge.toLowerCase()}`]}>{release.badge}</span>}
Expand Down
18 changes: 16 additions & 2 deletions web/src/components/DocsNav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const currentTitle = pages.find((p) => p.id === current)?.data.title ?? "Docs";
{/* Below 900px the rail is a stacked block, and every page opened with a
fourteen-page index plus this page's own sections above the first
paragraph. There it collapses into one sticky control instead. */}
<aside class="docsnav" data-docsnav>
<aside class="docsnav card frost" data-docsnav>
<button
type="button"
class="docsnav__toggle"
Expand Down Expand Up @@ -135,12 +135,17 @@ const currentTitle = pages.find((p) => p.id === current)?.data.title ?? "Docs";
</script>

<style>
/* The rail is a card: .card gives it the radius, surface and border, .frost
the blur. Only the padding is its own. The card sits on .docsnav rather
than on the panel inside it so the frame stays put while a long index
scrolls within it. */
.docsnav {
position: sticky;
top: 92px;
align-self: start;
max-height: calc(100vh - 120px);
overflow-y: auto;
padding: 14px;
}

.docsnav__panel {
Expand Down Expand Up @@ -211,8 +216,8 @@ const currentTitle = pages.find((p) => p.id === current)?.data.title ?? "Docs";
/* Nearly opaque, not glass: it parks over screenshots and code blocks, and
a light backdrop showed straight through a lower alpha. */
background: rgba(10, 11, 14, 0.95);
backdrop-filter: blur(18px) saturate(160%);
-webkit-backdrop-filter: blur(18px) saturate(160%);
backdrop-filter: blur(18px) saturate(160%);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
color: var(--muted);
font-family: inherit;
Expand Down Expand Up @@ -256,10 +261,19 @@ const currentTitle = pages.find((p) => p.id === current)?.data.title ?? "Docs";
/* Without the script this stays the full list stacked above the article —
long, but every link works. Everything below is the collapsed version,
so it only applies once the script has run. */
/* Undoes the card: down here the rail is one control (or, without the
script, a plain stacked list), and .docsnav__toggle carries its own
surface. The blur goes too — over a transparent box it would otherwise
smear a band of the article behind the toggle. */
.docsnav {
position: static;
max-height: none;
margin-bottom: 28px;
padding: 0;
background: none;
border: none;
border-radius: 0;
backdrop-filter: none;
}

/* Sticky needs a block container: as a grid item the rail could only
Expand Down
4 changes: 1 addition & 3 deletions web/src/components/Faq.astro
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { faqsHighlight } from "../data/content";
<h2 class="faq__title">Before you download.</h2>
</div>

<div class="faq__list reveal" style="--reveal-delay:.1s" data-faq>
<div class="faq__list frost reveal" style="--reveal-delay:.1s" data-faq>
{
faqsHighlight.map((f) => (
<details class="faq__item" name="faq">
Expand Down Expand Up @@ -55,8 +55,6 @@ import { faqsHighlight } from "../data/content";
border-radius: 18px;
background: var(--surface);
border: 1px solid var(--border);
backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px);
overflow: hidden;
}
.faq__item + .faq__item {
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/FeatureGrid.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { highlights } from "../data/content";
{
highlights.map((c, i) => (
<article
class:list={["fcard", "reveal", { "fcard--tinted": c.hue !== null }]}
class:list={["fcard", "frost", "reveal", { "fcard--tinted": c.hue !== null }]}
style={`--hue:${c.hue ?? 0};--reveal-delay:${(i % 3) * 0.08}s`}
>
<div class="fcard__icon">{c.glyph}</div>
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/FinalCta.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Icon from "./Icon.astro";
---

<section id="install" class="cta container reveal">
<div class="cta__panel">
<div class="cta__panel frost">
<div class="cta__sweep" aria-hidden="true"></div>
<h2 class="cta__title">Free, open source,<br />and unmistakably Mac.</h2>
<p class="cta__sub">
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/Nav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ const linkIcon: Record<string, "grid" | "book" | "help" | "history"> = {
right: 0;
z-index: 50;
padding-block: 14px;
backdrop-filter: blur(18px) saturate(160%);
-webkit-backdrop-filter: blur(18px) saturate(160%);
backdrop-filter: blur(18px) saturate(160%);
background: rgba(10, 11, 14, 0);
border-bottom: 1px solid rgba(255, 255, 255, 0);
transition: background 0.35s ease, border-color 0.35s ease;
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/RelatedDocs.astro
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const pages = (related ?? []).map((id) => {
<h2 class="related__title">Where to go next</h2>
<div class="related__grid">
{pages.map((p) => (
<a href={`/docs/${p.id}`} class="related__card card">
<a href={`/docs/${p.id}`} class="related__card card frost">
<span class="related__name">{p.data.title}</span>
<span class="related__summary">{p.data.summary}</span>
</a>
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/RemoteShowcase.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
---

<section class="showcase container reveal">
<div class="showcase__panel showcase__panel--cyan">
<div class="showcase__panel showcase__panel--cyan frost">
<div class="showcase__copy">
<div class="eyebrow">REMOTE FOLDERS</div>
<h2 class="showcase__title">Your server's docs, on your desktop.</h2>
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/RenderShowcase.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const tags = ["Code copy buttons", "Image lightbox", "Heading anchors"];
---

<section class="showcase container reveal">
<div class="showcase__panel showcase__panel--purple">
<div class="showcase__panel showcase__panel--purple frost">
<div class="showcase__shot">
<img
src="/screenshots/rendering-showcase/01-rendering.png"
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/changelog.astro
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { releasesLatest, releases } from "../data/site";
{releasesLog.map((release, i) => <ChangelogEntry release={release} index={i} />)}
</div>

<div class="clog__cta reveal">
<div class="clog__cta frost reveal">
<h3>Update from within the app</h3>
<p>
Sparkle checks for and installs new releases automatically — or grab the latest build
Expand Down
6 changes: 3 additions & 3 deletions web/src/pages/docs.astro
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const steps = [
</div>
</header>

<section class="start card" data-hidewhenfiltering>
<section class="start card frost" data-hidewhenfiltering>
<div class="start__head">
<div>
<div class="pill hub__eyebrow">New to Reader.md?</div>
Expand All @@ -85,7 +85,7 @@ const steps = [
</div>
<ol class="start__steps">
{steps.map((s, i) => (
<li class="step">
<li class="step frost">
<div class="step__n">{i + 1}</div>
<div class="step__title">{s.title}</div>
<p class="step__body" set:html={s.body} />
Expand All @@ -103,7 +103,7 @@ const steps = [
{pages.map((p) => (
<a
href={`/docs/${p.id}`}
class="dcard card"
class="dcard card frost"
data-card
data-search={`${p.data.title} ${p.data.summary} ${p.data.category}`.toLowerCase()}
>
Expand Down
29 changes: 16 additions & 13 deletions web/src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,22 @@ pre {
border: 1px solid var(--border);
}

/* Frost every card-like surface so text stays readable over the dot grid. */
.card,
.fcard,
.entry__card,
.arch__card,
.req__card,
.showcase__panel,
.cta__code,
.scut__row,
/* Frosts a surface so text stays readable over the dot grid. Cards carry
.frost as a class in the markup; .btn, .pill and .cta__code always frost, so
they take it here rather than repeating the class at every call site.

The -webkit- line comes FIRST here and at every other backdrop-filter in this
site, and the order is load-bearing: esbuild's CSS minifier treats the two as
one property and keeps whichever is written last. Standard-first therefore
ships only the prefix, which Chrome has since removed and Firefox never had —
the blur silently dies everywhere but Safari. Prefix-first keeps the standard
property, and Safari <18 loses the blur rather than everyone else. */
.frost,
.btn,
.pill {
backdrop-filter: blur(2px);
.pill,
.cta__code {
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
}

/* Pills / badges */
Expand Down Expand Up @@ -548,8 +551,8 @@ pre {
border-radius: 18px;
border: 1px solid var(--border);
background: var(--surface);
backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
overflow: hidden;
}

Expand Down Expand Up @@ -630,8 +633,8 @@ pre {
border-radius: 12px;
background: var(--surface-2);
border: 1px solid var(--border);
backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
}

.filter:focus-within {
Expand Down
Loading