diff --git a/apps/web/src/lib/blob-proxy.ts b/apps/web/src/lib/blob-proxy.ts
new file mode 100644
index 0000000..ac4ac0c
--- /dev/null
+++ b/apps/web/src/lib/blob-proxy.ts
@@ -0,0 +1,26 @@
+/**
+ * Rewrites a PDS getBlob URL to the site's own /blob route, which proxies the
+ * blob and applies image transformations where the platform provides them.
+ */
+
+const WIDTHS = [256, 1600] as const;
+export type BlobWidth = (typeof WIDTHS)[number];
+
+export function isBlobWidth(value: number): value is BlobWidth {
+ return (WIDTHS as readonly number[]).includes(value);
+}
+
+/** Unrecognized URLs pass through untouched. */
+export function blobProxyPath(blobUrl: string, width: BlobWidth): string {
+ let url: URL;
+ try {
+ url = new URL(blobUrl);
+ } catch {
+ return blobUrl;
+ }
+ if (url.pathname !== '/xrpc/com.atproto.sync.getBlob') return blobUrl;
+ const did = url.searchParams.get('did');
+ const cid = url.searchParams.get('cid');
+ if (!did || !cid) return blobUrl;
+ return `/blob/${encodeURIComponent(did)}/${encodeURIComponent(cid)}?w=${width}`;
+}
diff --git a/apps/web/src/lib/components/theme/SiteLayout.svelte b/apps/web/src/lib/components/theme/SiteLayout.svelte
index cfa6e43..3eab034 100644
--- a/apps/web/src/lib/components/theme/SiteLayout.svelte
+++ b/apps/web/src/lib/components/theme/SiteLayout.svelte
@@ -65,9 +65,9 @@
@@ -97,6 +97,7 @@
--accent: #9c3218;
--accent-ink: #fdfbf6;
--rule: #e0d8c8;
+ --airmail-blue: #1c3f6e;
--font-serif: 'Iowan Old Style', 'Hoefler Text', 'Palatino Linotype', Palatino,
'Book Antiqua', Georgia, serif;
@@ -134,6 +135,7 @@
--accent: #d4714f;
--accent-ink: #101520;
--rule: #242c3a;
+ --airmail-blue: #3a6ea8;
}
}
@@ -144,7 +146,7 @@
-45deg,
var(--accent) 0 10px,
var(--paper) 10px 20px,
- #1c3f6e 20px 30px,
+ var(--airmail-blue) 20px 30px,
var(--paper) 30px 40px
);
}
@@ -183,7 +185,9 @@
nav a {
color: var(--muted);
text-decoration: none;
- padding-bottom: 2px;
+ /* Small type, big target: pad the hit area without moving the layout. */
+ padding: 0.5rem 0.25rem 2px;
+ margin: -0.5rem -0.25rem 0;
border-bottom: 1px solid transparent;
transition: color 160ms ease, border-color 160ms ease;
}
@@ -227,6 +231,9 @@
footer a {
color: inherit;
+ display: inline-block;
+ padding: 0.45rem 0.25rem;
+ margin: -0.45rem -0.25rem;
}
.handle {
diff --git a/apps/web/src/lib/components/theme/SiteSections.svelte b/apps/web/src/lib/components/theme/SiteSections.svelte
index 09801ab..b5d84f2 100644
--- a/apps/web/src/lib/components/theme/SiteSections.svelte
+++ b/apps/web/src/lib/components/theme/SiteSections.svelte
@@ -1,7 +1,9 @@