Skip to content

Add video support#47

Open
RobbieTheWagner wants to merge 1 commit into
mainfrom
video-support
Open

Add video support#47
RobbieTheWagner wants to merge 1 commit into
mainfrom
video-support

Conversation

@RobbieTheWagner

@RobbieTheWagner RobbieTheWagner commented Jun 24, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Refreshed mobile navigation with a sticky app bar and an accessible slide-over menu, including Escape/scrim dismissal and focus trapping.
    • Added video-capable episode playback with a watch/listen switch and expandable/minimizable video theater.
    • Navigation/CTA label and destination can now be customized via site configuration.
  • Bug Fixes
    • Improved playback state so episode artwork and video sources stay in sync when switching episodes.
  • Documentation
    • Added comprehensive design-system and product/UX briefs for consistent UI behavior.
  • Tests
    • Expanded player unit coverage for video/media mode scenarios.

@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
starpod Ready Ready Preview, Comment Jul 24, 2026 7:43pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds HLS video playback from RSS alternate enclosures, a unified persistent video player, reusable episode CTAs, accessible mobile navigation, sticky layout wiring, configurable CTA resolution, and Starpod design/product documentation.

Changes

Starpod video playback, navigation, and design system

Layer / File(s) Summary
Episode video metadata and playback
package.json, src/lib/rss.ts, src/components/Player.tsx, src/components/player/..., tests/unit/Player.test.tsx
Adds HLS parsing and dependencies, replaces the audio-only player with a shared video element, and adds video-mode, theater, HLS, media-ref, styling, and test updates.
Episode CTA and state integration
src/components/state.ts, src/components/EpisodeCta.tsx, src/components/EpisodeList.astro, src/components/FullPlayButton.tsx, src/pages/[episode].astro
Adds media state and reusable audio/video CTAs, propagating video and artwork metadata through episode playback paths.
Responsive navigation and CTA wiring
src/components/MobileNav.tsx, src/layouts/Layout.astro, src/lib/cta.ts, src/lib/navLinks.ts, src/utils/config.ts, src/styles/global.css, .impeccable/live/config.json
Adds focus-trapped mobile navigation, sticky CTA/navigation layout, configurable CTA fallback resolution, shared links, and menu/play styling with reduced-motion support.
Design and product specifications
DESIGN.md, PRODUCT.md, .impeccable/briefs/..., .impeccable/design.json
Adds Starpod design tokens, component rules, product scope, accessibility requirements, implementation brief, and machine-readable design metadata.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Listener
  participant EpisodeCta
  participant State
  participant Player
  participant RSS
  participant VideoElement

  Listener->>EpisodeCta: select audio or video CTA
  EpisodeCta->>State: update episode, mode, and playback state
  State-->>Player: propagate reactive state
  Player->>RSS: use episode video source
  Player->>VideoElement: load native or HLS source
  VideoElement-->>Player: emit metadata and playback events
  Player->>State: synchronize position and playing state
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding video support across playback, data, and UI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch video-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/FullPlayButton.tsx (1)

59-68: 🎯 Functional Correctness | 🟡 Minor

Set playback mode explicitly in FullPlayButton
currentEpisode is updated here, but mediaMode and isTheaterOpen are left as-is. Since mediaMode defaults to 'video', list play on an episode with video will start video playback while the theater stays closed, and later clicks inherit whatever mode a previous CTA left behind. Set mediaMode.value here (and open the theater for video, or force 'audio' if this button should stay audio-only).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/FullPlayButton.tsx` around lines 59 - 68, `FullPlayButton`
updates `currentEpisode` and `isPlaying`, but leaves `mediaMode` and
`isTheaterOpen` stale, so playback can inherit the previous CTA state. In the
`FullPlayButton` click flow where `currentEpisode.value` is assigned, explicitly
set `mediaMode.value` to the intended mode for this button and update
`isTheaterOpen.value` accordingly when starting video playback, or force audio
mode if this action should remain audio-only. Keep the behavior localized to
this handler so future clicks always start from a predictable state.
🧹 Nitpick comments (3)
src/components/EpisodeCta.tsx (1)

100-100: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor consistency nits.

  • Line 100: becomingCurrent ? true : false is just becomingCurrent.
  • Line 116 casts the icon as JSX.Element but the pill variant (Line 126) does not. Align them or drop the cast.

Also applies to: 116-116, 126-126

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/EpisodeCta.tsx` at line 100, Simplify the conditional
assignment in EpisodeCta so isPlaying.value uses becomingCurrent directly
instead of a ternary that returns true/false. Also make the icon rendering
consistent between the two branches by either removing the unnecessary
JSX.Element cast on the icon in the current branch or adding the same cast in
the pill variant branch, using the existing render logic around EpisodeCta and
its icon/pill JSX.
src/pages/[episode].astro (1)

