fix for SR
Some checks failed
ci / site (push) Has been cancelled
publish-image / publish (push) Has been cancelled

This commit is contained in:
2026-02-10 17:54:13 -05:00
parent 5d07e57256
commit 57ad560b01
18 changed files with 389 additions and 110 deletions

View File

@@ -0,0 +1,51 @@
## MODIFIED Requirements
### Requirement: Custom event tracking
When Umami is enabled, the site MUST support custom event emission for:
- `cta_click`
- `outbound_click`
- `media_preview`
- `media_preview_close`
- a general click interaction event for all instrumented clickable items (per the site tracking taxonomy)
Each emitted event MUST include enough properties to segment reports by platform and placement when applicable.
All tracked clickable items MUST emit events with a unique, consistent set of data elements as defined by the site tracking taxonomy, including at minimum `target_id` and `placement`.
The site MUST instrument tracked clickables using Umami's supported Track Events data-attribute method:
- `data-umami-event="<event-name>"`
- optional event data using `data-umami-event-*`
For interactions that are triggered programmatically (e.g., modal close events where the close method must be recorded), the site MAY use Umami's JavaScript API (`umami.track()`) instead of data attributes when data attributes cannot express the required properties.
For content-related links (clickables representing a specific piece of content), the site MUST also provide the following Umami event data attributes:
- `data-umami-event-title`
- `data-umami-event-type`
#### Scenario: Emit outbound click event
- **WHEN** a user clicks a non-CTA outbound link from the homepage
- **THEN** the system emits an `outbound_click` event with a property identifying the destination domain
#### Scenario: Emit general click event for any clickable
- **WHEN** a user clicks an instrumented navigation link
- **THEN** the system emits a click interaction event with `target_id` and `placement`
#### Scenario: Content click includes title and type
- **WHEN** a user clicks an instrumented content link (video, podcast episode, blog post/page)
- **THEN** the emitted Umami event includes `title` and `type` properties via `data-umami-event-*` attributes
#### Scenario: Uninstrumented clicks do not break the page
- **WHEN** a user clicks an element with no tracking metadata
- **THEN** the system does not throw and navigation/interaction proceeds normally
#### Scenario: Media preview event emitted on card click
- **WHEN** a user clicks a video or podcast content card that opens a media modal
- **THEN** the system emits a `media_preview` event with `target_id`, `placement`, `title`, `type`, and `source`
#### Scenario: Media preview close event emitted
- **WHEN** a user closes the media modal
- **THEN** the system emits a `media_preview_close` event with the `target_id` of the content that was previewed and the `close_method` used
#### Scenario: Modal CTA click emitted
- **WHEN** a user clicks a CTA inside the media modal (e.g., "View on YouTube")
- **THEN** the system emits a `cta_click` event with `target_id`, `placement=media_modal`, `platform`, and `target_url`

View File

@@ -0,0 +1,45 @@
## MODIFIED Requirements
### Requirement: Standard card information architecture
All content cards rendered by the site MUST use a standardized layout so cards across different surfaces look consistent.
The standard card layout MUST be:
- featured image displayed prominently at the top (when available)
- title
- summary/excerpt text, trimmed to a fixed maximum length
- footer row showing:
- publish date on the left
- views when available (if omitted, the footer MUST still render cleanly)
- the content source label (e.g., `youtube`, `podcast`, `blog`)
If a field is not available (for example, views for some sources), the card MUST still render cleanly with that field omitted.
For content cards with source `youtube` or `podcast`, the card MUST render as a clickable element that opens a media modal dialog instead of navigating to an external URL. The card MUST NOT render as an outbound `<a>` link for these sources.
For content cards with other sources (e.g., `blog`, `instagram`), the card MUST continue to render as a navigational link (the existing behavior).
The card element for modal-trigger cards MUST carry the content item's data (id, source, url, title, summary, publishedAt, thumbnailUrl, views) as `data-*` attributes so the modal script can access them.
#### Scenario: Card renders with all fields
- **WHEN** a content item has an image, title, summary, publish date, views, and source
- **THEN** the card renders those fields in the standard card layout order
#### Scenario: Card renders without views
- **WHEN** a content item has no views data
- **THEN** the card renders the footer bar with date + source and omits views without breaking the layout
#### Scenario: Card renders without featured image
- **WHEN** a content item has no featured image
- **THEN** the card renders a placeholder media area and still renders the remaining fields
#### Scenario: YouTube video card opens modal
- **WHEN** a user clicks a content card with source `youtube`
- **THEN** a media modal dialog opens with the video's embedded player and metadata instead of navigating to YouTube
#### Scenario: Podcast card opens modal
- **WHEN** a user clicks a content card with source `podcast`
- **THEN** a media modal dialog opens with the episode's embedded player (or metadata link) instead of navigating to the podcast platform
#### Scenario: Blog card still navigates
- **WHEN** a user clicks a content card with source `blog`
- **THEN** the card navigates to the blog post as an internal link (existing behavior, unaffected)

