Browser caches /cms-images responses immutably for a year. When the
editor changes a focal point or alt text, the underlying transform
output changes too, but the URL stays the same — so the browser keeps
serving the previous bytes. Manual hard-reloads and /api/cache/clear
help once but not for visitors who already have the file.
- RustyImageTransformParams gains an optional `version` that
serializes as `_v` in the /cms-images URL.
- RustyImage.svelte takes a matching `version` prop and forwards it
through `baseParams`, so every <picture> source carries the tag.
- The post thumbnail passes `post._updated` (truncated to seconds)
as version. Each save bumps `_updated`, the URL changes, browsers
re-fetch.
`_v` is intentionally not consumed by `/cms-images` — its sole job is
to break the browser cache key. The server-side image-cache and the
RustyCMS transform cache key both ignore it, so disk usage doesn't
balloon when the version tag changes.
Three CI typecheck failures from the previous microformat patch:
- post.created is the only date field in the schema (no _created on the
generated PostEntry). Drop the _created fallback.
- postTag items can be a slug string OR a tag object. Type narrowing
with `'name' in tag` widened to `never`; pull the name through an
explicit `{ name?: string }` cast in @const so the iteration stays
honest about the runtime shape.
- author isn't on PostEntry either; cast at the use-site for the
hidden h-card author block.
Posts whose row*Content contains a `youtube_video` block now ship a
schema.org VideoObject per video alongside the existing BlogPosting /
Event JSON-LD. Lets Google attach a video rich-result to the post URL
(thumbnail, duration where available, embed/content URLs) instead of
treating the page as plain text whose body happens to be a single
iframe.
Thumbnail uses YouTube's predictable maxresdefault + hqdefault URLs;
upload date falls back to post.created when the embed has none.
Microformats:
- Wrap the post <article> in h-entry with p-name on the headline,
p-summary on the subheadline (or sr-only fallback from excerpt),
e-content on the rendered body, dt-published on the created date
(hidden time element) and an invisible p-author h-card. Tag names
are mirrored as hidden p-category entries so crawlers see them
even though the visual Tags component already links them.
- itemscope/itemtype maps to schema.org BlogPosting (or Event when
`isEvent`), aligning the invisible microdata with the existing
JSON-LD.
Keywords:
- When post.seoKeywords is empty, fall back to the comma-joined tag
names so <meta name="keywords"> still ships something meaningful.
The article template only rendered the H1 it could pluck from the
markdown body (`contentHeadlineHtml`). Posts whose body opens with H2
(or no heading) silently lost both the schema-level `headline` and
`subheadline` — they were used in SEO/JSON-LD/breadcrumb only.
Fall back to the structured fields when no inline H1 is present.
- Added support for a preview mode in the CMS, allowing draft content to be viewed without being indexed.
- Updated hooks and server logic to handle preview parameters, adjusting cache control and robots tags accordingly.
- Enhanced layout to display a preview notification when in preview mode, improving user experience for content editors.
- Extracted headline and body content from the post's HTML, allowing for distinct rendering of the headline and body in the post page.
- Updated the Svelte component to display the extracted headline and body content separately, enhancing the layout and readability of posts.
- Added `executeScripts` function to handle script elements within the comment slot, ensuring proper execution of inline scripts.
- Updated the comment slot container to utilize the new script execution functionality, enhancing dynamic content handling.
Auto-mode deadline_banner now resolves to the next future event across
all calendar_items in the CMS instead of requiring a manually-curated
items[] pool. Server load hooks (+page.server.ts for /, /[...slug],
/post/[slug]) call resolveDeadlineBannerBlocks which fetches the
global calendar_item list once and attaches it as items[] when mode
is "auto" and items[] is not already resolved. Component logic
unchanged — it still picks the soonest future entry.
Also:
- cms.ts: getCalendarItems() bulk list fetcher
- PostOverviewBlock.svelte: design defaults to "cards" when value is
empty string (not just null/undefined) so existing entries with
design: "" render
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Introduced keywords property in layout and page server files to enhance SEO capabilities.
- Updated relevant components to include keywords in meta tags for better search engine visibility.
- Changed site URLs in docker-compose and deployment configurations to remove "www" prefix for consistency.
- Improved image handling by introducing warmPostCardImages function for pre-fetching images in posts and tags.
- Enhanced PostCard component with responsive image sizes for better performance.
- Updated layout to include robots meta tag and JSON-LD structured data for improved SEO.
- Added loading state for images in TopBanner component to enhance user experience.
- Updated PostEntry type to include _rawImageUrl and _imageFocal for improved image management.
- Refactored image handling in various components to utilize the new properties, ensuring better focal point support and responsive image rendering.
- Introduced warmResponsiveImage function for pre-fetching image variants to optimize loading performance.
- Replaced CmsImage component with RustyImage in multiple blocks for consistent image processing.
- Added support for extracting focal points and alt text from CMS image fields.
- Introduced responsive image handling in TopBanner component, allowing for AVIF/WebP sources and LQIP placeholders.
- Updated image transformation functions to accommodate focal point parameters for better cropping.
- Refactored image URL resolution logic across various components and routes to utilize new image field structure.
- Set trailingSlash='always' globally via root layout.
- Update postHref, pageHref, Pagination, tag/breadcrumb hrefs, blog→posts
redirects to emit trailing slash.
- Match old Astro canonical so indexed URLs hit 200 directly instead of
308-redirect.