170-183: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

CTA wiring looks correct; consider extracting the repeated episode literal.

The same episode={{ audio, video, episodeImage, episodeNumber, id, title }} object is duplicated four times. Hoisting it into a single frontmatter const (e.g. const ctaEpisode = {...}) would remove the repetition and keep the field list in sync.

Also applies to: 204-247

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/`[episode].astro around lines 170 - 183, The EpisodeCta usage is
repeating the same episode object shape in multiple places, so hoist that
literal into a single frontmatter constant in [episode].astro and reuse it
wherever EpisodeCta is rendered. Update the repeated EpisodeCta calls to
reference the shared object (using the existing audio, video, episodeImage,
episodeNumber, id, and title fields) so the field list stays synchronized across
all instances.
src/lib/rss.ts (1)

101-104: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

HLS type match is case-sensitive.

alt['@_type'] === HLS_TYPE requires an exact application/x-mpegURL. Feeds commonly use application/x-mpegurl (lowercase) or application/vnd.apple.mpegurl, which would be missed. A case-insensitive compare is more robust.

♻️ Proposed change
     const hls = alternates.find(
-      (alt: Record<string, unknown>) => alt['`@_type`'] === HLS_TYPE
+      (alt: Record<string, unknown>) =>
+        String(alt['`@_type`']).toLowerCase() === HLS_TYPE.toLowerCase()
     );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/rss.ts` around lines 101 - 104, The HLS alternate lookup in rss.ts is
too strict because the @'_type' comparison in the alternates.find logic only
matches one exact case/form. Update the HLS_TYPE matching in the relevant rss
parsing flow to do a case-insensitive comparison and accept common variants like
application/x-mpegurl and application/vnd.apple.mpegurl, while keeping the
existing hls selection behavior intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.impeccable/briefs/reshape-sticky-rail.md:
- Around line 145-147: The config-validation guidance is inconsistent with the
repository standard: update the `defineStarpodConfig` guidance for the new `cta`
field to recommend Valibot-based validation instead of an
identity-function/default skip. Keep the instructions aligned with the existing
config pattern in `defineStarpodConfig` and `starpod.config.ts`, and remove any
wording that tells implementers not to introduce Valibot in this pass.

In `@DESIGN.md`:
- Around line 295-300: The mobile navigation docs are out of sync with the
shipped layout behavior: the identity rail no longer moves its content into a
footer on mobile, and the architecture uses a mobile slide-over nav instead.
Update the relevant design text around the Identity rail and nav behavior to
describe the actual mobile slide-over pattern and remove any mention of a
mobile-only footer so future changes reference the correct structure.
- Around line 281-283: The focus styling guidance currently tells readers to use
!outline-none, but for Tailwind v4 the intended utility is outline-hidden when
hiding the default outline while preserving forced-colors behavior. Update the
focus indicator guidance in DESIGN.md to reference outline-hidden instead of
!outline-none, keeping the rest of the border-focused behavior described around
the focus state intact.

In `@src/components/Player.tsx`:
- Around line 28-30: The Player component has a Rules-of-Hooks issue because it
returns early when currentEpisode.value is null before its useEffect hooks run,
which changes hook order between renders. Move the guard below the hooks in
Player and keep the hooks unconditional, then add the null check inside each
useEffect body (or otherwise guard the effect logic) so the hook order stays
stable.

In `@src/lib/navLinks.ts`:
- Around line 15-20: The navLinks constant includes a show-specific hardcoded
Store URL, which makes the reusable template ship an чужд/incorrect link for
adopters. Update navLinks in navLinks.ts to remove that show-specific entry or
gate it behind configuration, and review the related sponsor link in the same
array to ensure only template-safe defaults remain.

---