View File

@@ -0,0 +1,48 @@
## ADDED Requirements
### Requirement: Modal CTAs for YouTube and Spotify
The media modal MUST render two CTA actions:
- "Subscribe on YouTube" / "Follow on Spotify" — links to the channel/podcast profile page
- "View on YouTube" / "Listen on Spotify" — links to the specific content item URL
The CTA label and destination MUST be determined by the content source:
- For `youtube` source: "Subscribe on YouTube" links to the YouTube channel URL, "View on YouTube" links to the video URL
- For `podcast` source: "Follow on Spotify" links to the podcast profile URL, "Listen on Spotify" links to the episode URL
Each CTA MUST be rendered using the existing `CtaLink` component conventions (or equivalent markup) with UTM parameters appended.
#### Scenario: YouTube video modal shows YouTube CTAs
- **WHEN** the media modal is displaying a YouTube video
- **THEN** the modal renders "Subscribe on YouTube" (linking to the channel) and "View on YouTube" (linking to the video URL) as CTA actions
#### Scenario: Podcast episode modal shows Spotify CTAs
- **WHEN** the media modal is displaying a podcast episode
- **THEN** the modal renders "Follow on Spotify" (linking to the podcast profile) and "Listen on Spotify" (linking to the episode URL) as CTA actions
### Requirement: Modal CTA tracking
Each CTA rendered inside the media modal MUST emit a `cta_click` event conforming to the existing CTA tracking requirements.
The modal CTAs MUST use:
- `placement=media_modal`
- `target_id` following the `modal.cta.{action}.{platform}` namespace
- `platform` set to `youtube` or `spotify` (mapped from content source)
#### Scenario: Modal CTA emits cta_click event
- **WHEN** a user clicks the "Subscribe on YouTube" CTA inside the media modal
- **THEN** the system emits a `cta_click` event with `target_id=modal.cta.subscribe.youtube`, `placement=media_modal`, `platform=youtube`, and `target_url` set to the YouTube channel URL
#### Scenario: Modal CTA emits cta_click event (secondary)
- **WHEN** a user clicks the "View on YouTube" CTA inside the media modal
- **THEN** the system emits a `cta_click` event with `target_id=modal.cta.view.youtube`, `placement=media_modal`, `platform=youtube`, and `target_url` set to the video URL
#### Scenario: Modal CTA emits cta_click event (podcast)
- **WHEN** a user clicks the "Follow on Spotify" CTA inside the media modal
- **THEN** the system emits a `cta_click` event with `target_id=modal.cta.follow.spotify`, `placement=media_modal`, `platform=spotify`, and `target_url` set to the podcast profile URL
#### Scenario: Modal CTA emits cta_click event (podcast secondary)
- **WHEN** a user clicks the "Listen on Spotify" CTA inside the media modal
- **THEN** the system emits a `cta_click` event with `target_id=modal.cta.listen.spotify`, `placement=media_modal`, `platform=spotify`, and `target_url` set to the episode URL
#### Scenario: Modal CTA includes UTM parameters
- **WHEN** a modal CTA is rendered
- **THEN** the CTA link URL includes UTM parameters for attribution (utm_source, utm_medium, utm_campaign, utm_content)

View File

