feat(series): Add-to-series control + Series browse view + nav (FC-6.2)
CI / lint (push) Successful in 3s
CI / backend-lint-and-test (push) Successful in 25s
CI / frontend-build (push) Successful in 25s
CI / integration (push) Successful in 3m4s

Completes FC-6.2 with the UI.

- PostSeriesMenu: a "Series ▾" control on each post card — "New series from
  this post" (promote → navigates to manage) and "Add to existing series…"
  (dialog with a browsable picker loaded from GET /api/series, client-side
  filtered — avoids the empty-autocomplete #712 trap).
- SeriesView (/series): a top-level Series browse grid — cover, name, artist,
  chapter/page counts, gap badge; sort recent|name|size; cards → manage/read.
  meta.title adds it to the nav automatically (peer of Posts).
- seriesBrowse store for the list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 18:38:37 -04:00
parent db490e92df
commit 9e262cc5f0
5 changed files with 305 additions and 1 deletions
+31
View File
@@ -0,0 +1,31 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { useApi } from '../composables/useApi.js'
import { useAsyncAction } from '../composables/useAsyncAction.js'
// Backs the Series browse view (FC-6.2). list_series returns every series as a
// card; homelab scale is small enough to load the whole list and sort/filter
// server-side.
export const useSeriesBrowseStore = defineStore('seriesBrowse', () => {
const api = useApi()
const series = ref([])
const sort = ref('recent')
const artistId = ref(null)
const { loading, error, run } = useAsyncAction({ errorAs: 'message' })
async function load() {
await run(async () => {
const params = { sort: sort.value }
if (artistId.value != null) params.artist_id = artistId.value
const body = await api.get('/api/series', { params })
series.value = body.series || []
})
}
function setSort(s) {
sort.value = s
return load()
}
return { series, sort, artistId, loading, error, load, setSort }
})