Outside diff comments:
In `@src/components/FullPlayButton.tsx`:
- Around line 59-68: `FullPlayButton` updates `currentEpisode` and `isPlaying`,
but leaves `mediaMode` and `isTheaterOpen` stale, so playback can inherit the
previous CTA state. In the `FullPlayButton` click flow where
`currentEpisode.value` is assigned, explicitly set `mediaMode.value` to the
intended mode for this button and update `isTheaterOpen.value` accordingly when
starting video playback, or force audio mode if this action should remain
audio-only. Keep the behavior localized to this handler so future clicks always
start from a predictable state.

---

Nitpick comments:
In `@src/components/EpisodeCta.tsx`:
- Line 100: Simplify the conditional assignment in EpisodeCta so isPlaying.value
uses becomingCurrent directly instead of a ternary that returns true/false. Also
make the icon rendering consistent between the two branches by either removing
the unnecessary JSX.Element cast on the icon in the current branch or adding the
same cast in the pill variant branch, using the existing render logic around
EpisodeCta and its icon/pill JSX.

In `@src/lib/rss.ts`:
- Around line 101-104: The HLS alternate lookup in rss.ts is too strict because
the @'_type' comparison in the alternates.find logic only matches one exact
case/form. Update the HLS_TYPE matching in the relevant rss parsing flow to do a
case-insensitive comparison and accept common variants like
application/x-mpegurl and application/vnd.apple.mpegurl, while keeping the
existing hls selection behavior intact.

In `@src/pages/`[episode].astro:
- Around line 170-183: The EpisodeCta usage is repeating the same episode object
shape in multiple places, so hoist that literal into a single frontmatter
constant in [episode].astro and reuse it wherever EpisodeCta is rendered. Update
the repeated EpisodeCta calls to reference the shared object (using the existing
audio, video, episodeImage, episodeNumber, id, and title fields) so the field
list stays synchronized across all instances.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: af3b7ae5-a36b-496e-a50d-cce525b343ab

📥 Commits

Reviewing files that changed from the base of the PR and between 8c0de9f and 6e4862f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (25)
  • .impeccable/briefs/reshape-sticky-rail.md
  • .impeccable/design.json
  • .impeccable/live/config.json
  • DESIGN.md
  • PRODUCT.md
  • package.json
  • src/components/EpisodeCta.tsx
  • src/components/EpisodeList.astro
  • src/components/FullPlayButton.tsx
  • src/components/MobileNav.tsx
  • src/components/Player.tsx
  • src/components/player/ForwardButton/index.tsx
  • src/components/player/PlayButton.tsx
  • src/components/player/PlaybackRateButton.tsx
  • src/components/player/RewindButton/index.tsx
  • src/components/player/Slider/index.tsx
  • src/components/state.ts
  • src/layouts/Layout.astro
  • src/lib/cta.ts
  • src/lib/navLinks.ts
  • src/lib/rss.ts
  • src/pages/[episode].astro
  • src/styles/global.css
  • src/utils/config.ts
  • tests/unit/Player.test.tsx

Comment on lines +145 to +147
1. **Config validation:** `defineStarpodConfig` is currently an identity function
(no Valibot), despite CLAUDE.md. **Default:** keep the identity-function pattern
for the new `cta` field; don't introduce Valibot in this pass.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Align the config-validation default with repository standards.

Line 145-147 currently recommends skipping Valibot, which conflicts with the project rule and creates contradictory implementation guidance.

As per coding guidelines, src/utils/config.ts: "Use Valibot for configuration validation in starpod.config.ts."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.impeccable/briefs/reshape-sticky-rail.md around lines 145 - 147, The
config-validation guidance is inconsistent with the repository standard: update
the `defineStarpodConfig` guidance for the new `cta` field to recommend
Valibot-based validation instead of an identity-function/default skip. Keep the
instructions aligned with the existing config pattern in `defineStarpodConfig`
and `starpod.config.ts`, and remove any wording that tells implementers not to
introduce Valibot in this pass.

Source: Coding guidelines

Comment thread DESIGN.md
Comment on lines +281 to +283
- **Focus:** Border color shifts to the focused hairline tone; **ring and outline
are explicitly suppressed** (`!ring-0`, `!outline-none`) — the border shift is
the entire focus signal. Maintain a visible, AA-contrast focus indicator when

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant section in DESIGN.md
git ls-files DESIGN.md
wc -l DESIGN.md
sed -n '270,305p' DESIGN.md