@@ -0,0 +1,102 @@
## ADDED Requirements
### Requirement: Media preview event for in-page content views
The tracking taxonomy MUST define a `media_preview` event for content card clicks that open an in-page media modal instead of navigating outbound.
The `media_preview` event MUST include the following properties:
- `target_id` (stable unique identifier for the card, following the existing `card.{placement}.{source}.{id}` format)
- `placement` (the listing surface where the card appears, e.g., `home.newest`, `videos.list`, `podcast.list`)
- `title` (human-readable content title, truncated to max 160 characters)
- `type` (`video` or `podcast_episode`)
- `source` (`youtube` or `podcast`)
#### Scenario: Video card click emits media_preview
- **WHEN** a user clicks a YouTube video card on the videos listing page
- **THEN** the system emits a `media_preview` event with `target_id=card.videos.list.youtube.{id}`, `placement=videos.list`, `type=video`, and `source=youtube`
#### Scenario: Podcast card click emits media_preview on homepage
- **WHEN** a user clicks a podcast card in the homepage podcast section
- **THEN** the system emits a `media_preview` event with `target_id=card.home.podcast.podcast.{id}`, `placement=home.podcast`, `type=podcast_episode`, and `source=podcast`
### Requirement: Media preview close event
The tracking taxonomy MUST define a `media_preview_close` event emitted when the media modal is dismissed.
The `media_preview_close` event MUST include:
- `target_id` (the same identifier as the `media_preview` event that opened the modal)
- `close_method` (one of: `button`, `escape`, `backdrop`)
#### Scenario: User closes modal via Escape key
- **WHEN** the user presses Escape to close the media modal that was opened from a video card
- **THEN** the system emits a `media_preview_close` event with the original `target_id` and `close_method=escape`
#### Scenario: User closes modal via close button
- **WHEN** the user clicks the close button on the media modal
- **THEN** the system emits a `media_preview_close` event with the original `target_id` and `close_method=button`
#### Scenario: User closes modal via backdrop click
- **WHEN** the user clicks the backdrop outside the modal content
- **THEN** the system emits a `media_preview_close` event with the original `target_id` and `close_method=backdrop`
### Requirement: Modal CTA namespace
The tracking taxonomy MUST define a `media_modal` placement value for CTA interactions within the media modal.
Modal CTAs MUST use `target_id` values in the namespace `modal.cta.{action}.{platform}`.
The `action` value MUST be one of:
- `subscribe` (YouTube channel)
- `view` (YouTube video)
- `follow` (Spotify podcast profile)
- `listen` (Spotify episode)
#### Scenario: User clicks "View on YouTube" in modal
- **WHEN** the user clicks the "View on YouTube" CTA inside the media modal
- **THEN** the system emits a `cta_click` event with `target_id=modal.cta.view.youtube`, `placement=media_modal`, and `platform=youtube`
#### Scenario: User clicks "Subscribe on YouTube" in modal
- **WHEN** the user clicks the "Subscribe on YouTube" CTA inside the media modal
- **THEN** the system emits a `cta_click` event with `target_id=modal.cta.subscribe.youtube`, `placement=media_modal`, and `platform=youtube`
#### Scenario: User clicks "Follow on Spotify" in modal
- **WHEN** the user clicks the "Follow on Spotify" CTA inside the media modal
- **THEN** the system emits a `cta_click` event with `target_id=modal.cta.follow.spotify`, `placement=media_modal`, and `platform=spotify`
#### Scenario: User clicks "Listen on Spotify" in modal
- **WHEN** the user clicks the "Listen on Spotify" CTA inside the media modal
- **THEN** the system emits a `cta_click` event with `target_id=modal.cta.listen.spotify`, `placement=media_modal`, and `platform=spotify`
## MODIFIED Requirements
### Requirement: Minimum required properties
Every tracked click event MUST include, at minimum:
- `target_id`
- `placement`
For links, the event MUST also include:
- `target_url` (or a stable target identifier that can be mapped to a URL)
For content-related links (clickables representing a specific piece of content), the event MUST also include:
- `title` (human-readable content title)
- `type` (content type identifier)
The `type` value MUST be one of:
- `video`
- `podcast_episode`
- `blog_post`
- `blog_page`
For non-link clickables that trigger in-page actions (e.g., modal openers), the event MUST also include:
- `title` (human-readable content title)
- `type` (content type identifier)
- `source` (content source identifier)
#### Scenario: Tracking a content card click
- **WHEN** a user clicks a content card link
- **THEN** the emitted event includes `target_id`, `placement`, and `target_url`
#### Scenario: Tracking a content link includes title and type
- **WHEN** a user clicks a content-related link that represents a specific content item
- **THEN** the emitted event includes `target_id`, `placement`, `target_url`, `title`, and `type`
#### Scenario: Tracking a modal-trigger card includes title, type, and source
- **WHEN** a user clicks a content card that opens a media modal instead of navigating
- **THEN** the emitted event includes `target_id`, `placement`, `title`, `type`, and `source` (no `target_url` since the user stays on-page)

View File

@@ -0,0 +1,88 @@
## ADDED Requirements
### Requirement: Media modal dialog
The site MUST provide a modal dialog that displays embedded media (YouTube video or podcast episode) when a user clicks a video or podcast content card on a listing surface (homepage, `/videos`, `/podcast`).
The modal MUST render the following elements in order:
- A header row with the content title on the left and a close button on the right
- An embedded media player (YouTube iframe for videos; Spotify embed for podcast episodes when the URL is a Spotify URL; otherwise an in-modal audio player when an `audioUrl` is available)
- The full description/summary text (not truncated)
- The publish date and view count (when available)
- A "Subscribe on YouTube" / "Follow on Spotify" CTA and a "View on YouTube" / "Listen on Spotify" CTA
#### Scenario: User clicks a YouTube video card
- **WHEN** a user clicks a video content card on any listing surface
- **THEN** a modal dialog opens displaying a YouTube iframe embed, the video title, full description, date, view count (if available), and CTAs for "Subscribe on YouTube" and "View on YouTube"
#### Scenario: User clicks a podcast episode card with a Spotify URL
- **WHEN** a user clicks a podcast content card whose URL is a Spotify URL
- **THEN** a modal dialog opens displaying a Spotify episode embed, the episode title, full description, date, and CTAs for "Follow on Spotify" and "Listen on Spotify"
#### Scenario: User clicks a podcast episode card with a non-Spotify URL
- **WHEN** a user clicks a podcast content card whose URL is not a Spotify URL
- **THEN** the modal dialog opens displaying the episode metadata (title, description, date) and either:
- an in-modal audio player when an `audioUrl` is available
- otherwise, a "Listen on Spotify" outbound link
#### Scenario: Modal renders with missing optional fields
- **WHEN** a content item has no view count or no summary
- **THEN** the modal MUST still render cleanly with those fields omitted
### Requirement: Playback stops on modal close
The modal MUST stop all media playback when it is dismissed, regardless of the dismissal method.
The modal MUST support three dismissal methods:
- Close button click
- Pressing the `Escape` key
- Clicking the backdrop outside the modal content
After dismissal, no audio or video from the embedded player MUST continue playing.
#### Scenario: User closes modal via close button
- **WHEN** the modal is open with a playing YouTube video and the user clicks the close button
- **THEN** the modal closes and the video playback stops immediately
#### Scenario: User presses Escape while modal is open
- **WHEN** the modal is open with a playing Spotify episode and the user presses the `Escape` key
- **THEN** the modal closes and the audio playback stops immediately
#### Scenario: User clicks the backdrop
- **WHEN** the modal is open and the user clicks outside the modal content area (the backdrop)
- **THEN** the modal closes and any active media playback stops immediately
### Requirement: Modal accessibility
The modal MUST conform to WCAG 2.2 AA dialog patterns:
- The modal MUST use the native `<dialog>` element opened via `showModal()`
- The modal MUST trap keyboard focus within the dialog while open
- The modal MUST set `aria-modal="true"` and have an accessible label (via `aria-labelledby` referencing the title element)
- Closing the modal MUST return focus to the element that triggered it (the card that was clicked)
- The close button MUST have an accessible label (e.g., `aria-label="Close"`)
#### Scenario: Focus is trapped within the modal
- **WHEN** the modal is open and the user presses `Tab`
- **THEN** focus cycles through the focusable elements within the modal and does not move to elements behind the modal
#### Scenario: Focus returns to trigger on close
- **WHEN** the user closes the modal
- **THEN** focus returns to the card element that originally opened the modal
### Requirement: Responsive modal layout
The modal MUST be responsive across viewports:
- On desktop viewports, the modal MUST be centered with a max-width that leaves visible backdrop on both sides
- On mobile viewports (at or below the site's mobile breakpoint), the modal MUST expand to near-full viewport width with reduced padding
- Embedded media MUST scale proportionally (16:9 aspect ratio for YouTube video, fixed height for Spotify embed)
#### Scenario: Modal on desktop viewport
- **WHEN** the modal is opened on a desktop viewport
- **THEN** the modal is centered horizontally with backdrop visible and the video embed maintains a 16:9 aspect ratio
#### Scenario: Modal on mobile viewport
- **WHEN** the modal is opened on a mobile viewport
- **THEN** the modal expands to near-full viewport width and the video embed scales to fit
### Requirement: Embed loading state
The modal MUST display a loading placeholder while the embedded media iframe is loading.
#### Scenario: Iframe loading
- **WHEN** the modal opens and the iframe has not yet loaded
- **THEN** a placeholder (matching the site's card-placeholder style) is visible in the embed area until the iframe finishes loading