diff --git a/client/src/components/Filters.vue b/client/src/components/Filters.vue index 826d76a..53d669d 100644 --- a/client/src/components/Filters.vue +++ b/client/src/components/Filters.vue @@ -20,6 +20,29 @@ +
+
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
@@ -124,12 +147,6 @@
-
- - - -
-
+
+ + + +
+
{{ applyFiltersLabel }} @@ -190,6 +213,8 @@ formIsLive: undefined, + formResultType: undefined, + activeFilters: 0 } }, @@ -326,6 +351,7 @@ nsfw: this.formNSFW, host: this.formHost || undefined, isLive: this.formIsLive, + resultType: this.formResultType, publishedDateRange: this.formPublishedDateRange, durationRange: this.formDurationRange, categoryOneOf: this.formCategoryOneOf, @@ -366,6 +392,9 @@ if (query.isLive) this.formIsLive = query.isLive else this.formIsLive = undefined + if (query.resultType) this.formResultType = query.resultType + else this.formResultType = undefined + if (query.host) this.formHost = query.host else this.formHost = '' }, @@ -378,6 +407,7 @@ else if (field === 'licenceOneOf') this.formLicenceOneOf = undefined else if (field === 'languageOneOf') this.formLanguageOneOf = undefined else if (field === 'isLive') this.formIsLive = undefined + else if (field === 'resultType') this.formResultType = undefined else if (field === 'tagsAllOf') this.formTagsAllOf = [] else if (field === 'tagsOneOf') this.formTagsOneOf = [] else if (field === 'host') this.formHost = '' diff --git a/client/src/models/search-url.model.ts b/client/src/models/search-url.model.ts index a97d092..bf9e934 100644 --- a/client/src/models/search-url.model.ts +++ b/client/src/models/search-url.model.ts @@ -11,6 +11,8 @@ export interface SearchUrl { tagsAllOf?: string[] tagsOneOf?: string[] + resultType?: 'videos' | 'channels' | 'playlists' + isLive?: string sort?: string diff --git a/client/src/scss/classes.scss b/client/src/scss/classes.scss index 66731ac..7b4dc02 100644 --- a/client/src/scss/classes.scss +++ b/client/src/scss/classes.scss @@ -17,7 +17,7 @@ [type=radio]:checked + label, [type=radio]:not(:checked) + label { position: relative; - padding-left: 28px; + padding-left: 20px; cursor: pointer; line-height: 20px; display: inline-block; @@ -29,7 +29,7 @@ content: ''; position: absolute; left: 0; - top: 0; + top: 2px; width: 14px; height: 14px; border: 1px solid #C6C6C6; @@ -44,7 +44,7 @@ height: 8px; background: $orange-main; position: absolute; - top: 3px; + top: 5px; left: 3px; border-radius: 100%; transition: all 0.2s ease; diff --git a/client/src/views/Search.vue b/client/src/views/Search.vue index 6a54fc7..270cf44 100644 --- a/client/src/views/Search.vue +++ b/client/src/views/Search.vue @@ -35,27 +35,87 @@ -
+
- - {{ $gettext('No results found.') }} - + {{ $gettext('No results found.') }} - - {{ $ngettext('%{resultsCount} result found:', '%{resultsCount} results found:', resultsCount, { resultsCount: resultsCount.toLocaleString() }) }} - + {{ $ngettext('%{totalResults} result found:', '%{totalResults} results found:', totalResults, { totalResults: totalResults.toLocaleString() }) }}
-
- +
+

+ + {{ $ngettext('%{totalVideos} video', '%{totalVideos} videos', totalVideos, { totalVideos: totalVideos + '' }) }} + +

- +
- +
+

+ + {{ $ngettext('%{totalChannels} channel', '%{totalChannels} channels', totalChannels, { totalChannels: totalChannels + '' }) }} + +

+ + +
+ +
+

+ + {{ $ngettext('%{totalPlaylists} playlist', '%{totalPlaylists} playlists', totalPlaylists, { totalPlaylists: totalPlaylists + '' }) }} + +

+ + +
+ +
@@ -102,22 +162,30 @@ searched: false, indexName: '', - results: [] as (EnhancedVideo | EnhancedVideoChannel | EnhancedPlaylist)[], - resultsCount: null as number, - channelsCount: null as number, - videosCount: null as number, - playlistsCount: null as number, + totalResults: null as number, + + totalVideos: null as number, + videos: null as EnhancedVideo[], + + totalChannels: null as number, + channels: null as EnhancedVideoChannel[], + + totalPlaylists: null as number, + playlists: null as EnhancedPlaylist[], currentPage: 1, pages: [], - resultsPerVideosPage: 10, - resultsPerChannelsPage: 3, - resultsPerPlaylistsPage: 3, + + summaryResultsCount: { + videos: 5, + channels: 2, + playlists: 2 + }, + filteredTypeResultsPerPage: 10, activeFilters: 0, - displayFilters: false, - oldQuery: '' + displayFilters: false } }, @@ -163,7 +231,9 @@ methods: { async doSearch () { - this.results = [] + this.videos = [] + this.channels = [] + this.playlists = [] this.searched = false Nprogress.start() @@ -179,15 +249,17 @@ this.activeFilters = this.countActiveFilters() - this.channelsCount = channelsResult.total - this.videosCount = videosResult.total - this.playlistsCount = playlistsResult.total - this.resultsCount = videosResult.total + channelsResult.total + playlistsResult.total + this.totalVideos = videosResult.total + this.videos = videosResult.data - this.results = channelsResult.data - this.results = this.results.concat(playlistsResult.data) - this.results = this.results.concat(videosResult.data) + this.totalChannels = channelsResult.total + this.channels = channelsResult.data + + this.totalPlaylists = playlistsResult.total + this.playlists = playlistsResult.data + + this.totalResults = videosResult.total + channelsResult.total + playlistsResult.total this.buildPages() this.searched = true @@ -199,32 +271,6 @@ } }, - isVideo (result: EnhancedVideo | EnhancedVideoChannel | EnhancedPlaylist): result is EnhancedVideo { - if ((result as EnhancedVideo).language) return true - - return false - }, - - isPlaylist (result: EnhancedVideo | EnhancedVideoChannel | EnhancedPlaylist): result is EnhancedPlaylist { - if ((result as EnhancedPlaylist).videosLength !== undefined) return true - - return false - }, - - isChannel (result: EnhancedVideo | EnhancedVideoChannel | EnhancedPlaylist): result is EnhancedVideoChannel { - if ((result as EnhancedVideoChannel).followingCount !== undefined) return true - - return false - }, - - getResultKey (result: EnhancedVideo | EnhancedVideoChannel | EnhancedPlaylist) { - if (this.isVideo(result)) return (result as EnhancedVideo).uuid - if (this.isChannel(result)) return result.id + (result as EnhancedVideoChannel).host - if (this.isPlaylist(result)) return (result as EnhancedPlaylist).uuid - - throw new Error('Unknown result') - }, - loadUrl () { const query = this.$route.query as SearchUrl const queryPage = extractQueryToInt(query.page) @@ -247,6 +293,7 @@ if (query.licenceOneOf) count++ if (query.languageOneOf) count++ if (query.isLive) count++ + if (query.resultType) count++ if (Array.isArray(query.tagsAllOf) && query.tagsAllOf.length !== 0) count++ if (Array.isArray(query.tagsOneOf) && query.tagsOneOf.length !== 0) count++ @@ -256,7 +303,11 @@ buildVideoSearchQuery () { const query = this.$route.query as SearchUrl - const { start, count } = pageToAPIParams(this.currentPage, this.resultsPerVideosPage) + const resultsPerPage = this.getResultTypeFilter() === 'videos' + ? this.filteredTypeResultsPerPage + : this.summaryResultsCount.videos + + const { start, count } = pageToAPIParams(this.currentPage, resultsPerPage) const { durationMin, durationMax } = durationRangeToAPIParams(query.durationRange) const { startDate, endDate } = publishedDateRangeToAPIParams(query.publishedDateRange) @@ -300,7 +351,11 @@ buildChannelSearchQuery () { const query = this.$route.query as SearchUrl - const { start, count } = pageToAPIParams(this.currentPage, this.resultsPerChannelsPage) + const resultsPerPage = this.getResultTypeFilter() === 'channels' + ? this.filteredTypeResultsPerPage + : this.summaryResultsCount.channels + + const { start, count } = pageToAPIParams(this.currentPage, resultsPerPage) return { search: query.search, @@ -313,7 +368,12 @@ buildPlaylistSearchQuery () { const query = this.$route.query as SearchUrl - const { start, count } = pageToAPIParams(this.currentPage, this.resultsPerChannelsPage) + + const resultsPerPage = this.getResultTypeFilter() === 'playlists' + ? this.filteredTypeResultsPerPage + : this.summaryResultsCount.playlists + + const { start, count } = pageToAPIParams(this.currentPage, resultsPerPage) return { search: query.search, @@ -325,13 +385,17 @@ }, searchVideos (): Promise> { + if (this.isVideoSearchDisabled()) { + return Promise.resolve({ total: 0, data: [] }) + } + const query = this.buildVideoSearchQuery() return searchVideos(query) }, searchChannels (): Promise> { - if (this.isChannelOrPlaylistSearchDisabled()) { + if (this.isChannelSearchDisabled()) { return Promise.resolve({ data: [], total: 0 }) } @@ -341,7 +405,7 @@ }, searchPlaylists (): Promise> { - if (this.isChannelOrPlaylistSearchDisabled()) { + if (this.isPlaylistSearchDisabled()) { return Promise.resolve({ data: [], total: 0 }) } @@ -350,21 +414,19 @@ return searchVideoPlaylists(query) }, - getChannelsMaxPage () { - return Math.ceil(this.channelsCount / this.resultsPerChannelsPage) - }, - - getPlaylistsMaxPage () { - return Math.ceil(this.playlistsCount / this.resultsPerPlaylistsPage) - }, - - getVideosMaxPage () { - return Math.ceil(this.videosCount / this.resultsPerVideosPage) - }, + // --------------------------------------------------------------------------- getMaxPage () { + const resultType = (this.$route.query as SearchUrl).resultType + + let maxPage: number + + if (resultType === 'videos') maxPage = Math.ceil(this.totalVideos / this.filteredTypeResultsPerPage) + else if (resultType === 'channels') maxPage = Math.ceil(this.totalChannels / this.filteredTypeResultsPerPage) + else if (resultType === 'playlists') maxPage = Math.ceil(this.totalPlaylists / this.filteredTypeResultsPerPage) + // Limit to 10 pages - return Math.min(10, Math.max(this.getPlaylistsMaxPage(), this.getChannelsMaxPage(), this.getVideosMaxPage())) + return Math.min(10, maxPage) }, buildPages () { @@ -379,11 +441,51 @@ this.displayFilters = !this.displayFilters }, - isChannelOrPlaylistSearchDisabled () { - const query = this.$route.query as SearchUrl + // --------------------------------------------------------------------------- + + getResultTypeFilter () { + return (this.$route.query as SearchUrl).resultType + }, + + hasResultTypeFilter () { + return !!this.getResultTypeFilter() + }, + + getMoreResultsQuery (type: 'videos' | 'channels' | 'playlists'): SearchUrl { + return { + ...this.$route.query, + + resultType: type + } + }, + + // --------------------------------------------------------------------------- + + isVideoSearchDisabled () { + const { resultType } = this.$route.query as SearchUrl + + if (resultType !== undefined && resultType !== 'videos') return true + + return false + }, + + isChannelSearchDisabled () { + const { resultType, host } = this.$route.query as SearchUrl + + if (resultType !== undefined && resultType !== 'channels') return true // We can search against host for playlists and channels - if (query.host) return this.countActiveFilters() > 1 + if (host) return this.countActiveFilters() > 1 + + return this.countActiveFilters() > 0 + }, + + isPlaylistSearchDisabled () { + const { resultType, host } = this.$route.query as SearchUrl + if (resultType !== undefined && resultType !== 'playlists') return true + + // We can search against host for playlists and channels + if (host) return this.countActiveFilters() > 1 return this.countActiveFilters() > 0 } @@ -463,4 +565,8 @@ text-align: center; } + h2 { + @include font-size(1.125rem); + } +