series page scaffolding

This commit is contained in:
Gauthier Roebroeck 2026-01-14 16:42:41 +08:00
parent deb49b2242
commit 0b9aa753c5
2 changed files with 125 additions and 4 deletions

View file

@ -1,10 +1,106 @@
<template>
SERIES
<EmptyStateConstruction />
<v-app-bar>
<v-spacer />
<PageSizeSelector
v-model="appStore.browsingPageSize"
allow-unpaged
:sizes="[1, 10, 20]"
/>
<PresentationSelector
v-model="presentationMode"
:modes="['grid', 'list']"
/>
</v-app-bar>
<template v-if="series">
<v-data-iterator
v-model="selectedItems"
return-object
:items="series.content"
:items-per-page="itemsPerPage"
:page="page1"
show-select
>
<template #default="{ items, toggleSelect, isSelected }">
<v-container
v-if="presentationMode === 'grid'"
fluid
>
<v-row>
<v-col
v-for="item in items"
:key="item.raw.id"
cols="2"
>
<ItemCardSeries
:series="item.raw"
:selected="isSelected(item)"
:pre-select="preSelect"
@selection="toggleSelect(item)"
/>
</v-col>
</v-row>
</v-container>
<v-list v-if="presentationMode === 'list'">
<v-list-item
v-for="item in items"
:key="item.raw.id"
:title="item.raw.metadata.title"
:base-color="isSelected(item) ? 'red' : 'blue'"
@click="toggleSelect(item)"
/>
</v-list>
</template>
</v-data-iterator>
<v-pagination
v-model="page1"
:length="pageCount"
></v-pagination>
</template>
</template>
<script lang="ts" setup>
//
import { useQuery } from '@pinia/colada'
import { seriesListQuery } from '@/colada/series'
import type { components } from '@/generated/openapi/komga'
import { PageRequest } from '@/types/PageRequest'
import { useGetLibrariesById } from '@/composables/libraries'
import { useAppStore } from '@/stores/app'
import { useItemsPerPage, usePagination } from '@/composables/pagination'
import { useSearchConditionLibraries } from '@/composables/search'
const route = useRoute('/libraries/[id]/series')
const libraryId = route.params.id
const { libraries } = useGetLibrariesById(libraryId)
const { librariesCondition } = useSearchConditionLibraries(libraries)
const appStore = useAppStore()
const presentationMode = appStore.getPresentationMode(`${libraryId}_series`, 'grid')
const { itemsPerPage } = useItemsPerPage(appStore.browsingPageSize)
const { page0, page1, pageCount } = usePagination()
const selectedItems = ref<components['schemas']['SeriesDto'][]>([])
const preSelect = computed(() => selectedItems.value.length > 0)
const { data: series } = useQuery(seriesListQuery, () => {
const search: components['schemas']['SeriesSearch'] = {
condition: librariesCondition.value as components['schemas']['AnyOfSeries'],
}
return {
search: search,
pageRequest: PageRequest.FromPageSize(appStore.browsingPageSize, page0.value),
}
})
watch(series, (newSeries) => {
if (newSeries) pageCount.value = newSeries.totalPages ?? 0
})
</script>
<route lang="yaml">

View file

@ -1,6 +1,8 @@
// Utilities
import { defineStore } from 'pinia'
import { useDisplay } from 'vuetify'
import type { PresentationMode } from '@/types/libraries'
import type { PageSize } from '@/types/page'
export const useAppStore = defineStore('app', {
state: () => ({
@ -9,12 +11,35 @@ export const useAppStore = defineStore('app', {
theme: 'system',
rememberMe: false,
importBooksPath: '',
browsingPageSize: 20 as PageSize,
/**
* Store the presentation mode per view.
* Use the getter to ensure a default value is always set.
*/
presentationMode: {} as Record<string, PresentationMode>,
// transient
reorderLibraries: false,
}),
getters: {
getPresentationMode: (state) => (key: string, defaultValue: PresentationMode) => {
return computed({
get: () => state.presentationMode[key] ?? (state.presentationMode[key] = defaultValue),
set: (value) => {
state.presentationMode[key] = value
},
})
},
},
persist: {
key: 'komga.nextui.app',
// explicitly state which keys are stored
pick: ['drawer', 'theme', 'rememberMe', 'importBooksPath'],
pick: [
'drawer',
'theme',
'rememberMe',
'importBooksPath',
'browsingPageSize',
'presentationMode',
],
},
})