Files
astro-website/openspec/changes/reduce-bounce-rate/tasks.md
Santhosh Janardhanan ac3de3e142
Some checks failed
ci / site (push) Has been cancelled
publish-image / publish (push) Has been cancelled
lazy-loading done
2026-02-10 15:59:03 -05:00

52 lines
4.9 KiB
Markdown

## 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.url``https://www.youtube.com/embed/{id}?rel=0&modestbranding=1`. For podcast, detect Spotify URLs → `https://open.spotify.com/embed/episode/{id}?theme=0`. For non-Spotify podcast URLs, hide the embed area and show a "Listen on [platform]" 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 "Follow 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" / "View 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.
## 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).
- [ ] 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.