fix(webui): lazy load collections on browse series

also adjusted layout for smaller screens
This commit is contained in:
Gauthier Roebroeck 2020-06-29 11:37:26 +08:00
parent 938c9239d6
commit d89533ded6
5 changed files with 142 additions and 94 deletions

View file

@ -0,0 +1,71 @@
<template>
<v-expansion-panels v-model="collectionPanel">
<v-expansion-panel v-for="(c, index) in collections"
:key="index"
>
<v-expansion-panel-header>{{ c.name }} collection</v-expansion-panel-header>
<v-expansion-panel-content>
<horizontal-scroller>
<template v-slot:prepend>
<router-link class="overline"
:to="{name: 'browse-collection', params: {collectionId: c.id}}"
>Manage collection
</router-link>
</template>
<template v-slot:content>
<item-browser :items="collectionsContent[index]"
nowrap
:selectable="false"
:action-menu="false"
:fixed-item-width="100"
/>
</template>
</horizontal-scroller>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</template>
<script lang="ts">
import HorizontalScroller from '@/components/HorizontalScroller.vue'
import ItemBrowser from '@/components/ItemBrowser.vue'
import Vue from 'vue'
export default Vue.extend({
name: 'CollectionsExpansionPanels',
components: {
HorizontalScroller,
ItemBrowser,
},
props: {
collections: {
type: Array as () => CollectionDto[],
required: true,
},
},
data: () => {
return {
collectionPanel: undefined as number | undefined,
collectionsContent: [[]] as any[],
}
},
watch: {
collections: {
handler (val) {
this.collectionPanel = undefined
this.collectionsContent = [...Array(val.length)].map(elem => new Array(0))
},
immediate: true,
},
async collectionPanel (val) {
if (val !== undefined) {
const collId = this.collections[val].id
if (this.$_.isEmpty(this.collectionsContent[val])) {
const content = (await this.$komgaCollections.getSeries(collId, { unpaged: true } as PageRequest)).content
this.collectionsContent.splice(val, 1, content)
}
}
},
},
})
</script>

View file