Repository: shipshapecode/starpod

Length of output: 2067


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant section in DESIGN.md
git ls-files DESIGN.md
wc -l DESIGN.md
sed -n '270,305p' DESIGN.md

Repository: shipshapecode/starpod

Length of output: 2067


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate Tailwind-related version/config information
git ls-files | rg '(^|/)(package.json|pnpm-lock.yaml|package-lock.json|yarn.lock|tailwind\\.config\\.|tailwind\\.css|postcss\\.config\\.)$'
rg -n '"tailwindcss"|tailwindcss@|outline-hidden|outline-none' package.json pnpm-lock.yaml package-lock.json yarn.lock tailwind.config.* postcss.config.* DESIGN.md 2>/dev/null || true

Repository: shipshapecode/starpod

Length of output: 839


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate Tailwind-related version/config information
git ls-files | rg '(^|/)(package.json|pnpm-lock.yaml|package-lock.json|yarn.lock|tailwind\\.config\\.|tailwind\\.css|postcss\\.config\\.)$'
rg -n '"tailwindcss"|tailwindcss@|outline-hidden|outline-none' package.json pnpm-lock.yaml package-lock.json yarn.lock tailwind.config.* postcss.config.* DESIGN.md 2>/dev/null || true

Repository: shipshapecode/starpod

Length of output: 839


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate Tailwind-related version/config information
git ls-files | rg '(^|/)(package.json|pnpm-lock.yaml|package-lock.json|yarn.lock|tailwind\\.config\\.|tailwind\\.css|postcss\\.config\\.)$'
rg -n '"tailwindcss"|tailwindcss@|outline-hidden|outline-none' package.json pnpm-lock.yaml package-lock.json yarn.lock tailwind.config.* postcss.config.* DESIGN.md 2>/dev/null || true

Repository: shipshapecode/starpod

Length of output: 839


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find Tailwind version/config declarations
git ls-files | rg '(^|/)(package.json|pnpm-lock.yaml|package-lock.json|yarn.lock|tailwind\\.config\\.|postcss\\.config\\.)$'
for f in package.json pnpm-lock.yaml package-lock.json yarn.lock; do
  [ -f "$f" ] && { echo "== $f =="; rg -n '"tailwindcss"|tailwindcss@|outline-hidden|outline-none' "$f" || true; }
done

Repository: shipshapecode/starpod

Length of output: 651


🌐 Web query:

Tailwind CSS v4 outline-none outline-hidden docs

💡 Result:

In Tailwind CSS v4, the outline-none and outline-hidden utilities serve distinct purposes for managing browser focus styles [1][2]. outline-none In v4, this utility now sets the CSS outline-style property to none [3][2]. This is a departure from Tailwind CSS v3, where outline-none was implemented as a 2px solid transparent outline with a 2px offset to maintain visibility for users in forced-colors modes [4][5][6]. outline-hidden This utility was introduced in v4 to provide the behavior that outline-none previously offered [3][2]. It is specifically designed to hide the default browser outline while still preserving a visible focus state for users when forced-colors mode is active [1]. Recommendation Tailwind documentation highly recommends that you apply your own custom focus styling for accessibility whenever you use either of these utilities [1]. Use outline-hidden if you need to ensure accessibility compliance for users with forced-colors settings enabled [1].

Citations:


Use outline-hidden for Tailwind v4 focus styling. !outline-none is the v4 utility that removes the outline style; if the intent is to hide the default outline while preserving forced-colors behavior, switch to outline-hidden instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DESIGN.md` around lines 281 - 283, The focus styling guidance currently tells
readers to use !outline-none, but for Tailwind v4 the intended utility is
outline-hidden when hiding the default outline while preserving forced-colors
behavior. Update the focus indicator guidance in DESIGN.md to reference
outline-hidden instead of !outline-none, keeping the rest of the border-focused
behavior described around the focus state intact.

Comment thread DESIGN.md
Comment on lines +295 to +300
- **Identity rail:** A fixed left column (`28rem`/`lg`, `30rem`/`xl`) holding
artwork, title, blurb, listen links, and hosts. On mobile it collapses; rail
content (hosts, info) moves into the footer.
- **Nav links (`.animated-bottom-border`):** Body type with an **underline that
grows from left to right on hover** (gradient: Iris in light, Aqua in dark,
500ms ease).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update mobile navigation docs to match shipped layout behavior.

Line 297 says rail content moves into a footer, but the current architecture uses a mobile slide-over nav and removes the mobile-only footer. This doc mismatch will mislead follow-up changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DESIGN.md` around lines 295 - 300, The mobile navigation docs are out of sync
with the shipped layout behavior: the identity rail no longer moves its content
into a footer on mobile, and the architecture uses a mobile slide-over nav
instead. Update the relevant design text around the Identity rail and nav
behavior to describe the actual mobile slide-over pattern and remove any mention
of a mobile-only footer so future changes reference the correct structure.

