Skip to content

feat(web): add series detail page at /series/<series_id>#44

Open
andykais wants to merge 11 commits into
mainfrom
claude/add-series-detail-page-JSzq0
Open

feat(web): add series detail page at /series/<series_id>#44
andykais wants to merge 11 commits into
mainfrom
claude/add-series-detail-page-JSzq0

Conversation

@andykais

Copy link
Copy Markdown
Owner

Implement a new page for viewing media series items with similar UI to the
browse page but specialized for series navigation.

Features:

  • New route at /series/[series_id] with full SvelteKit page structure
  • SeriesController and SeriesQueryParamsManager for series-specific state
  • Series-specific search filters and sort options (including series_index)
  • Display series_index number under each media tile in series view
  • Link from browse page media tiles to series detail page
  • Reuse browse components where possible (MediaDetails, MediaView, Footer)
  • Default sort by series_index in ascending order

Changes:

  • Extend MediaListRune to support series.search API
  • Add series_index property to MediaViewRune
  • Create series-specific components in routes/series/[series_id]/
  • Update browse SearchResults to link series items to detail page

The implementation follows existing patterns and shares logic through
SvelteKit layouts, shared components, and rune-based state management.

full_thumbnails: undefined
}
// @ts-ignore - series_index is only present in SeriesSearchResponse
this.series_index = media_response.series_index

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Instead of adding metadata to the base rune, you should put series specific metadata on the MediaSeriesRune