@ -14,24 +14,25 @@
:class="flexClass"
>
<v-item
v-for="item in localItems"
:key="item.id"
class="my-3 mx-2"
v-slot:default="{ toggle, active }" :value="item"
v-for="item in localItems"
:key="item.id"
class="my-2 mx-2"
v-slot:default="{ toggle, active }" :value="item"
>
<slot name="item">
<div style="position: relative"
:class="draggable ? 'draggable-item' : undefined"
>
<item-card
class="item-card"
:item="item"
:width="itemWidth"
:selected="active"
:no-link="draggable || deletable"
:preselect="shouldPreselect"
:onEdit="(draggable || deletable) ? undefined : editFunction"
:onSelected="(draggable || deletable) ? undefined : selectable ? toggle: undefined"
class="item-card"
:item="item"
:width="itemWidth"
:selected="active"
:no-link="draggable || deletable"
:preselect="shouldPreselect"
:onEdit="(draggable || deletable) ? undefined : editFunction"
:onSelected="(draggable || deletable) ? undefined : selectable ? toggle: undefined"
:action-menu="actionMenu"
></item-card>
<v-slide-y-reverse-transition>
@ -84,6 +85,10 @@ export default Vue.extend({
type: Array,
required: true,
},
fixedItemWidth: {
type: Number,
required: false,
},
selectable: {
type: Boolean,
default: true,
@ -110,6 +115,10 @@ export default Vue.extend({
type: Boolean,
default: false,
},
actionMenu: {
type: Boolean,
default: true,
},
},
data: () => {
return {
@ -152,7 +161,7 @@ export default Vue.extend({
return this.items.length > 0
},
itemWidth (): number {
return this.width
return this.fixedItemWidth ? this.fixedItemWidth : this.width
},
shouldPreselect (): boolean {
return this.selectedItems.length > 0

View file

@ -74,65 +74,21 @@
</v-col>
</v-row>
<v-row>
<v-row v-if="$vuetify.breakpoint.name !== 'xs'">
<v-col>
<v-expansion-panels v-model="collectionPanel" v-if="$vuetify.breakpoint.name !== 'xs'">
<v-expansion-panel v-for="(c, i) in collections"
:key="i"
>
<v-expansion-panel-header>{{ c.name }} collection</v-expansion-panel-header>
<v-expansion-panel-content>
<horizontal-scroller>
<template v-slot:prepend>
<router-link class="overline"
:to="{name: 'browse-collection', params: {collectionId: c.id}}"
>Manage collection
</router-link>
</template>
<template v-slot:content>
<div v-for="(s, i) in collectionsContent[c.id]"
:key="i"
>
<item-card class="ma-2 card" :item="s"/>
</div>
</template>
</horizontal-scroller>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
<collections-expansion-panels :collections="collections"/>
</v-col>
</v-row>
</v-col>
</v-row>
<v-row v-if="$vuetify.breakpoint.name === 'xs'">
<v-expansion-panels v-model="collectionPanel">
<v-expansion-panel v-for="(c, i) in collections"
:key="i"
>
<v-expansion-panel-header>{{ c.name }} collection</v-expansion-panel-header>
<v-expansion-panel-content>
<horizontal-scroller>
<template v-slot:prepend>
<router-link class="overline"
:to="{name: 'browse-collection', params: {collectionId: c.id}}"
>Manage collection
</router-link>
</template>
<template v-slot:content>
<div v-for="(s, i) in collectionsContent[c.id]"
:key="i"
>
<item-card class="ma-2 card" :item="s"/>
</div>
</template>
</horizontal-scroller>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
<v-col class="pt-0 py-1">
<collections-expansion-panels :collections="collections"/>
</v-col>
</v-row>
<v-divider class="my-4"/>
<v-divider class="my-1"/>
<empty-state
v-if="totalPages === 0"
@ -164,21 +120,21 @@
<script lang="ts">
import Badge from '@/components/Badge.vue'
import BooksMultiSelectBar from '@/components/bars/BooksMultiSelectBar.vue'
import ToolbarSticky from '@/components/bars/ToolbarSticky.vue'
import CollectionsExpansionPanels from '@/components/CollectionsExpansionPanels.vue'
import EmptyState from '@/components/EmptyState.vue'
import FilterMenuButton from '@/components/FilterMenuButton.vue'
import HorizontalScroller from '@/components/HorizontalScroller.vue'
import ItemBrowser from '@/components/ItemBrowser.vue'
import ItemCard from '@/components/ItemCard.vue'
import PageSizeSelect from '@/components/PageSizeSelect.vue'
import SeriesActionsMenu from '@/components/menus/SeriesActionsMenu.vue'
import PageSizeSelect from '@/components/PageSizeSelect.vue'
import SortMenuButton from '@/components/SortMenuButton.vue'
import ToolbarSticky from '@/components/bars/ToolbarSticky.vue'
import { parseQueryFilter, parseQuerySort } from '@/functions/query-params'
import { seriesThumbnailUrl } from '@/functions/urls'
import { ReadStatus } from '@/types/enum-books'
import { BOOK_CHANGED, LIBRARY_DELETED, SERIES_CHANGED } from '@/types/events'
import Vue from 'vue'
import BooksMultiSelectBar from '@/components/bars/BooksMultiSelectBar.vue'
const cookiePageSize = 'pagesize'
@ -192,10 +148,10 @@ export default Vue.extend({
ItemBrowser,
PageSizeSelect,
SeriesActionsMenu,
HorizontalScroller,
ItemCard,
EmptyState,
BooksMultiSelectBar,
CollectionsExpansionPanels,
},
data: () => {
return {
@ -219,8 +175,6 @@ export default Vue.extend({
pageUnwatch: null as any,
pageSizeUnwatch: null as any,
collections: [] as CollectionDto[],
collectionsContent: [] as any[][],
collectionPanel: -1,
}
},
computed: {
@ -294,7 +248,6 @@ export default Vue.extend({
this.totalElements = null
this.books = []
this.collections = []
this.collectionPanel = -1
this.loadSeries(Number(to.params.seriesId))
@ -348,9 +301,6 @@ export default Vue.extend({
async loadSeries (seriesId: number) {
this.series = await this.$komgaSeries.getOneSeries(seriesId)
this.collections = await this.$komgaSeries.getCollections(seriesId)
for (const c of this.collections) {
this.collectionsContent[c.id] = (await this.$komgaCollections.getSeries(c.id, { unpaged: true } as PageRequest)).content
}
await this.loadPage(seriesId, this.page, this.sortActive)
},
parseQuerySortOrDefault (querySort: any): SortActive {

View file

@ -17,7 +17,7 @@
@edit="editMultipleBooks"
/>
<v-container fluid class="px-6">
<v-container fluid>
<empty-state v-if="allEmpty"
title="Nothing to show"
icon="mdi-help-circle"
@ -25,7 +25,7 @@
>
</empty-state>
<horizontal-scroller v-if="inProgressBooks.length !== 0" class="my-4">
<horizontal-scroller v-if="inProgressBooks.length !== 0" class="mb-4">
<template v-slot:prepend>
<div class="title">Keep Reading</div>
</template>
@ -35,11 +35,12 @@
:edit-function="singleEditBook"
:selected.sync="selectedBooks"
:selectable="selectedSeries.length === 0"
:fixed-item-width="fixedCardWidth"
/>
</template>
</horizontal-scroller>
<horizontal-scroller v-if="onDeckBooks.length !== 0" class="my-4">
<horizontal-scroller v-if="onDeckBooks.length !== 0" class="mb-4">
<template v-slot:prepend>
<div class="title">On Deck</div>
</template>
@ -49,11 +50,12 @@
:edit-function="singleEditBook"
:selected.sync="selectedBooks"
:selectable="selectedSeries.length === 0"
:fixed-item-width="fixedCardWidth"
/>
</template>
</horizontal-scroller>
<horizontal-scroller v-if="newSeries.length !== 0" class="my-4">
<horizontal-scroller v-if="newSeries.length !== 0" class="mb-4">
<template v-slot:prepend>
<div class="title">Recently Added Series</div>
</template>
@ -63,11 +65,12 @@
:edit-function="singleEditSeries"
:selected.sync="selectedSeries"
:selectable="selectedBooks.length === 0"
:fixed-item-width="fixedCardWidth"
/>
</template>
</horizontal-scroller>
<horizontal-scroller v-if="updatedSeries.length !== 0" class="my-4">
<horizontal-scroller v-if="updatedSeries.length !== 0" class="mb-4">
<template v-slot:prepend>
<div class="title">Recently Updated Series</div>
</template>
@ -77,11 +80,12 @@
:edit-function="singleEditSeries"
:selected.sync="selectedSeries"
:selectable="selectedBooks.length === 0"
:fixed-item-width="fixedCardWidth"
/>
</template>
</horizontal-scroller>
<horizontal-scroller v-if="latestBooks.length !== 0" class="my-4">
<horizontal-scroller v-if="latestBooks.length !== 0" class="mb-4">
<template v-slot:prepend>
<div class="title">Recently Added Books</div>
</template>
@ -91,6 +95,7 @@
:edit-function="singleEditBook"
:selected.sync="selectedBooks"
:selectable="selectedSeries.length === 0"
:fixed-item-width="fixedCardWidth"
/>
</template>
</horizontal-scroller>
@ -99,14 +104,14 @@
</template>
<script lang="ts">
import BooksMultiSelectBar from '@/components/bars/BooksMultiSelectBar.vue'
import SeriesMultiSelectBar from '@/components/bars/SeriesMultiSelectBar.vue'
import EmptyState from '@/components/EmptyState.vue'
import HorizontalScroller from '@/components/HorizontalScroller.vue'
import ItemBrowser from '@/components/ItemBrowser.vue'
import { ReadStatus } from '@/types/enum-books'
import { BOOK_CHANGED, LIBRARY_DELETED, SERIES_CHANGED } from '@/types/events'
import Vue from 'vue'
import ItemBrowser from '@/components/ItemBrowser.vue'
import SeriesMultiSelectBar from '@/components/bars/SeriesMultiSelectBar.vue'
import BooksMultiSelectBar from '@/components/bars/BooksMultiSelectBar.vue'
export default Vue.extend({
name: 'Dashboard',
@ -150,6 +155,9 @@ export default Vue.extend({
},
},
computed: {
fixedCardWidth (): number {
return this.$vuetify.breakpoint.name === 'xs' ? 120 : 150
},
allEmpty (): boolean {
return this.newSeries.length === 0 &&
this.updatedSeries.length === 0 &&

View file

@ -23,7 +23,7 @@
@edit="editMultipleBooks"
/>
<v-container fluid class="px-6">
<v-container fluid>
<empty-state
v-if="emptyResults"
title="The search returned no results"
@ -35,7 +35,7 @@
</empty-state>
<template v-else>
<horizontal-scroller v-if="series.length !== 0" class="my-4">
<horizontal-scroller v-if="series.length !== 0" class="mb-4">
<template v-slot:prepend>
<div class="title">Series</div>
</template>
@ -45,11 +45,12 @@
:edit-function="singleEditSeries"
:selected.sync="selectedSeries"
:selectable="selectedBooks.length === 0"
:fixed-item-width="fixedCardWidth"
/>
</template>
</horizontal-scroller>
<horizontal-scroller v-if="books.length !== 0" class="my-4">
<horizontal-scroller v-if="books.length !== 0" class="mb-4">
<template v-slot:prepend>
<div class="title">Books</div>
</template>
@ -59,16 +60,22 @@
:edit-function="singleEditBook"
:selected.sync="selectedBooks"
:selectable="selectedSeries.length === 0"
:fixed-item-width="fixedCardWidth"
/>
</template>
</horizontal-scroller>
<horizontal-scroller v-if="collections.length !== 0" class="my-4">
<horizontal-scroller v-if="collections.length !== 0" class="mb-4">
<template v-slot:prepend>
<div class="title">Collections</div>
</template>
<template v-slot:content>
<item-browser :items="collections" nowrap :edit-function="singleEditCollection" :selectable="false"/>
<item-browser :items="collections"
nowrap
:edit-function="singleEditCollection"
:selectable="false"
:fixed-item-width="fixedCardWidth"
/>
</template>
</horizontal-scroller>
@ -79,14 +86,14 @@
</template>
<script lang="ts">
import EmptyState from '@/components/EmptyState.vue'
import HorizontalScroller from '@/components/HorizontalScroller.vue'
import ToolbarSticky from '@/components/bars/ToolbarSticky.vue'
import { BOOK_CHANGED, COLLECTION_CHANGED, LIBRARY_DELETED, SERIES_CHANGED } from '@/types/events'
import Vue from 'vue'
import ItemBrowser from '@/components/ItemBrowser.vue'
import BooksMultiSelectBar from '@/components/bars/BooksMultiSelectBar.vue'
import SeriesMultiSelectBar from '@/components/bars/SeriesMultiSelectBar.vue'
import ToolbarSticky from '@/components/bars/ToolbarSticky.vue'
import EmptyState from '@/components/EmptyState.vue'
import HorizontalScroller from '@/components/HorizontalScroller.vue'
import ItemBrowser from '@/components/ItemBrowser.vue'
import { BOOK_CHANGED, COLLECTION_CHANGED, LIBRARY_DELETED, SERIES_CHANGED } from '@/types/events'
import Vue from 'vue'
export default Vue.extend({
name: 'Search',
@ -147,6 +154,9 @@ export default Vue.extend({
},
},
computed: {
fixedCardWidth (): number {
return this.$vuetify.breakpoint.name === 'xs' ? 120 : 150
},
showToolbar (): boolean {
return this.selectedSeries.length === 0 && this.selectedBooks.length === 0
},