Comment thread src/components/Player.tsx
Comment on lines 28 to 30
if (currentEpisode.value === null) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
ast-grep outline src/components/Player.tsx
git log --oneline -5 -- src/components/Player.tsx

Repository: shipshapecode/starpod

Length of output: 250


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant portion of Player.tsx with line numbers.
sed -n '1,260p' src/components/Player.tsx | nl -ba | sed -n '1,260p'

# Map the hook usage structurally, if possible, to confirm ordering.
ast-grep run --pattern $'function Player() {\n  $$$\n}' --lang tsx src/components/Player.tsx

Repository: shipshapecode/starpod

Length of output: 199


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant portion of Player.tsx with line numbers.
sed -n '1,260p' src/components/Player.tsx | nl -ba | sed -n '1,260p'

# Map the hook usage structurally, if possible, to confirm ordering.
ast-grep run --pattern $'function Player() {\n  $$$\n}' --lang tsx src/components/Player.tsx

Repository: shipshapecode/starpod

Length of output: 199


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant portion of Player.tsx with line numbers.
sed -n '1,260p' src/components/Player.tsx | nl -ba | sed -n '1,260p'

# Map the hook usage structurally, if possible, to confirm ordering.
ast-grep run --pattern $'function Player() {\n  $$$\n}' --lang tsx src/components/Player.tsx

Repository: shipshapecode/starpod

Length of output: 199


🏁 Script executed:

#!/bin/bash
set -euo pipefail

nl -ba src/components/Player.tsx | sed -n '1,240p'

Repository: shipshapecode/starpod

Length of output: 199


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the file with line numbers without relying on `nl`.
awk '{printf("%6d  %s\n", NR, $0)}' src/components/Player.tsx | sed -n '1,240p'

# Structural outline for hook ordering.
ast-grep outline src/components/Player.tsx --view expanded

Repository: shipshapecode/starpod

Length of output: 9987


Rules-of-Hooks violation: move the early return below the hooks. Player returns when currentEpisode.value === null before the useEffect calls, so hook order changes between the empty and loaded states. Keep the hooks unconditional and guard the effect bodies instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Player.tsx` around lines 28 - 30, The Player component has a
Rules-of-Hooks issue because it returns early when currentEpisode.value is null
before its useEffect hooks run, which changes hook order between renders. Move
the guard below the hooks in Player and keep the hooks unconditional, then add
the null check inside each useEffect body (or otherwise guard the effect logic)
so the hook order stays stable.

Comment thread src/lib/navLinks.ts
Comment on lines +15 to +20
export const navLinks: Array<NavLink> = [
{ label: 'About', href: '/about' },
{ label: 'Contact', href: '/contact' },
{ label: 'Store', href: 'https://whiskey.fund/' },
{ label: 'Become a sponsor', href: '/sponsor' }
];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Show-specific URL hardcoded in a template-level constant.

Starpod is a reusable podcast template, but { label: 'Store', href: 'https://whiskey.fund/' } (and arguably /sponsor) is specific to one show. Adopters who copy this template will ship a broken/foreign Store link. Until the planned config migration noted above lands, consider dropping the show-specific entry or moving it behind config.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/navLinks.ts` around lines 15 - 20, The navLinks constant includes a
show-specific hardcoded Store URL, which makes the reusable template ship an
чужд/incorrect link for adopters. Update navLinks in navLinks.ts to remove that
show-specific entry or gate it behind configuration, and review the related
sponsor link in the same array to ensure only template-safe defaults remain.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/unit/Player.test.tsx (1)

