Files
Santhosh Janardhanan 57ad560b01
Some checks failed
ci / site (push) Has been cancelled
publish-image / publish (push) Has been cancelled
fix for SR
2026-02-10 17:54:13 -05:00

5.2 KiB

1. Card component changes

  • 1.1 Add a mode prop (or equivalent) to StandardCard.astro to support rendering as a <button> (modal trigger) instead of an <a> link. When mode="modal", the root element MUST be a <button> (or role="button" tabindex="0") with the same visual styling as the current card.
  • 1.2 Add data-* attributes to modal-trigger cards in ContentCard.astro — encode id, source, url, title, summary, publishedAt, thumbnailUrl, and metrics.views so the modal script can read them on click.
  • 1.3 Update ContentCard.astro to use mode="modal" for youtube and podcast sources, and keep mode="link" (current behavior) for other sources.
  • 1.4 Change Umami event from outbound_click to media_preview on modal-trigger cards. Update data-umami-event-* attributes to include target_id, placement, title, type, and source (drop domain, target_url since it's no longer outbound).

2. Media modal component

  • 2.1 Create MediaModal.astro component containing a native <dialog> element with the modal layout: header (title + close button), embed area, description, date/views row, CTA row.
  • 2.2 Add CSS for the modal in global.css: backdrop styling, modal container, responsive layout (centered on desktop, near-full-width on mobile), embed aspect-ratio (16:9 for video), loading placeholder.
  • 2.3 Write the modal open/populate script: listen for clicks on modal-trigger cards, read data-* attributes, populate the modal fields (title, description, date, views), construct the embed URL, set the iframe src, and call dialog.showModal().
  • 2.4 Implement embed URL construction: extract YouTube video ID from item.urlhttps://www.youtube.com/embed/{id}?rel=0&modestbranding=1. For podcast, embed Spotify when a Spotify episode ID is available (https://open.spotify.com/embed/episode/{id}). For non-Spotify podcast URLs, render an in-modal audio player when an audioUrl is available, otherwise show a "Listen on Spotify" link.
  • 2.5 Implement playback stop on close: on dialog close event, set iframe src to about:blank (or remove the iframe) to guarantee playback stops.
  • 2.6 Implement all three close methods: close button click, Escape key (native <dialog> handles this), and backdrop click (detect clicks on <dialog> element outside the inner content container).

3. Modal accessibility

  • 3.1 Set aria-modal="true" and aria-labelledby (referencing the title element) on the <dialog>.
  • 3.2 Add aria-label="Close" to the close button.
  • 3.3 Implement focus return: store a reference to the clicked card before opening, restore focus to it on close.
  • 3.4 Verify focus trapping works with the native <dialog> (Tab cycles through modal focusables only).
  • 3.5 Verify prefers-reduced-motion suppresses modal open/close animations (covered by the existing global CSS rule).

4. Modal CTAs

  • 4.1 Render "Subscribe on YouTube" / "Follow on Spotify" CTA inside the modal, linking to the channel/podcast profile URL (from LINKS.youtubeChannel / LINKS.podcast). Apply UTM parameters.
  • 4.2 Render "View on YouTube" / "Listen on Spotify" CTA inside the modal, linking to the specific content item URL. Apply UTM parameters.
  • 4.3 Add data-umami-event="cta_click" with target_id=modal.cta.{action}.{platform}, placement=media_modal, platform, and target_url on each modal CTA. Actions: subscribe/view for YouTube; follow/listen for Spotify.

5. Umami analytics updates

  • 5.1 Emit media_preview_close event on modal close with target_id (from the card that opened it) and close_method (button, escape, or backdrop). Use umami.track() JS API since close_method is determined at runtime.
  • 5.2 Verify media_preview event fires correctly from card data-umami-event attributes on listing surfaces (homepage newest, homepage high-performing, homepage podcast, videos list, podcast list).
  • 5.3 Update existing Umami attribute tests (site/tests/umami-attributes.test.ts) to expect media_preview instead of outbound_click for video/podcast cards.
  • 5.4 Add new test cases for modal CTA Umami attributes (cta_click, target_id, placement=media_modal).

6. Page integration

  • 6.1 Add the MediaModal component to index.astro (homepage).
  • 6.2 Add the MediaModal component to videos.astro.
  • 6.3 Add the MediaModal component to podcast.astro.

7. Verification

  • 7.1 Run npm run build in site/ and verify no build errors.
  • 7.2 Run npm test in site/ and verify all tests pass (including updated Umami attribute tests). Note: site/tests/blog-nav.test.ts is failing in the repo for reasons unrelated to this change.
  • 7.3 Manual smoke test: click a video card → modal opens with YouTube embed → close → playback stops. Repeat with Escape and backdrop click.
  • 7.4 Manual smoke test: click a podcast card → modal opens with Spotify embed (or fallback link) → close → playback stops.
  • 7.5 Verify modal accessibility: keyboard-only navigation, focus trap, focus return, screen reader announces dialog.
  • 7.6 Verify responsive behavior: modal layout on desktop and mobile viewports.