Commits
* just some quick things to make it look better
* adding things to make the comments more legible
* adjust styling to make the comments and bsky posts more uniform
* combine comments and bsky mentions in all places
* show discussion from postLink everywhere where there is a postLink
* tabbing replies and quotes in the bluesky thread viewer, fixing a ton of
styling
* open threads in the drawer rather than as new pages
* standard site posts open in interaction drawer on posts
* bottom sheet to open on mobile rather than a drawer
* little fixes
* Scope subpage comment counts and panel to the page
Comment counts on the post page all came from the document-wide
commentsCount aggregate, so every subpage block and the bottom comments
button showed the whole document's comment total. The subpage block's
comment icon also opened a standalone discussion modal.
- Compute a per-page comment count map (commentsCountByPage) in
getPostPageData from each comment's onPage; expose it via DocumentContext
- Subpage block comment button now opens the subpage and its interaction
panel scoped to comments, instead of the discussion modal
- Bottom comments button, post header, canvas page, and the drawer toggle
now show the count for their own page
* update cover images in medium size standard site post block to be
smaller
* more tweak
* default open comments/quotes if present
---------
Co-authored-by: Jared Pereira <jared@awarm.space>
* Use Supabase image transform for publication homepage cover thumbnails
Publication homepage post lists displayed full-resolution cover image
blobs (proxied from the PDS via /api/atproto_images) at small thumbnail
sizes. Now, when a cover image is present, request a downscaled version:
the proxy caches the blob in the url-previews bucket and redirects to a
Supabase image-transform URL sized for the variant, avoiding shipping the
full-size image just to render a thumbnail.
* Apply Supabase thumbnail transform to feed and standard-site post covers
Extend the cover-image thumbnail transform to the reader feed
(PostListing) and the standard-site post block (StandardSitePostItem),
which also rendered full-resolution cover blobs at thumbnail sizes.
* Stream transformed cover thumbnails instead of redirecting
Replace the 307 redirect to Supabase's public transform URL with
streaming the transformed bytes directly through the proxy. This keeps
thumbnails to a single round trip served with our own immutable cache
headers, avoiding the extra redirect hop on cold browser loads. The blob
is still cached in the url-previews bucket and downscaled via Supabase's
image transform on first request.
* Cache transformed cover thumbnails at the edge for a year
These thumbnails are derived from content-addressed (immutable) CIDs at a
fixed width, so they never change. Bump the thumbnail edge cache
(CDN-Cache-Control) from one day to a year to match the browser TTL and
avoid needless re-pulls of immutable content.
* Cache full-resolution PDS blobs at the edge for a year too
Full images are addressed by the same content-addressed (immutable) CIDs
as thumbnails, so bump their edge cache (CDN-Cache-Control) from one day
to a year as well. Generalize the shared constant now that both paths use
it.
* Simplify CDN cache comment
* Simplify thumbnail transform changes
- Reuse the shared supabaseServerClient instead of re-creating the
service-role client inline in the atproto_images route.
- Centralize the duplicated 800/360 thumbnail widths into a single
COVER_THUMBNAIL_WIDTH constant used by all three cover-image call sites.
---------
Co-authored-by: Claude <noreply@anthropic.com>
The crop in #286 was in the image *serving* path, not upload. The
next/image custom loader (supabase-image-loader.js) hit Supabase's
render/image endpoint without a resize param, so it defaulted to
resize=cover. Because next/image only passes `width` to a custom loader
(never height), imgproxy filled the missing height with the source
height and cropped the width to fit the box — chopping the right side
off large images.
Verified against the reported image on prod (5712x4284) and locally:
width=3840 -> cropped (full source height kept)
width=2500 -> still cropped (clamping width alone does not help)
width=3840&resize=contain -> correct aspect, no crop
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Profile description mentions were linking to internal Leaflet profile
pages (/p/handle). Since these are Bluesky handles, link them to the
user's Bluesky profile on bsky.app instead, opening in a new tab.
Co-authored-by: Claude <noreply@anthropic.com>
Refactor/profile data cache
* optimize homepage leaflets query
* seperate static landing page
* wrap legal in suspense boundary
* login tweaks
* don't show untitled for logged out users
* fix adding empty doc to home from new button
* just some quick things to make it look better
* adding things to make the comments more legible
* adjust styling to make the comments and bsky posts more uniform
* combine comments and bsky mentions in all places
* show discussion from postLink everywhere where there is a postLink
* tabbing replies and quotes in the bluesky thread viewer, fixing a ton of
styling
* open threads in the drawer rather than as new pages
* standard site posts open in interaction drawer on posts
* bottom sheet to open on mobile rather than a drawer
* little fixes
* Scope subpage comment counts and panel to the page
Comment counts on the post page all came from the document-wide
commentsCount aggregate, so every subpage block and the bottom comments
button showed the whole document's comment total. The subpage block's
comment icon also opened a standalone discussion modal.
- Compute a per-page comment count map (commentsCountByPage) in
getPostPageData from each comment's onPage; expose it via DocumentContext
- Subpage block comment button now opens the subpage and its interaction
panel scoped to comments, instead of the discussion modal
- Bottom comments button, post header, canvas page, and the drawer toggle
now show the count for their own page
* update cover images in medium size standard site post block to be
smaller
* more tweak
* default open comments/quotes if present
---------
Co-authored-by: Jared Pereira <jared@awarm.space>
* Use Supabase image transform for publication homepage cover thumbnails
Publication homepage post lists displayed full-resolution cover image
blobs (proxied from the PDS via /api/atproto_images) at small thumbnail
sizes. Now, when a cover image is present, request a downscaled version:
the proxy caches the blob in the url-previews bucket and redirects to a
Supabase image-transform URL sized for the variant, avoiding shipping the
full-size image just to render a thumbnail.
* Apply Supabase thumbnail transform to feed and standard-site post covers
Extend the cover-image thumbnail transform to the reader feed
(PostListing) and the standard-site post block (StandardSitePostItem),
which also rendered full-resolution cover blobs at thumbnail sizes.
* Stream transformed cover thumbnails instead of redirecting
Replace the 307 redirect to Supabase's public transform URL with
streaming the transformed bytes directly through the proxy. This keeps
thumbnails to a single round trip served with our own immutable cache
headers, avoiding the extra redirect hop on cold browser loads. The blob
is still cached in the url-previews bucket and downscaled via Supabase's
image transform on first request.
* Cache transformed cover thumbnails at the edge for a year
These thumbnails are derived from content-addressed (immutable) CIDs at a
fixed width, so they never change. Bump the thumbnail edge cache
(CDN-Cache-Control) from one day to a year to match the browser TTL and
avoid needless re-pulls of immutable content.
* Cache full-resolution PDS blobs at the edge for a year too
Full images are addressed by the same content-addressed (immutable) CIDs
as thumbnails, so bump their edge cache (CDN-Cache-Control) from one day
to a year as well. Generalize the shared constant now that both paths use
it.
* Simplify CDN cache comment
* Simplify thumbnail transform changes
- Reuse the shared supabaseServerClient instead of re-creating the
service-role client inline in the atproto_images route.
- Centralize the duplicated 800/360 thumbnail widths into a single
COVER_THUMBNAIL_WIDTH constant used by all three cover-image call sites.
---------
Co-authored-by: Claude <noreply@anthropic.com>
The crop in #286 was in the image *serving* path, not upload. The
next/image custom loader (supabase-image-loader.js) hit Supabase's
render/image endpoint without a resize param, so it defaulted to
resize=cover. Because next/image only passes `width` to a custom loader
(never height), imgproxy filled the missing height with the source
height and cropped the width to fit the box — chopping the right side
off large images.
Verified against the reported image on prod (5712x4284) and locally:
width=3840 -> cropped (full source height kept)
width=2500 -> still cropped (clamping width alone does not help)
width=3840&resize=contain -> correct aspect, no crop
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>