/**
* Base params interface - common fields shared by all search types
*/
export interface BaseSearchParams {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Let's make BaseQueryParamsManager have no opinions on the default params that a page should use. Think about this class like the manager for query params state that will be used by any page. It should handle serialization, url syncing, mount loading, and anything else that is standard scaffolding

{/snippet}

{#snippet media_list({ controller })}
<MediaList {controller} />

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Instead of abstracting at the MediaList level, why not do it at the media tile level? We can introduce a new media tile component for series specific rendering (e.g. thumbnail + series index)


<MediaBrowserLayout {controller}>
{#snippet header({ controller })}
<Header {controller} bind:height={dimensions.heights.header} />

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Since the SearchParams are the only things that differ, let's try making that the snippet

andykais-claude pushed a commit that referenced this pull request Jan 10, 2026
Address feedback from PR #44 review comments:

1. Move series_index to specific rune classes
   - Remove series_index from base MediaViewRune
   - Add series_index to MediaFileRune (where it's actually used)
   - Add series_index to MediaSeriesRune (for nested series support)
   - Prevents pollution of base class with subclass-specific metadata

2. Make BaseQueryParamsManager neutral and opinion-free
   - Remove BaseSearchParams interface with opinionated fields
   - Change generic constraint from BaseSearchParams to Record<string, any>
   - Move field-specific parsing logic (search_string, stars, filepath) to subclasses
   - Move field-specific serialization logic to subclasses
   - Make merge() generic instead of assuming search_string exists
   - Remove extend() method from base (now in subclasses only)
   - Base class now only handles URL state synchronization

3. Abstract at media tile level instead of MediaList level
   - Create reusable MediaTile component with metadata snippet slot
   - Browse SearchResults uses metadata slot for grouped/series links
   - Series SearchResults uses metadata slot for series_index display
   - Eliminates code duplication in tile rendering logic
   - Makes differences between pages explicit via snippets

Benefits:
- Better separation of concerns (base vs specialized logic)
- More maintainable and extensible architecture
- Clearer component boundaries and responsibilities
- Easier to add new page types in the future
andykais pushed a commit that referenced this pull request Jan 16, 2026
Address feedback from PR #44 review comments:

1. Move series_index to specific rune classes
   - Remove series_index from base MediaViewRune
   - Add series_index to MediaFileRune (where it's actually used)
   - Add series_index to MediaSeriesRune (for nested series support)
   - Prevents pollution of base class with subclass-specific metadata

2. Make BaseQueryParamsManager neutral and opinion-free
   - Remove BaseSearchParams interface with opinionated fields
   - Change generic constraint from BaseSearchParams to Record<string, any>
   - Move field-specific parsing logic (search_string, stars, filepath) to subclasses
   - Move field-specific serialization logic to subclasses
   - Make merge() generic instead of assuming search_string exists
   - Remove extend() method from base (now in subclasses only)
   - Base class now only handles URL state synchronization

3. Abstract at media tile level instead of MediaList level
   - Create reusable MediaTile component with metadata snippet slot
   - Browse SearchResults uses metadata slot for grouped/series links
   - Series SearchResults uses metadata slot for series_index display
   - Eliminates code duplication in tile rendering logic
   - Makes differences between pages explicit via snippets

Benefits:
- Better separation of concerns (base vs specialized logic)
- More maintainable and extensible architecture
- Clearer component boundaries and responsibilities
- Easier to add new page types in the future
@andykais andykais force-pushed the claude/add-series-detail-page-JSzq0 branch from 87eb21f to cd741fe Compare January 16, 2026 17:26
andykais-claude pushed a commit that referenced this pull request Jan 16, 2026
Address feedback from PR #44 review comments:

1. Move series_index to specific rune classes
   - Remove series_index from base MediaViewRune
   - Add series_index to MediaFileRune (where it's actually used)
   - Add series_index to MediaSeriesRune (for nested series support)
   - Prevents pollution of base class with subclass-specific metadata

2. Make BaseQueryParamsManager neutral and opinion-free
   - Remove BaseSearchParams interface with opinionated fields
   - Change generic constraint from BaseSearchParams to Record<string, any>
   - Move field-specific parsing logic (search_string, stars, filepath) to subclasses
   - Move field-specific serialization logic to subclasses
   - Make merge() generic instead of assuming search_string exists
   - Remove extend() method from base (now in subclasses only)
   - Base class now only handles URL state synchronization

3. Abstract at media tile level instead of MediaList level
   - Create reusable MediaTile component with metadata snippet slot
   - Browse SearchResults uses metadata slot for grouped/series links
   - Series SearchResults uses metadata slot for series_index display
   - Eliminates code duplication in tile rendering logic
   - Makes differences between pages explicit via snippets

Benefits:
- Better separation of concerns (base vs specialized logic)
- More maintainable and extensible architecture
- Clearer component boundaries and responsibilities
- Easier to add new page types in the future
@andykais-claude andykais-claude force-pushed the claude/add-series-detail-page-JSzq0 branch from cd741fe to 927711a Compare January 16, 2026 21:21
andykais-claude pushed a commit that referenced this pull request Jan 22, 2026
Address feedback from PR #44 review comments:

1. Move series_index to specific rune classes
   - Remove series_index from base MediaViewRune
   - Add series_index to MediaFileRune (where it's actually used)
   - Add series_index to MediaSeriesRune (for nested series support)
   - Prevents pollution of base class with subclass-specific metadata

2. Make BaseQueryParamsManager neutral and opinion-free
   - Remove BaseSearchParams interface with opinionated fields
   - Change generic constraint from BaseSearchParams to Record<string, any>
   - Move field-specific parsing logic (search_string, stars, filepath) to subclasses
   - Move field-specific serialization logic to subclasses
   - Make merge() generic instead of assuming search_string exists
   - Remove extend() method from base (now in subclasses only)
   - Base class now only handles URL state synchronization

3. Abstract at media tile level instead of MediaList level
   - Create reusable MediaTile component with metadata snippet slot
   - Browse SearchResults uses metadata slot for grouped/series links
   - Series SearchResults uses metadata slot for series_index display
   - Eliminates code duplication in tile rendering logic
   - Makes differences between pages explicit via snippets

Benefits:
- Better separation of concerns (base vs specialized logic)
- More maintainable and extensible architecture
- Clearer component boundaries and responsibilities
- Easier to add new page types in the future
@andykais-claude andykais-claude force-pushed the claude/add-series-detail-page-JSzq0 branch from 4e31d41 to 2114ef9 Compare January 22, 2026 17:08
@andykais andykais force-pushed the claude/add-series-detail-page-JSzq0 branch from dadf78e to 1aa96f9 Compare February 28, 2026 00:32
claude and others added 11 commits February 27, 2026 19:33
Implement a new page for viewing media series items with similar UI to the
browse page but specialized for series navigation.

Features:
- New route at /series/[series_id] with full SvelteKit page structure
- SeriesController and SeriesQueryParamsManager for series-specific state
- Series-specific search filters and sort options (including series_index)
- Display series_index number under each media tile in series view
- Link from browse page media tiles to series detail page
- Reuse browse components where possible (MediaDetails, MediaView, Footer)
- Default sort by series_index in ascending order

Changes:
- Extend MediaListRune to support series.search API
- Add series_index property to MediaViewRune
- Create series-specific components in routes/series/[series_id]/
- Update browse SearchResults to link series items to detail page

The implementation follows existing patterns and shares logic through
SvelteKit layouts, shared components, and rune-based state management.
Refactor browse and series pages to share common logic through inheritance
and component composition, following SvelteKit patterns.

Changes:
- Create BaseQueryParamsManager abstract class with common URL handling
- Refactor BrowseQueryParamsManager to extend base class
- Refactor SeriesQueryParamsManager to extend base class
- Create MediaBrowserLayout component to share UI structure
- Update browse page to use MediaBrowserLayout with snippets
- Update series page to use MediaBrowserLayout with snippets

Benefits:
- Eliminates code duplication between browse and series queryparams
- Shared layout ensures consistent UI structure
- Easier to maintain and extend in the future
- Follows DRY principles and Svelte 5 snippet patterns

The base class handles:
- URL parsing and serialization
- State management (current/draft params)
- Browser history integration
- Common merge/extend operations

Each subclass implements:
- execute_search (specific API calls)
- contextual_query (specific query structure)
- Custom URL parsing/serialization hooks
Address feedback from PR #44 review comments:

1. Move series_index to specific rune classes
   - Remove series_index from base MediaViewRune
   - Add series_index to MediaFileRune (where it's actually used)
   - Add series_index to MediaSeriesRune (for nested series support)
   - Prevents pollution of base class with subclass-specific metadata

2. Make BaseQueryParamsManager neutral and opinion-free
   - Remove BaseSearchParams interface with opinionated fields
   - Change generic constraint from BaseSearchParams to Record<string, any>
   - Move field-specific parsing logic (search_string, stars, filepath) to subclasses
   - Move field-specific serialization logic to subclasses
   - Make merge() generic instead of assuming search_string exists
   - Remove extend() method from base (now in subclasses only)
   - Base class now only handles URL state synchronization

3. Abstract at media tile level instead of MediaList level
   - Create reusable MediaTile component with metadata snippet slot
   - Browse SearchResults uses metadata slot for grouped/series links
   - Series SearchResults uses metadata slot for series_index display
   - Eliminates code duplication in tile rendering logic
   - Makes differences between pages explicit via snippets

Benefits:
- Better separation of concerns (base vs specialized logic)
- More maintainable and extensible architecture
- Clearer component boundaries and responsibilities
- Easier to add new page types in the future
Fix build error where @deno/vite-plugin attempted to resolve Vite's
virtual modules (those starting with \x00) using child_process.spawn,
which doesn't allow null bytes in arguments.

The error was:
  [vite-plugin-sveltekit-compile] [vite-plugin-sveltekit-guard]
  The argument 'args[2]' must be a string without null bytes.
  Received '\x00vite/preload-helper.js'

Solution:
- Wrap the deno() plugin function with patchedDeno()
- Patch all resolveId hooks in the plugin(s) to return null for
  virtual modules (source.startsWith('\x00'))
- This allows Vite to handle virtual modules itself instead of
  passing them to the deno resolver

This fix is simple and reasonable - it's a targeted workaround for
a known limitation in @deno/vite-plugin@1.0.5 when working with
Vite 7's virtual module system.
Updated deno.lock after testing @deno/vite-plugin upgrade from 1.0.5 to 1.0.6.
Discovered esbuild import resolution issues that require further investigation.
Move shared components to lib/components/browse_media/:
- MediaBrowserLayout.svelte
- MediaDetails.svelte
- MediaView.svelte
- Footer.svelte
- MediaTile.svelte

Move shared runes to lib/runes/:
- dimensions.svelte.ts
- media_selections.svelte.ts

This prevents lib components from importing from routes, maintaining proper
dependency hierarchy where routes are leaves that import from lib.

Define MediaBrowserController interface in MediaBrowserLayout without importing
concrete controller types from routes.
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.

2 participants