diff --git a/next-ui/src/components.d.ts b/next-ui/src/components.d.ts index 20b40c9d..9ea5572b 100644 --- a/next-ui/src/components.d.ts +++ b/next-ui/src/components.d.ts @@ -47,6 +47,7 @@ declare module 'vue' { FilterByGenre: typeof import('./components/filter/by/Genre.vue')['default'] FilterByIncludeExclude: typeof import('./components/filter/by/IncludeExclude.vue')['default'] FilterByLanguage: typeof import('./components/filter/by/Language.vue')['default'] + FilterByLibrary: typeof import('./components/filter/by/Library.vue')['default'] FilterByOneShot: typeof import('./components/filter/by/OneShot.vue')['default'] FilterByPublisher: typeof import('./components/filter/by/Publisher.vue')['default'] FilterByReadStatus: typeof import('./components/filter/by/ReadStatus.vue')['default'] diff --git a/next-ui/src/components/book/card/BookCard.stories.ts b/next-ui/src/components/book/card/BookCard.stories.ts index d811719b..17e88410 100644 --- a/next-ui/src/components/book/card/BookCard.stories.ts +++ b/next-ui/src/components/book/card/BookCard.stories.ts @@ -27,6 +27,7 @@ const meta = { }, args: { book: mockBook, + showSeries: true, onSelection: fn(), }, } satisfies Meta diff --git a/next-ui/src/components/book/card/BookCard.vue b/next-ui/src/components/book/card/BookCard.vue index 5f5f133c..08898540 100644 --- a/next-ui/src/components/book/card/BookCard.vue +++ b/next-ui/src/components/book/card/BookCard.vue @@ -85,8 +85,11 @@ const titleAndLines = computed<{ title: ItemCardTitle; lines: ItemCardLine[] }>( text: intl.formatMessage( { description: 'Book card subtitle: count of pages', - defaultMessage: '{count} pages', - id: 'BSFC7R', + defaultMessage: `{count, plural, +one {# page} +other {# pages} +}`, + id: 'Ai7bBV', }, { count: book.media.pagesCount }, ), diff --git a/next-ui/src/components/filter/by/Library.stories.ts b/next-ui/src/components/filter/by/Library.stories.ts new file mode 100644 index 00000000..bfa26870 --- /dev/null +++ b/next-ui/src/components/filter/by/Library.stories.ts @@ -0,0 +1,43 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite' + +import Library from './Library.vue' +import { fn } from 'storybook/test' + +const meta = { + component: Library, + render: (args: object) => ({ + components: { Library }, + setup() { + return { args } + }, + template: '', + }), + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + docs: { + description: { + component: 'Library filter.', + }, + }, + }, + args: { + 'onUpdate:modelValue': fn(), + modelValue: [], + }, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: {}, +} + +export const InitialValue: Story = { + args: { + modelValue: [ + { i: 'e', v: '1' }, + { i: 'i', v: '2' }, + ], + }, +} diff --git a/next-ui/src/components/filter/by/Library.vue b/next-ui/src/components/filter/by/Library.vue new file mode 100644 index 00000000..5ed9cc0d --- /dev/null +++ b/next-ui/src/components/filter/by/Library.vue @@ -0,0 +1,39 @@ + + + + + + + diff --git a/next-ui/src/components/selection/Bar.vue b/next-ui/src/components/selection/Bar.vue index 2eb01b86..dbc5073b 100644 --- a/next-ui/src/components/selection/Bar.vue +++ b/next-ui/src/components/selection/Bar.vue @@ -15,8 +15,11 @@ $formatMessage( { description: 'Selection bar: count of items', - defaultMessage: '{count} selected', - id: 'lqyIjk', + defaultMessage: `{count, plural, +one {# selected} +other {# selected} +}`, + id: 'tCm6kO', }, { count: selectionStore.count, diff --git a/next-ui/src/composables/filters.ts b/next-ui/src/composables/filter.ts similarity index 100% rename from next-ui/src/composables/filters.ts rename to next-ui/src/composables/filter.ts diff --git a/next-ui/src/composables/search.ts b/next-ui/src/composables/search.ts deleted file mode 100644 index f849b211..00000000 --- a/next-ui/src/composables/search.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { components } from '@/generated/openapi/komga' - -export function useSearchConditionLibraries( - libraries: MaybeRefOrGetter, -) { - const condition = computed(() => { - return { - anyOf: - toValue(libraries)?.map((it) => ({ - libraryId: { - operator: 'Is', - value: it.id, - }, - })) ?? [], - } - }) - - return { - librariesCondition: condition, - } -} diff --git a/next-ui/src/functions/filter.ts b/next-ui/src/functions/filter.ts index e4316f75..6f1a5a86 100644 --- a/next-ui/src/functions/filter.ts +++ b/next-ui/src/functions/filter.ts @@ -22,6 +22,20 @@ export function clearFilter(filter: FilterType | FilterTypeSelectRange | FilterI if ('i' in filter) filter.i = undefined } +export function valuesToConditions(value: string[] | undefined, key: string) { + if (!value || value.length === 0) return null + const list = value.map((it) => ({ + [key]: { + operator: 'is', + value: it, + }, + })) + + return { + anyOf: list, + } +} + export function schemaFilterSeriesStatusToConditions( filter: InferOutput, ) { diff --git a/next-ui/src/pages/collection/[id].vue b/next-ui/src/pages/collection/[id].vue index 4be85c57..1861accd 100644 --- a/next-ui/src/pages/collection/[id].vue +++ b/next-ui/src/pages/collection/[id].vue @@ -1,11 +1,424 @@ - + + + meta: requiresRole: USER + scrollable: true diff --git a/next-ui/src/pages/libraries/[id]/books.vue b/next-ui/src/pages/libraries/[id]/books.vue index c9e79c73..f1a04cd1 100644 --- a/next-ui/src/pages/libraries/[id]/books.vue +++ b/next-ui/src/pages/libraries/[id]/books.vue @@ -56,6 +56,7 @@ @@ -140,7 +141,6 @@ import FilterButton from '@/components/filter/FilterButton.vue' import { useDisplay } from 'vuetify' import { usePresentationMode } from '@/composables/presentationMode' import { useGetLibrariesById } from '@/composables/libraries' -import { useSearchConditionLibraries } from '@/composables/search' import { useAppStore } from '@/stores/app' import { storeToRefs } from 'pinia' import { usePagination } from '@/composables/pagination' @@ -156,19 +156,19 @@ import { schemaFilterIncludeExcludeToConditions, schemaFilterReadStatusToConditions, schemaFilterStringToConditions, + valuesToConditions, } from '@/functions/filter' import { useInfiniteQuery, useQuery } from '@pinia/colada' import { PageRequest, sortToString } from '@/types/PageRequest' import { komgaClient } from '@/api/komga-client' import { bookListQuery } from '@/colada/books' import { commonMessages } from '@/utils/i18n/common-messages' -import { useFilterAuthors } from '@/composables/filters' +import { useFilterAuthors } from '@/composables/filter' import ChipCount from '@/components/ChipCount.vue' const route = useRoute('/libraries/[id]/books') const libraryId = route.params.id -const { libraries } = useGetLibrariesById(libraryId) -const { librariesCondition } = useSearchConditionLibraries(libraries) +const { libraryIds } = useGetLibrariesById(libraryId) const display = useDisplay() const appStore = useAppStore() @@ -215,7 +215,7 @@ const sortOptions = sortBooks.map((it) => convertSortOptionDescriptor(it)) const conds = computed(() => ({ allOf: [ - librariesCondition.value, + valuesToConditions(libraryIds.value, 'libraryId'), schemaFilterIncludeExcludeToConditions(filterUnavailable.value, 'deleted'), schemaFilterIncludeExcludeToConditions(filterOneShot.value, 'oneShot'), schemaFilterReadStatusToConditions(filterReadStatus.value), @@ -288,6 +288,12 @@ const filterDrawer = ref(false) const filterExpansionPanels = ref() + + meta: requiresRole: USER diff --git a/next-ui/src/pages/libraries/[id]/series.vue b/next-ui/src/pages/libraries/[id]/series.vue index 6e431c49..4c6ceb8b 100644 --- a/next-ui/src/pages/libraries/[id]/series.vue +++ b/next-ui/src/pages/libraries/[id]/series.vue @@ -57,6 +57,7 @@ @@ -220,7 +221,6 @@ import { PageRequest, sortToString } from '@/types/PageRequest' import { useGetLibrariesById } from '@/composables/libraries' import { useAppStore } from '@/stores/app' import { usePagination } from '@/composables/pagination' -import { useSearchConditionLibraries } from '@/composables/search' import { useSelectionStore } from '@/stores/selection' import { useDisplay } from 'vuetify' import { @@ -232,6 +232,7 @@ import { schemaFilterReadStatusToConditions, schemaFilterIncludeExcludeToConditions, clearFilter, + valuesToConditions, } from '@/functions/filter' import { SchemaFilterReadStatus, @@ -250,13 +251,12 @@ import PosterSizeSlider from '@/components/PosterSizeSlider.vue' import FilterButton from '@/components/filter/FilterButton.vue' import { usePresentationMode } from '@/composables/presentationMode' import { storeToRefs } from 'pinia' -import { useFilterAuthors } from '@/composables/filters' +import { useFilterAuthors } from '@/composables/filter' import ChipCount from '@/components/ChipCount.vue' const route = useRoute('/libraries/[id]/series') const libraryId = route.params.id -const { libraries } = useGetLibrariesById(libraryId) -const { librariesCondition } = useSearchConditionLibraries(libraries) +const { libraryIds } = useGetLibrariesById(libraryId) const display = useDisplay() const appStore = useAppStore() @@ -326,7 +326,7 @@ const sortOptions = sortSeries.map((it) => convertSortOptionDescriptor(it)) const conds = computed(() => ({ allOf: [ - librariesCondition.value, + valuesToConditions(libraryIds.value, 'libraryId'), schemaFilterIncludeExcludeToConditions(filterComplete.value, 'complete'), schemaFilterIncludeExcludeToConditions(filterUnavailable.value, 'deleted'), schemaFilterIncludeExcludeToConditions(filterOneShot.value, 'oneShot'), @@ -407,7 +407,11 @@ const filterDrawer = ref(false) const filterExpansionPanels = ref() - + meta: diff --git a/next-ui/src/pages/readlist/[id].vue b/next-ui/src/pages/readlist/[id].vue index 090508c4..3201bedc 100644 --- a/next-ui/src/pages/readlist/[id].vue +++ b/next-ui/src/pages/readlist/[id].vue @@ -8,4 +8,5 @@ const readListId = computed(() => route.params.id) meta: requiresRole: USER + scrollable: true diff --git a/next-ui/src/pages/series/[id].vue b/next-ui/src/pages/series/[id].vue index 6fa3f01e..2640fb67 100644 --- a/next-ui/src/pages/series/[id].vue +++ b/next-ui/src/pages/series/[id].vue @@ -8,4 +8,5 @@ const seriesId = computed(() => route.params.id) meta: requiresRole: USER + scrollable: true diff --git a/next-ui/src/utils/i18n/common-messages.ts b/next-ui/src/utils/i18n/common-messages.ts index 06e44353..2633a570 100644 --- a/next-ui/src/utils/i18n/common-messages.ts +++ b/next-ui/src/utils/i18n/common-messages.ts @@ -77,6 +77,11 @@ export const commonMessages = { defaultMessage: 'Status', id: 'Pp3+1S', }), + filterPanelLibrary: defineMessage({ + description: 'Filter panel: Library', + defaultMessage: 'Library', + id: 'phzvRy', + }), filterPanelGenre: defineMessage({ description: 'Filter panel: Genre', defaultMessage: 'Genre',