4-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the configured bare src/... import.

Change ../../src/components/state to src/components/state so this test follows the repository’s TypeScript import convention.

Proposed fix
-from '../../src/components/state';
+from 'src/components/state';

As per coding guidelines, **/*.{ts,tsx} should use strict TypeScript settings and prefer bare src/... imports enabled by baseUrl: ".".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/Player.test.tsx` around lines 4 - 10, Update the state import in
Player.test.tsx to use the configured bare src/components/state path instead of
the relative ../../src/components/state path, leaving the imported symbols
unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@DESIGN.md`:
- Around line 100-104: Update the input-focus token in DESIGN.md to include the
focused hairline/border color required by the surrounding documentation, while
preserving its existing backgroundColor, textColor, rounded, and padding values.

---

Nitpick comments:
In `@tests/unit/Player.test.tsx`:
- Around line 4-10: Update the state import in Player.test.tsx to use the
configured bare src/components/state path instead of the relative
../../src/components/state path, leaving the imported symbols unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d1a8350a-8e9d-4349-babd-0c23c06ca7bb

📥 Commits

Reviewing files that changed from the base of the PR and between 6e4862f and c34d98f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (25)
  • .impeccable/briefs/reshape-sticky-rail.md
  • .impeccable/design.json
  • .impeccable/live/config.json
  • DESIGN.md
  • PRODUCT.md
  • package.json
  • src/components/EpisodeCta.tsx
  • src/components/EpisodeList.astro
  • src/components/FullPlayButton.tsx
  • src/components/MobileNav.tsx
  • src/components/Player.tsx
  • src/components/player/ForwardButton/index.tsx
  • src/components/player/PlayButton.tsx
  • src/components/player/PlaybackRateButton.tsx
  • src/components/player/RewindButton/index.tsx
  • src/components/player/Slider/index.tsx
  • src/components/state.ts
  • src/layouts/Layout.astro
  • src/lib/cta.ts
  • src/lib/navLinks.ts
  • src/lib/rss.ts
  • src/pages/[episode].astro
  • src/styles/global.css
  • src/utils/config.ts
  • tests/unit/Player.test.tsx
🚧 Files skipped from review as they are similar to previous changes (22)
  • src/components/EpisodeList.astro
  • src/components/FullPlayButton.tsx
  • src/utils/config.ts
  • PRODUCT.md
  • src/lib/navLinks.ts
  • src/pages/[episode].astro
  • src/components/player/PlayButton.tsx
  • src/components/player/RewindButton/index.tsx
  • src/lib/cta.ts
  • .impeccable/live/config.json
  • src/components/MobileNav.tsx
  • src/components/state.ts
  • package.json
  • src/styles/global.css
  • src/components/player/Slider/index.tsx
  • .impeccable/briefs/reshape-sticky-rail.md
  • src/components/player/ForwardButton/index.tsx
  • src/layouts/Layout.astro
  • .impeccable/design.json
  • src/lib/rss.ts
  • src/components/EpisodeCta.tsx
  • src/components/Player.tsx

Comment thread DESIGN.md
Comment on lines +100 to +104
input-focus:
backgroundColor: "{colors.white}"
textColor: "{colors.light-text-body}"
rounded: "{rounded.sm}"
padding: "1rem"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include the focused border color in input-focus.

The prose below requires the focused hairline color, but this machine-readable token only repeats the default input styling. Consumers resolving input-focus will lose the documented focus-state distinction.

Proposed fix
  input-focus:
    backgroundColor: "{colors.white}"
    textColor: "{colors.light-text-body}"
    rounded: "{rounded.sm}"
    padding: "1rem"
+   borderColor: "{colors.light-input-border-focused}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
input-focus:
backgroundColor: "{colors.white}"
textColor: "{colors.light-text-body}"
rounded: "{rounded.sm}"
padding: "1rem"
input-focus:
backgroundColor: "{colors.white}"
textColor: "{colors.light-text-body}"
rounded: "{rounded.sm}"
padding: "1rem"
borderColor: "{colors.light-input-border-focused}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DESIGN.md` around lines 100 - 104, Update the input-focus token in DESIGN.md
to include the focused hairline/border color required by the surrounding
documentation, while preserving its existing backgroundColor, textColor,
rounded, and padding values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant