89 lines
5.0 KiB
Markdown
89 lines
5.0 KiB
Markdown
## 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
|