diff --git a/client/components/app/BookShelfCategorized.vue b/client/components/app/BookShelfCategorized.vue index fe1d5df5..ca070e18 100644 --- a/client/components/app/BookShelfCategorized.vue +++ b/client/components/app/BookShelfCategorized.vue @@ -28,6 +28,9 @@

{{ $strings[shelf.labelStringKey] }}

+ +

{{ $strings[shelf.labelStringKey] }}

+
@@ -185,8 +188,8 @@ export default { this.shelves = categories }, async setShelvesFromSearch() { - var shelves = [] - if (this.results.books && this.results.books.length) { + const shelves = [] + if (this.results.books?.length) { shelves.push({ id: 'books', label: 'Books', @@ -196,7 +199,7 @@ export default { }) } - if (this.results.podcasts && this.results.podcasts.length) { + if (this.results.podcasts?.length) { shelves.push({ id: 'podcasts', label: 'Podcasts', @@ -206,7 +209,7 @@ export default { }) } - if (this.results.series && this.results.series.length) { + if (this.results.series?.length) { shelves.push({ id: 'series', label: 'Series', @@ -221,7 +224,7 @@ export default { }) }) } - if (this.results.tags && this.results.tags.length) { + if (this.results.tags?.length) { shelves.push({ id: 'tags', label: 'Tags', @@ -236,7 +239,7 @@ export default { }) }) } - if (this.results.authors && this.results.authors.length) { + if (this.results.authors?.length) { shelves.push({ id: 'authors', label: 'Authors', @@ -250,6 +253,20 @@ export default { }) }) } + if (this.results.narrators?.length) { + shelves.push({ + id: 'narrators', + label: 'Narrators', + labelStringKey: 'LabelNarrators', + type: 'narrators', + entities: this.results.narrators.map((n) => { + return { + ...n, + type: 'narrator' + } + }) + }) + } this.shelves = shelves }, scan() { diff --git a/client/components/app/BookShelfRow.vue b/client/components/app/BookShelfRow.vue index bd97d56a..60632db7 100644 --- a/client/components/app/BookShelfRow.vue +++ b/client/components/app/BookShelfRow.vue @@ -41,6 +41,11 @@ +
+ +
@@ -88,6 +93,7 @@ export default { return this.bookCoverWidth * this.bookCoverAspectRatio }, shelfHeight() { + if (this.shelf.type === 'narrators') return 148 return this.bookCoverHeight + 48 }, paddingLeft() { diff --git a/client/components/cards/ItemSearchCard.vue b/client/components/cards/ItemSearchCard.vue index f29888e5..1784db0f 100644 --- a/client/components/cards/ItemSearchCard.vue +++ b/client/components/cards/ItemSearchCard.vue @@ -10,7 +10,7 @@

by {{ authorName }}

-

+
@@ -67,12 +67,13 @@ export default { // but with removing commas periods etc this is no longer plausible const html = this.matchText - if (this.matchKey === 'episode') return `

Episode: ${html}

` - if (this.matchKey === 'tags') return `

Tags: ${html}

` + if (this.matchKey === 'episode') return `

${this.$strings.LabelEpisode}: ${html}

` + if (this.matchKey === 'tags') return `

${this.$strings.LabelTags}: ${html}

` if (this.matchKey === 'authors') return `by ${html}` if (this.matchKey === 'isbn') return `

ISBN: ${html}

` if (this.matchKey === 'asin') return `

ASIN: ${html}

` - if (this.matchKey === 'series') return `

Series: ${html}

` + if (this.matchKey === 'series') return `

${this.$strings.LabelSeries}: ${html}

` + if (this.matchKey === 'narrators') return `

${this.$strings.LabelNarrator}: ${html}

` return `${html}` } }, diff --git a/client/components/cards/LazySeriesCard.vue b/client/components/cards/LazySeriesCard.vue index 313530b6..1175acf1 100644 --- a/client/components/cards/LazySeriesCard.vue +++ b/client/components/cards/LazySeriesCard.vue @@ -7,7 +7,7 @@
{{ books.length }}
-
+

{{ displayTitle }}

@@ -85,13 +85,13 @@ export default { case 'addedAt': return `${this.$strings.LabelAdded} ${this.$formatDate(this.addedAt, this.dateFormat)}` case 'totalDuration': - return `${this.$strings.LabelDuration} ${this.$elapsedPrettyExtended(this.totalDuration, false)}` + return `${this.$strings.LabelDuration} ${this.$elapsedPrettyExtended(this.totalDuration, false)}` case 'lastBookUpdated': - const lastUpdated = Math.max(...(this.books).map(x => x.updatedAt), 0) + const lastUpdated = Math.max(...this.books.map((x) => x.updatedAt), 0) return `${this.$strings.LabelLastBookUpdated} ${this.$formatDate(lastUpdated, this.dateFormat)}` case 'lastBookAdded': - const lastBookAdded = Math.max(...(this.books).map(x => x.addedAt), 0) - return `${this.$strings.LabelLastBookAdded} ${this.$formatDate(lastBookAdded, this.dateFormat)}` + const lastBookAdded = Math.max(...this.books.map((x) => x.addedAt), 0) + return `${this.$strings.LabelLastBookAdded} ${this.$formatDate(lastBookAdded, this.dateFormat)}` default: return null } @@ -115,6 +115,14 @@ export default { seriesBooksFinished() { return this.seriesBookProgress.filter((p) => p.isFinished) }, + hasSeriesBookInProgress() { + return this.seriesBookProgress.some((p) => !p.isFinished && p.progress > 0) + }, + seriesPercentInProgress() { + let totalFinishedAndInProgress = this.seriesBooksFinished.length + if (this.hasSeriesBookInProgress) totalFinishedAndInProgress += 1 + return Math.min(1, Math.max(0, totalFinishedAndInProgress / this.books.length)) + }, isSeriesFinished() { return this.books.length === this.seriesBooksFinished.length }, diff --git a/client/components/cards/NarratorCard.vue b/client/components/cards/NarratorCard.vue new file mode 100644 index 00000000..9d3e5a30 --- /dev/null +++ b/client/components/cards/NarratorCard.vue @@ -0,0 +1,50 @@ + + + \ No newline at end of file diff --git a/client/components/cards/NarratorSearchCard.vue b/client/components/cards/NarratorSearchCard.vue new file mode 100644 index 00000000..e147e079 --- /dev/null +++ b/client/components/cards/NarratorSearchCard.vue @@ -0,0 +1,34 @@ + + + + + \ No newline at end of file diff --git a/client/components/controls/GlobalSearch.vue b/client/components/controls/GlobalSearch.vue index 670eb6e7..3dbebf1c 100644 --- a/client/components/controls/GlobalSearch.vue +++ b/client/components/controls/GlobalSearch.vue @@ -63,6 +63,15 @@ + +

{{ $strings.LabelNarrators }}

+
@@ -84,6 +93,7 @@ export default { authorResults: [], seriesResults: [], tagResults: [], + narratorResults: [], searchTimeout: null, lastSearch: null } @@ -114,6 +124,7 @@ export default { this.authorResults = [] this.seriesResults = [] this.tagResults = [] + this.narratorResults = [] this.showMenu = false this.isFetching = false this.isTyping = false @@ -142,7 +153,7 @@ export default { } this.isFetching = true - var searchResults = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/search?q=${value}&limit=3`).catch((error) => { + const searchResults = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/search?q=${value}&limit=3`).catch((error) => { console.error('Search error', error) return [] }) @@ -155,6 +166,7 @@ export default { this.authorResults = searchResults.authors || [] this.seriesResults = searchResults.series || [] this.tagResults = searchResults.tags || [] + this.narratorResults = searchResults.narrators || [] this.isFetching = false if (!this.showMenu) { diff --git a/client/components/modals/AccountModal.vue b/client/components/modals/AccountModal.vue index b1cdabf0..070baab4 100644 --- a/client/components/modals/AccountModal.vue +++ b/client/components/modals/AccountModal.vue @@ -6,7 +6,7 @@
-
+
@@ -96,7 +96,14 @@
- +
+ +
+

{{ $strings.LabelInvert }}

+ +
+
+
@@ -185,6 +192,9 @@ export default { value: t } }) + }, + tagsSelectionText() { + return this.newUser.permissions.selectedTagsNotAccessible ? this.$strings.LabelTagsNotAccessibleToUser : this.$strings.LabelTagsAccessibleToUser } }, methods: { @@ -193,8 +203,11 @@ export default { if (this.$refs.modal) this.$refs.modal.setHide() }, accessAllTagsToggled(val) { - if (val && this.newUser.itemTagsAccessible.length) { - this.newUser.itemTagsAccessible = [] + if (val) { + if (this.newUser.itemTagsSelected?.length) { + this.newUser.itemTagsSelected = [] + } + this.newUser.permissions.selectedTagsNotAccessible = false } }, fetchAllTags() { @@ -226,7 +239,7 @@ export default { this.$toast.error('Must select at least one library') return } - if (!this.newUser.permissions.accessAllTags && !this.newUser.itemTagsAccessible.length) { + if (!this.newUser.permissions.accessAllTags && !this.newUser.itemTagsSelected.length) { this.$toast.error('Must select at least one tag') return } @@ -307,12 +320,12 @@ export default { delete: type === 'admin', upload: type === 'admin', accessAllLibraries: true, - accessAllTags: true + accessAllTags: true, + selectedTagsNotAccessible: false } }, init() { this.fetchAllTags() - this.isNew = !this.account if (this.account) { this.newUser = { @@ -322,9 +335,10 @@ export default { isActive: this.account.isActive, permissions: { ...this.account.permissions }, librariesAccessible: [...(this.account.librariesAccessible || [])], - itemTagsAccessible: [...(this.account.itemTagsAccessible || [])] + itemTagsSelected: [...(this.account.itemTagsSelected || [])] } } else { + this.fetchAllTags() this.newUser = { username: null, password: null, @@ -336,7 +350,8 @@ export default { delete: false, upload: false, accessAllLibraries: true, - accessAllTags: true + accessAllTags: true, + selectedTagsNotAccessible: false }, librariesAccessible: [] } diff --git a/client/components/widgets/NarratorsSlider.vue b/client/components/widgets/NarratorsSlider.vue new file mode 100644 index 00000000..77302f6f --- /dev/null +++ b/client/components/widgets/NarratorsSlider.vue @@ -0,0 +1,100 @@ + + + \ No newline at end of file diff --git a/client/layouts/default.vue b/client/layouts/default.vue index 8c9316fa..b201fc4a 100644 --- a/client/layouts/default.vue +++ b/client/layouts/default.vue @@ -569,6 +569,7 @@ export default { changeLanguage(code) { console.log('Changed lang', code) this.currentLang = code + document.documentElement.lang = code } }, beforeMount() { @@ -593,6 +594,11 @@ export default { this.$toast.error(this.$route.query.error) this.$router.replace(this.$route.path) } + + // Set lang on HTML tag + if (this.$languageCodes?.current) { + document.documentElement.lang = this.$languageCodes.current + } }, beforeDestroy() { this.$eventBus.$off('change-lang', this.changeLanguage) diff --git a/client/pages/library/_library/search.vue b/client/pages/library/_library/search.vue index b338323f..2f43d202 100644 --- a/client/pages/library/_library/search.vue +++ b/client/pages/library/_library/search.vue @@ -11,27 +11,27 @@