mirror of https://github.com/FreeTubeApp/FreeTube
Compare commits
7 Commits
5a71ff2a3d
...
977ef1c2e9
Author | SHA1 | Date |
---|---|---|
ChunkyProgrammer | 977ef1c2e9 | |
Jason | 4bb53f780c | |
absidue | a5f3410378 | |
absidue | 4c511869fc | |
Elias Groß | 2f4c757741 | |
ChunkyProgrammer | 9b990bc5a8 | |
ChunkyProgrammer | 7505a5bb8c |
|
@ -64,6 +64,7 @@
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"marked": "^12.0.2",
|
"marked": "^12.0.2",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
|
"portal-vue": "^2.1.7",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"swiper": "^11.1.1",
|
"swiper": "^11.1.1",
|
||||||
"video.js": "7.21.5",
|
"video.js": "7.21.5",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import FtToast from './components/ft-toast/ft-toast.vue'
|
||||||
import FtProgressBar from './components/ft-progress-bar/ft-progress-bar.vue'
|
import FtProgressBar from './components/ft-progress-bar/ft-progress-bar.vue'
|
||||||
import FtPlaylistAddVideoPrompt from './components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue'
|
import FtPlaylistAddVideoPrompt from './components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue'
|
||||||
import FtCreatePlaylistPrompt from './components/ft-create-playlist-prompt/ft-create-playlist-prompt.vue'
|
import FtCreatePlaylistPrompt from './components/ft-create-playlist-prompt/ft-create-playlist-prompt.vue'
|
||||||
|
import FtSearchFilters from './components/ft-search-filters/ft-search-filters.vue'
|
||||||
import { marked } from 'marked'
|
import { marked } from 'marked'
|
||||||
import { IpcChannels } from '../constants'
|
import { IpcChannels } from '../constants'
|
||||||
import packageDetails from '../../package.json'
|
import packageDetails from '../../package.json'
|
||||||
|
@ -34,6 +35,7 @@ export default defineComponent({
|
||||||
FtProgressBar,
|
FtProgressBar,
|
||||||
FtPlaylistAddVideoPrompt,
|
FtPlaylistAddVideoPrompt,
|
||||||
FtCreatePlaylistPrompt,
|
FtCreatePlaylistPrompt,
|
||||||
|
FtSearchFilters
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
@ -46,6 +48,7 @@ export default defineComponent({
|
||||||
latestBlogUrl: '',
|
latestBlogUrl: '',
|
||||||
updateChangelog: '',
|
updateChangelog: '',
|
||||||
changeLogTitle: '',
|
changeLogTitle: '',
|
||||||
|
isPromptOpen: false,
|
||||||
lastExternalLinkToBeOpened: '',
|
lastExternalLinkToBeOpened: '',
|
||||||
showExternalLinkOpeningPrompt: false,
|
showExternalLinkOpeningPrompt: false,
|
||||||
externalLinkOpeningPromptValues: [
|
externalLinkOpeningPromptValues: [
|
||||||
|
@ -77,6 +80,9 @@ export default defineComponent({
|
||||||
showCreatePlaylistPrompt: function () {
|
showCreatePlaylistPrompt: function () {
|
||||||
return this.$store.getters.getShowCreatePlaylistPrompt
|
return this.$store.getters.getShowCreatePlaylistPrompt
|
||||||
},
|
},
|
||||||
|
showSearchFilters: function () {
|
||||||
|
return this.$store.getters.getShowSearchFilters
|
||||||
|
},
|
||||||
windowTitle: function () {
|
windowTitle: function () {
|
||||||
const routePath = this.$route.path
|
const routePath = this.$route.path
|
||||||
if (!routePath.startsWith('/channel/') && !routePath.startsWith('/watch/') && !routePath.startsWith('/hashtag/')) {
|
if (!routePath.startsWith('/channel/') && !routePath.startsWith('/watch/') && !routePath.startsWith('/hashtag/')) {
|
||||||
|
@ -143,12 +149,6 @@ export default defineComponent({
|
||||||
secColor: 'checkThemeSettings',
|
secColor: 'checkThemeSettings',
|
||||||
|
|
||||||
locale: 'setLocale',
|
locale: 'setLocale',
|
||||||
|
|
||||||
$route () {
|
|
||||||
// react to route changes...
|
|
||||||
// Hide top nav filter panel on page change
|
|
||||||
this.$refs.topNav?.hideFilters()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
this.checkThemeSettings()
|
this.checkThemeSettings()
|
||||||
|
@ -159,11 +159,17 @@ export default defineComponent({
|
||||||
this.grabUserSettings().then(async () => {
|
this.grabUserSettings().then(async () => {
|
||||||
this.checkThemeSettings()
|
this.checkThemeSettings()
|
||||||
|
|
||||||
await this.fetchInvidiousInstances()
|
await this.fetchInvidiousInstancesFromFile()
|
||||||
if (this.defaultInvidiousInstance === '') {
|
if (this.defaultInvidiousInstance === '') {
|
||||||
await this.setRandomCurrentInvidiousInstance()
|
await this.setRandomCurrentInvidiousInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.fetchInvidiousInstances().then(e => {
|
||||||
|
if (this.defaultInvidiousInstance === '') {
|
||||||
|
this.setRandomCurrentInvidiousInstance()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
this.grabAllProfiles(this.$t('Profile.All Channels')).then(async () => {
|
this.grabAllProfiles(this.$t('Profile.All Channels')).then(async () => {
|
||||||
this.grabHistory()
|
this.grabHistory()
|
||||||
this.grabAllPlaylists()
|
this.grabAllPlaylists()
|
||||||
|
@ -295,6 +301,10 @@ export default defineComponent({
|
||||||
this.showBlogBanner = false
|
this.showBlogBanner = false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handlePromptPortalUpdate: function(newVal) {
|
||||||
|
this.isPromptOpen = newVal
|
||||||
|
},
|
||||||
|
|
||||||
openDownloadsPage: function () {
|
openDownloadsPage: function () {
|
||||||
const url = 'https://freetubeapp.io#download'
|
const url = 'https://freetubeapp.io#download'
|
||||||
openExternalLink(url)
|
openExternalLink(url)
|
||||||
|
@ -538,13 +548,14 @@ export default defineComponent({
|
||||||
'getYoutubeUrlInfo',
|
'getYoutubeUrlInfo',
|
||||||
'getExternalPlayerCmdArgumentsData',
|
'getExternalPlayerCmdArgumentsData',
|
||||||
'fetchInvidiousInstances',
|
'fetchInvidiousInstances',
|
||||||
|
'fetchInvidiousInstancesFromFile',
|
||||||
'setRandomCurrentInvidiousInstance',
|
'setRandomCurrentInvidiousInstance',
|
||||||
'setupListenersToSyncWindows',
|
'setupListenersToSyncWindows',
|
||||||
'updateBaseTheme',
|
'updateBaseTheme',
|
||||||
'updateMainColor',
|
'updateMainColor',
|
||||||
'updateSecColor',
|
'updateSecColor',
|
||||||
'showOutlines',
|
'showOutlines',
|
||||||
'hideOutlines'
|
'hideOutlines',
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,11 +8,63 @@
|
||||||
isLocaleRightToLeft: isLocaleRightToLeft
|
isLocaleRightToLeft: isLocaleRightToLeft
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<top-nav ref="topNav" />
|
<portal-target
|
||||||
<side-nav ref="sideNav" />
|
name="promptPortal"
|
||||||
|
@change="handlePromptPortalUpdate"
|
||||||
|
/>
|
||||||
|
<ft-prompt
|
||||||
|
v-if="showReleaseNotes"
|
||||||
|
:label="changeLogTitle"
|
||||||
|
@click="showReleaseNotes = !showReleaseNotes"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="changeLogText"
|
||||||
|
v-html="updateChangelog"
|
||||||
|
/>
|
||||||
|
<ft-flex-box>
|
||||||
|
<ft-button
|
||||||
|
:label="$t('Download From Site')"
|
||||||
|
@click="openDownloadsPage"
|
||||||
|
/>
|
||||||
|
<ft-button
|
||||||
|
:label="$t('Close')"
|
||||||
|
@click="showReleaseNotes = !showReleaseNotes"
|
||||||
|
/>
|
||||||
|
</ft-flex-box>
|
||||||
|
</ft-prompt>
|
||||||
|
<ft-prompt
|
||||||
|
v-if="showExternalLinkOpeningPrompt"
|
||||||
|
:label="$t('Are you sure you want to open this link?')"
|
||||||
|
:extra-labels="[lastExternalLinkToBeOpened]"
|
||||||
|
:option-names="externalLinkOpeningPromptNames"
|
||||||
|
:option-values="externalLinkOpeningPromptValues"
|
||||||
|
@click="handleExternalLinkOpeningPromptAnswer"
|
||||||
|
/>
|
||||||
|
<ft-search-filters
|
||||||
|
v-if="showSearchFilters"
|
||||||
|
/>
|
||||||
|
<ft-playlist-add-video-prompt
|
||||||
|
v-if="showAddToPlaylistPrompt"
|
||||||
|
/>
|
||||||
|
<ft-create-playlist-prompt
|
||||||
|
v-if="showCreatePlaylistPrompt"
|
||||||
|
/>
|
||||||
|
<ft-toast />
|
||||||
|
<ft-progress-bar
|
||||||
|
v-if="showProgressBar"
|
||||||
|
/>
|
||||||
|
<top-nav
|
||||||
|
ref="topNav"
|
||||||
|
:inert="isPromptOpen"
|
||||||
|
/>
|
||||||
|
<side-nav
|
||||||
|
ref="sideNav"
|
||||||
|
:inert="isPromptOpen"
|
||||||
|
/>
|
||||||
<ft-flex-box
|
<ft-flex-box
|
||||||
class="flexBox routerView"
|
class="flexBox routerView"
|
||||||
role="main"
|
role="main"
|
||||||
|
:inert="isPromptOpen"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="showUpdatesBanner || showBlogBanner"
|
v-if="showUpdatesBanner || showBlogBanner"
|
||||||
|
@ -43,48 +95,9 @@
|
||||||
ref="router"
|
ref="router"
|
||||||
class="routerView"
|
class="routerView"
|
||||||
/>
|
/>
|
||||||
<!-- </keep-alive> -->
|
<!-- </keep-alive> -->
|
||||||
</transition>
|
</transition>
|
||||||
</ft-flex-box>
|
</ft-flex-box>
|
||||||
|
|
||||||
<ft-prompt
|
|
||||||
v-if="showReleaseNotes"
|
|
||||||
:label="changeLogTitle"
|
|
||||||
@click="showReleaseNotes = !showReleaseNotes"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="changeLogText"
|
|
||||||
v-html="updateChangelog"
|
|
||||||
/>
|
|
||||||
<ft-flex-box>
|
|
||||||
<ft-button
|
|
||||||
:label="$t('Download From Site')"
|
|
||||||
@click="openDownloadsPage"
|
|
||||||
/>
|
|
||||||
<ft-button
|
|
||||||
:label="$t('Close')"
|
|
||||||
@click="showReleaseNotes = !showReleaseNotes"
|
|
||||||
/>
|
|
||||||
</ft-flex-box>
|
|
||||||
</ft-prompt>
|
|
||||||
<ft-prompt
|
|
||||||
v-if="showExternalLinkOpeningPrompt"
|
|
||||||
:label="$t('Are you sure you want to open this link?')"
|
|
||||||
:extra-labels="[lastExternalLinkToBeOpened]"
|
|
||||||
:option-names="externalLinkOpeningPromptNames"
|
|
||||||
:option-values="externalLinkOpeningPromptValues"
|
|
||||||
@click="handleExternalLinkOpeningPromptAnswer"
|
|
||||||
/>
|
|
||||||
<ft-playlist-add-video-prompt
|
|
||||||
v-if="showAddToPlaylistPrompt"
|
|
||||||
/>
|
|
||||||
<ft-create-playlist-prompt
|
|
||||||
v-if="showCreatePlaylistPrompt"
|
|
||||||
/>
|
|
||||||
<ft-toast />
|
|
||||||
<ft-progress-bar
|
|
||||||
v-if="showProgressBar"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent, nextTick } from 'vue'
|
||||||
import { mapActions } from 'vuex'
|
import { mapActions } from 'vuex'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
||||||
|
@ -24,6 +24,9 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
title: function () {
|
||||||
|
return this.$t('User Playlists.CreatePlaylistPrompt.New Playlist Name')
|
||||||
|
},
|
||||||
allPlaylists: function () {
|
allPlaylists: function () {
|
||||||
return this.$store.getters.getAllPlaylists
|
return this.$store.getters.getAllPlaylists
|
||||||
},
|
},
|
||||||
|
@ -34,7 +37,7 @@ export default defineComponent({
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.playlistName = this.newPlaylistVideoObject.title
|
this.playlistName = this.newPlaylistVideoObject.title
|
||||||
// Faster to input required playlist name
|
// Faster to input required playlist name
|
||||||
this.$refs.playlistNameInput.focus()
|
nextTick(() => this.$refs.playlistNameInput.focus())
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
createNewPlaylist: function () {
|
createNewPlaylist: function () {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-prompt
|
<ft-prompt
|
||||||
|
:label="title"
|
||||||
@click="hideCreatePlaylistPrompt"
|
@click="hideCreatePlaylistPrompt"
|
||||||
>
|
>
|
||||||
<h2 class="center">
|
<h2 class="center">
|
||||||
{{ $t('User Playlists.CreatePlaylistPrompt.New Playlist Name') }}
|
{{ title }}
|
||||||
</h2>
|
</h2>
|
||||||
<ft-flex-box>
|
<ft-flex-box>
|
||||||
<ft-input
|
<ft-input
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
|
|
||||||
.tag-icon {
|
.tag-icon {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
block-size: 24px;
|
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,9 @@
|
||||||
:src="tag.icon"
|
:src="tag.icon"
|
||||||
alt=""
|
alt=""
|
||||||
class="tag-icon"
|
class="tag-icon"
|
||||||
|
height="24"
|
||||||
|
width="24"
|
||||||
|
loading="lazy"
|
||||||
>
|
>
|
||||||
</router-link>
|
</router-link>
|
||||||
<span>{{ (tag.preferredName) ? tag.preferredName : tag.name }}</span>
|
<span>{{ (tag.preferredName) ? tag.preferredName : tag.name }}</span>
|
||||||
|
|
|
@ -6,16 +6,6 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Style for `ft-prompt` */
|
|
||||||
:deep(.promptCard) {
|
|
||||||
/* Currently only this prompt has enough content to make prompt too high */
|
|
||||||
max-block-size: 95%;
|
|
||||||
|
|
||||||
/* Some child(s) will grow vertically */
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.searchInputsRow {
|
.searchInputsRow {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent, nextTick } from 'vue'
|
||||||
import { mapActions } from 'vuex'
|
import { mapActions } from 'vuex'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
|
@ -44,11 +44,16 @@ export default defineComponent({
|
||||||
doSearchPlaylistsWithMatchingVideos: false,
|
doSearchPlaylistsWithMatchingVideos: false,
|
||||||
updateQueryDebounce: function() {},
|
updateQueryDebounce: function() {},
|
||||||
lastShownAt: Date.now(),
|
lastShownAt: Date.now(),
|
||||||
lastActiveElement: null,
|
|
||||||
sortBy: SORT_BY_VALUES.LatestUpdatedFirst,
|
sortBy: SORT_BY_VALUES.LatestUpdatedFirst,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
title: function () {
|
||||||
|
return this.$tc('User Playlists.AddVideoPrompt.Select a playlist to add your N videos to', this.toBeAddedToPlaylistVideoCount, {
|
||||||
|
videoCount: this.toBeAddedToPlaylistVideoCount,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
showingCreatePlaylistPrompt: function () {
|
showingCreatePlaylistPrompt: function () {
|
||||||
return this.$store.getters.getShowCreatePlaylistPrompt
|
return this.$store.getters.getShowCreatePlaylistPrompt
|
||||||
},
|
},
|
||||||
|
@ -185,7 +190,7 @@ export default defineComponent({
|
||||||
if (val > oldVal) {
|
if (val > oldVal) {
|
||||||
// Focus back to search input only when playlist added
|
// Focus back to search input only when playlist added
|
||||||
// Allow search and easier deselecting new created playlist
|
// Allow search and easier deselecting new created playlist
|
||||||
this.$refs.searchBar.focus()
|
nextTick(() => this.$refs.searchBar.focus())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -195,19 +200,17 @@ export default defineComponent({
|
||||||
// Only care when CreatePlaylistPrompt hidden
|
// Only care when CreatePlaylistPrompt hidden
|
||||||
// Shift focus from button to prevent unwanted click event
|
// Shift focus from button to prevent unwanted click event
|
||||||
// due to enter key press in CreatePlaylistPrompt
|
// due to enter key press in CreatePlaylistPrompt
|
||||||
this.$refs.searchBar.focus()
|
nextTick(() => this.$refs.searchBar.focus())
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.lastActiveElement = document.activeElement
|
|
||||||
this.updateQueryDebounce = debounce(this.updateQuery, 500)
|
this.updateQueryDebounce = debounce(this.updateQuery, 500)
|
||||||
// User might want to search first if they have many playlists
|
|
||||||
this.$refs.searchBar.focus()
|
|
||||||
document.addEventListener('keydown', this.keyboardShortcutHandler)
|
document.addEventListener('keydown', this.keyboardShortcutHandler)
|
||||||
|
// User might want to search first if they have many playlists
|
||||||
|
nextTick(() => this.$refs.searchBar.focus())
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
document.removeEventListener('keydown', this.keyboardShortcutHandler)
|
document.removeEventListener('keydown', this.keyboardShortcutHandler)
|
||||||
this.lastActiveElement?.focus()
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hide: function () {
|
hide: function () {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-prompt
|
<ft-prompt
|
||||||
|
theme="flex-column"
|
||||||
|
:label="title"
|
||||||
@click="hide"
|
@click="hide"
|
||||||
>
|
>
|
||||||
<h2 class="heading">
|
<h2 class="heading">
|
||||||
{{ $tc('User Playlists.AddVideoPrompt.Select a playlist to add your N videos to', toBeAddedToPlaylistVideoCount, {
|
{{ title }}
|
||||||
videoCount: toBeAddedToPlaylistVideoCount,
|
|
||||||
}) }}
|
|
||||||
</h2>
|
</h2>
|
||||||
<p class="selected-count">
|
<p class="selected-count">
|
||||||
{{ $tc('User Playlists.AddVideoPrompt.N playlists selected', selectedPlaylistCount, {
|
{{ $tc('User Playlists.AddVideoPrompt.N playlists selected', selectedPlaylistCount, {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
background-color: rgb(0 0 0 / 70%);
|
background-color: rgb(0 0 0 / 70%);
|
||||||
|
|
||||||
/* Higher than components like playlist info */
|
/* Higher than components like playlist info */
|
||||||
z-index: 200;
|
z-index: 201;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
.promptCard {
|
.promptCard {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
max-block-size: 95%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.promptCard.autosize {
|
.promptCard.autosize {
|
||||||
|
@ -34,6 +35,31 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.promptCard.flex-column {
|
||||||
|
/* Some child(ren) will grow vertically */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promptCard.slim {
|
||||||
|
max-inline-size: 70%;
|
||||||
|
inset-inline-start: 15%;
|
||||||
|
padding-block: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.center {
|
.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (width <= 680px) {
|
||||||
|
.promptCard.slim {
|
||||||
|
padding-block: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (width <= 500px) {
|
||||||
|
.promptCard.slim {
|
||||||
|
max-inline-size: 80%;
|
||||||
|
inset-inline-start: 10%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent, nextTick } from 'vue'
|
||||||
import { mapActions } from 'vuex'
|
import { mapActions } from 'vuex'
|
||||||
import FtCard from '../../components/ft-card/ft-card.vue'
|
import FtCard from '../../components/ft-card/ft-card.vue'
|
||||||
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
||||||
|
@ -15,7 +15,7 @@ export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
required: true
|
||||||
},
|
},
|
||||||
extraLabels: {
|
extraLabels: {
|
||||||
type: Array,
|
type: Array,
|
||||||
|
@ -36,6 +36,10 @@ export default defineComponent({
|
||||||
autosize: {
|
autosize: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
type: String,
|
||||||
|
default: 'base'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['click'],
|
emits: ['click'],
|
||||||
|
@ -50,21 +54,22 @@ export default defineComponent({
|
||||||
return sanitizeForHtmlId(this.label)
|
return sanitizeForHtmlId(this.label)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy: function () {
|
|
||||||
document.removeEventListener('keydown', this.closeEventFunction, true)
|
|
||||||
this.lastActiveElement?.focus()
|
|
||||||
},
|
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.lastActiveElement = document.activeElement
|
this.lastActiveElement = document.activeElement
|
||||||
|
this.$nextTick(() => {
|
||||||
document.addEventListener('keydown', this.closeEventFunction, true)
|
document.addEventListener('keydown', this.closeEventFunction, true)
|
||||||
document.querySelector('.prompt').addEventListener('keydown', this.arrowKeys, true)
|
document.querySelector('.prompt').addEventListener('keydown', this.arrowKeys, true)
|
||||||
this.promptButtons = Array.from(
|
this.promptButtons = Array.from(
|
||||||
document.querySelector('.prompt .promptCard .ft-flex-box').childNodes
|
document.querySelector('.prompt .promptCard .ft-flex-box').childNodes
|
||||||
).filter((e) => {
|
).filter((e) => {
|
||||||
return e.id && e.id.startsWith('prompt')
|
return e.id && e.id.startsWith('prompt')
|
||||||
|
})
|
||||||
|
this.focusItem(0)
|
||||||
})
|
})
|
||||||
this.focusItem(0)
|
},
|
||||||
|
beforeDestroy: function () {
|
||||||
|
document.removeEventListener('keydown', this.closeEventFunction, true)
|
||||||
|
nextTick(() => this.lastActiveElement?.focus())
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
click: function (value) {
|
click: function (value) {
|
||||||
|
|
|
@ -1,52 +1,57 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<portal to="promptPortal">
|
||||||
class="prompt"
|
<div
|
||||||
tabindex="-1"
|
ref="openPrompt"
|
||||||
@click="handleHide"
|
class="prompt"
|
||||||
@keydown.enter="handleHide"
|
tabindex="-1"
|
||||||
>
|
@click="handleHide"
|
||||||
<ft-card
|
@keydown.enter="handleHide"
|
||||||
class="promptCard"
|
|
||||||
:class="{ autosize }"
|
|
||||||
:aria-labelledby="('dialog-' + sanitizedLabel)"
|
|
||||||
>
|
>
|
||||||
<slot>
|
<ft-card
|
||||||
<h2
|
class="promptCard"
|
||||||
:id="'dialog-' + sanitizedLabel"
|
:class="{ autosize, [theme]: true }"
|
||||||
class="center"
|
role="dialog"
|
||||||
>
|
aria-modal="true"
|
||||||
{{ label }}
|
:aria-labelledby="('dialog-' + sanitizedLabel)"
|
||||||
</h2>
|
>
|
||||||
<p
|
<slot>
|
||||||
v-for="extraLabel in extraLabels"
|
<h2
|
||||||
:key="extraLabel"
|
:id="'dialog-' + sanitizedLabel"
|
||||||
class="center"
|
class="center"
|
||||||
>
|
>
|
||||||
<strong>
|
{{ label }}
|
||||||
{{ extraLabel }}
|
</h2>
|
||||||
</strong>
|
<p
|
||||||
</p>
|
v-for="extraLabel in extraLabels"
|
||||||
<ft-flex-box>
|
:key="extraLabel"
|
||||||
<ft-button
|
class="center"
|
||||||
v-for="(option, index) in optionNames"
|
>
|
||||||
:id="'prompt-' + sanitizedLabel + '-' + index"
|
<strong>
|
||||||
:key="index"
|
{{ extraLabel }}
|
||||||
:label="option"
|
</strong>
|
||||||
@click="click(optionValues[index])"
|
</p>
|
||||||
/>
|
<ft-flex-box>
|
||||||
<ft-button
|
<ft-button
|
||||||
v-if="showClose"
|
v-for="(option, index) in optionNames"
|
||||||
:id="'prompt-' + sanitizedLabel + '-close'"
|
:id="'prompt-' + sanitizedLabel + '-' + index"
|
||||||
:label="$t('Close')"
|
:key="index"
|
||||||
:tabindex="0"
|
:label="option"
|
||||||
text-color="'var(--accent-color)'"
|
@click="click(optionValues[index])"
|
||||||
background-color="'var(--text-with-accent-color)'"
|
/>
|
||||||
@click="hide"
|
<ft-button
|
||||||
/>
|
v-if="showClose"
|
||||||
</ft-flex-box>
|
:id="'prompt-' + sanitizedLabel + '-close'"
|
||||||
</slot>
|
:label="$t('Close')"
|
||||||
</ft-card>
|
:tabindex="0"
|
||||||
</div>
|
text-color="'var(--accent-color)'"
|
||||||
|
background-color="'var(--text-with-accent-color)'"
|
||||||
|
@click="hide"
|
||||||
|
/>
|
||||||
|
</ft-flex-box>
|
||||||
|
</slot>
|
||||||
|
</ft-card>
|
||||||
|
</div>
|
||||||
|
</portal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./ft-prompt.js" />
|
<script src="./ft-prompt.js" />
|
||||||
|
|
|
@ -11,7 +11,7 @@ pure-checkbox input[type="checkbox"], .pure-radiobutton input[type="checkbox"],
|
||||||
}
|
}
|
||||||
|
|
||||||
.pure-checkbox input[type="checkbox"]:focus + label::before, .pure-radiobutton input[type="checkbox"]:focus + label::before, .pure-checkbox input[type="radio"]:focus + label::before, .pure-radiobutton input[type="radio"]:focus + label::before, .pure-checkbox input[type="checkbox"]:hover + label::before, .pure-radiobutton input[type="checkbox"]:hover + label::before, .pure-checkbox input[type="radio"]:hover + label::before, .pure-radiobutton input[type="radio"]:hover + label::before {
|
.pure-checkbox input[type="checkbox"]:focus + label::before, .pure-radiobutton input[type="checkbox"]:focus + label::before, .pure-checkbox input[type="radio"]:focus + label::before, .pure-radiobutton input[type="radio"]:focus + label::before, .pure-checkbox input[type="checkbox"]:hover + label::before, .pure-radiobutton input[type="checkbox"]:hover + label::before, .pure-checkbox input[type="radio"]:hover + label::before, .pure-radiobutton input[type="radio"]:hover + label::before {
|
||||||
border-color: var(--primary-color);
|
border: 2px solid var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pure-checkbox input[type="checkbox"]:active + label::before, .pure-radiobutton input[type="checkbox"]:active + label::before, .pure-checkbox input[type="radio"]:active + label::before, .pure-radiobutton input[type="radio"]:active + label::before { transition-duration: 0s; }
|
.pure-checkbox input[type="checkbox"]:active + label::before, .pure-radiobutton input[type="checkbox"]:active + label::before, .pure-checkbox input[type="radio"]:active + label::before, .pure-radiobutton input[type="radio"]:active + label::before { transition-duration: 0s; }
|
||||||
|
@ -22,20 +22,20 @@ pure-checkbox input[type="checkbox"], .pure-radiobutton input[type="checkbox"],
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: block;
|
display: block;
|
||||||
margin-block-end: -20px;
|
margin-block-start: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pure-checkbox input[type="checkbox"] + label::before, .pure-radiobutton input[type="checkbox"] + label::before, .pure-checkbox input[type="radio"] + label::before, .pure-radiobutton input[type="radio"] + label::before {
|
.pure-checkbox input[type="checkbox"] + label::before, .pure-radiobutton input[type="checkbox"] + label::before, .pure-checkbox input[type="radio"] + label::before, .pure-radiobutton input[type="radio"] + label::before {
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
content: '';
|
content: '';
|
||||||
color: var(--primary-color);
|
color: var(--primary-text-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset-block-start: 50%;
|
inset-block-start: 50%;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
inline-size: 14px;
|
inline-size: 14px;
|
||||||
block-size: 14px;
|
block-size: 14px;
|
||||||
margin-block-start: -9px;
|
margin-block-start: -9px;
|
||||||
border: 2px solid var(--primary-color);
|
border: 2px solid var(--primary-text-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: all 0.4s ease;
|
transition: all 0.4s ease;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ pure-checkbox input[type="checkbox"], .pure-radiobutton input[type="checkbox"],
|
||||||
.pure-checkbox input[type="checkbox"] + label::after, .pure-radiobutton input[type="checkbox"] + label::after, .pure-checkbox input[type="radio"] + label::after, .pure-radiobutton input[type="radio"] + label::after {
|
.pure-checkbox input[type="checkbox"] + label::after, .pure-radiobutton input[type="checkbox"] + label::after, .pure-checkbox input[type="radio"] + label::after, .pure-radiobutton input[type="radio"] + label::after {
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
content: '';
|
content: '';
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-text-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset-block-start: 50%;
|
inset-block-start: 50%;
|
||||||
inset-inline-start: 4px;
|
inset-inline-start: 4px;
|
||||||
|
@ -84,23 +84,33 @@ pure-checkbox input[type="checkbox"], .pure-radiobutton input[type="checkbox"],
|
||||||
animation: borderscale 300ms ease-in;
|
animation: borderscale 300ms ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pure-radiobutton input[type="radio"]:focus + label::after{
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
.pure-checkbox input[type="radio"]:checked + label::after, .pure-radiobutton input[type="radio"]:checked + label::after { transform: scale(1); }
|
.pure-checkbox input[type="radio"]:checked + label::after, .pure-radiobutton input[type="radio"]:checked + label::after { transform: scale(1); }
|
||||||
|
|
||||||
.pure-checkbox input[type="radio"] + label::before, .pure-radiobutton input[type="radio"] + label::before, .pure-checkbox input[type="radio"] + label::after, .pure-radiobutton input[type="radio"] + label::after { border-radius: 50%; }
|
.pure-checkbox input[type="radio"] + label::before, .pure-radiobutton input[type="radio"] + label::before, .pure-checkbox input[type="radio"] + label::after, .pure-radiobutton input[type="radio"] + label::after { border-radius: 50%; }
|
||||||
|
|
||||||
.pure-checkbox input[type="checkbox"]:checked + label::before, .pure-radiobutton input[type="checkbox"]:checked + label::before {
|
.pure-checkbox input[type="checkbox"]:checked + label::before, .pure-radiobutton input[type="checkbox"]:checked + label::before {
|
||||||
animation: borderscale 200ms ease-in;
|
animation: borderscale 200ms ease-in;
|
||||||
background: var(--primary-color);
|
background: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pure-radiobutton input[type="checkbox"]:checked + label::after { transform: rotate(-45deg) scale(1); }
|
.pure-radiobutton input[type="checkbox"]:checked + label::after { transform: rotate(-45deg) scale(1); }
|
||||||
|
|
||||||
@keyframes
|
@keyframes
|
||||||
borderscale { 50% {
|
borderscale { 50% {
|
||||||
box-shadow: 0 0 0 2px var(--primary-color);
|
box-shadow: 0 0 0 2px var(--primary-text-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.radioTitle {
|
.radioTitle {
|
||||||
margin-block-end: -20px;
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (width <= 680px) {
|
||||||
|
.pure-checkbox input[type="checkbox"] + label, .pure-radiobutton input[type="checkbox"] + label, .pure-checkbox input[type="radio"] + label, .pure-radiobutton input[type="radio"] + label {
|
||||||
|
margin-block-start: 3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ export default defineComponent({
|
||||||
disabled: {
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
initialValueIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['change'],
|
emits: ['change'],
|
||||||
|
@ -35,7 +39,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.id = this._uid
|
this.id = this._uid
|
||||||
this.selectedValue = this.values[0]
|
this.selectedValue = this.values[this.initialValueIndex]
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateSelectedValue: function (value) {
|
updateSelectedValue: function (value) {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
v-model="selectedValue"
|
v-model="selectedValue"
|
||||||
:name="inputName"
|
:name="inputName"
|
||||||
:value="values[index]"
|
:value="values[index]"
|
||||||
:checked="index === 0"
|
:checked="index === initialValueIndex"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
class="radio"
|
class="radio"
|
||||||
type="radio"
|
type="radio"
|
||||||
|
|
|
@ -1,17 +1,7 @@
|
||||||
.searchFilterInner {
|
|
||||||
max-inline-size: 800px;
|
|
||||||
margin-inline: auto;
|
|
||||||
padding-block: 20px 70px;
|
|
||||||
padding-inline: 20px;
|
|
||||||
max-block-size: 410px;
|
|
||||||
overflow-y: auto;
|
|
||||||
background-color: var(--card-bg-color);
|
|
||||||
box-shadow: 0 1px 2px rgb(0 0 0 / 10%);
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.center {
|
.center {
|
||||||
|
margin-block: 5px 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchRadio {
|
.searchRadio {
|
||||||
|
@ -19,13 +9,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.radioFlexBox {
|
.radioFlexBox {
|
||||||
max-inline-size: 1000px;
|
|
||||||
margin-block: 0;
|
margin-block: 0;
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (width <= 600px) {
|
.searchFilterCloseButtonContainer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (width <= 680px) {
|
||||||
.searchRadio {
|
.searchRadio {
|
||||||
border-inline-end: 0;
|
border-inline-end: 0;
|
||||||
|
padding-block-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radioFlexBox {
|
||||||
|
flex-flow: column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
import { mapActions } from 'vuex'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
import FtRadioButton from '../ft-radio-button/ft-radio-button.vue'
|
import FtRadioButton from '../ft-radio-button/ft-radio-button.vue'
|
||||||
|
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
||||||
|
import FtButton from '../ft-button/ft-button.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'FtSearchFilters',
|
name: 'FtSearchFilters',
|
||||||
components: {
|
components: {
|
||||||
'ft-flex-box': FtFlexBox,
|
'ft-flex-box': FtFlexBox,
|
||||||
'ft-radio-button': FtRadioButton
|
'ft-radio-button': FtRadioButton,
|
||||||
|
'ft-prompt': FtPrompt,
|
||||||
|
'ft-button': FtButton
|
||||||
},
|
},
|
||||||
emits: ['filterValueUpdated'],
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
searchSortByStartIndex: 0,
|
||||||
|
searchTimeStartIndex: 0,
|
||||||
|
searchTypeStartIndex: 0,
|
||||||
|
searchDurationStartIndex: 0,
|
||||||
sortByValues: [
|
sortByValues: [
|
||||||
'relevance',
|
'relevance',
|
||||||
'rating',
|
'rating',
|
||||||
|
@ -41,11 +49,15 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
title: function () {
|
||||||
|
return this.$t('Search Filters.Search Filters')
|
||||||
|
},
|
||||||
|
|
||||||
searchSettings: function () {
|
searchSettings: function () {
|
||||||
return this.$store.getters.getSearchSettings
|
return this.$store.getters.getSearchSettings
|
||||||
},
|
},
|
||||||
|
|
||||||
filterValueChanged: function() {
|
searchFilterValueChanged: function() {
|
||||||
return [
|
return [
|
||||||
this.$refs.sortByRadio.selectedValue !== this.sortByValues[0],
|
this.$refs.sortByRadio.selectedValue !== this.sortByValues[0],
|
||||||
this.$refs.timeRadio.selectedValue !== this.timeValues[0],
|
this.$refs.timeRadio.selectedValue !== this.timeValues[0],
|
||||||
|
@ -93,6 +105,12 @@ export default defineComponent({
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
created: function () {
|
||||||
|
this.searchSortByStartIndex = this.sortByValues.indexOf(this.searchSettings.sortBy)
|
||||||
|
this.searchTimeStartIndex = this.timeValues.indexOf(this.searchSettings.time)
|
||||||
|
this.searchTypeStartIndex = this.typeValues.indexOf(this.searchSettings.type)
|
||||||
|
this.searchDurationStartIndex = this.durationValues.indexOf(this.searchSettings.duration)
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isVideoOrMovieOrAll(type) {
|
isVideoOrMovieOrAll(type) {
|
||||||
return type === 'video' || type === 'movie' || type === 'all'
|
return type === 'video' || type === 'movie' || type === 'all'
|
||||||
|
@ -100,7 +118,7 @@ export default defineComponent({
|
||||||
|
|
||||||
updateSortBy: function (value) {
|
updateSortBy: function (value) {
|
||||||
this.$store.commit('setSearchSortBy', value)
|
this.$store.commit('setSearchSortBy', value)
|
||||||
this.$emit('filterValueUpdated', this.filterValueChanged)
|
this.$store.commit('setSearchFilterValueChanged', this.searchFilterValueChanged)
|
||||||
},
|
},
|
||||||
|
|
||||||
updateTime: function (value) {
|
updateTime: function (value) {
|
||||||
|
@ -110,7 +128,7 @@ export default defineComponent({
|
||||||
this.$store.commit('setSearchType', 'all')
|
this.$store.commit('setSearchType', 'all')
|
||||||
}
|
}
|
||||||
this.$store.commit('setSearchTime', value)
|
this.$store.commit('setSearchTime', value)
|
||||||
this.$emit('filterValueUpdated', this.filterValueChanged)
|
this.$store.commit('setSearchFilterValueChanged', this.searchFilterValueChanged)
|
||||||
},
|
},
|
||||||
|
|
||||||
updateType: function (value) {
|
updateType: function (value) {
|
||||||
|
@ -126,7 +144,7 @@ export default defineComponent({
|
||||||
this.$store.commit('setSearchSortBy', this.sortByValues[0])
|
this.$store.commit('setSearchSortBy', this.sortByValues[0])
|
||||||
}
|
}
|
||||||
this.$store.commit('setSearchType', value)
|
this.$store.commit('setSearchType', value)
|
||||||
this.$emit('filterValueUpdated', this.filterValueChanged)
|
this.$store.commit('setSearchFilterValueChanged', this.searchFilterValueChanged)
|
||||||
},
|
},
|
||||||
|
|
||||||
updateDuration: function (value) {
|
updateDuration: function (value) {
|
||||||
|
@ -136,7 +154,11 @@ export default defineComponent({
|
||||||
this.updateType('all')
|
this.updateType('all')
|
||||||
}
|
}
|
||||||
this.$store.commit('setSearchDuration', value)
|
this.$store.commit('setSearchDuration', value)
|
||||||
this.$emit('filterValueUpdated', this.filterValueChanged)
|
this.$store.commit('setSearchFilterValueChanged', this.searchFilterValueChanged)
|
||||||
}
|
},
|
||||||
|
|
||||||
|
...mapActions([
|
||||||
|
'hideSearchFilters'
|
||||||
|
])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<ft-prompt
|
||||||
<div class="searchFilterInner">
|
theme="slim"
|
||||||
<h2 class="center">
|
:label="title"
|
||||||
{{ $t("Search Filters.Search Filters") }}
|
@click="hideSearchFilters"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h2
|
||||||
|
class="center"
|
||||||
|
name="title"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
</h2>
|
</h2>
|
||||||
<ft-flex-box class="radioFlexBox">
|
<ft-flex-box class="radioFlexBox">
|
||||||
<ft-radio-button
|
<ft-radio-button
|
||||||
|
@ -10,6 +17,7 @@
|
||||||
:title="$t('Search Filters.Sort By.Sort By')"
|
:title="$t('Search Filters.Sort By.Sort By')"
|
||||||
:labels="sortByLabels"
|
:labels="sortByLabels"
|
||||||
:values="sortByValues"
|
:values="sortByValues"
|
||||||
|
:initial-value-index="searchSortByStartIndex"
|
||||||
class="searchRadio"
|
class="searchRadio"
|
||||||
@change="updateSortBy"
|
@change="updateSortBy"
|
||||||
/>
|
/>
|
||||||
|
@ -18,6 +26,7 @@
|
||||||
:title="$t('Search Filters.Time.Time')"
|
:title="$t('Search Filters.Time.Time')"
|
||||||
:labels="timeLabels"
|
:labels="timeLabels"
|
||||||
:values="timeValues"
|
:values="timeValues"
|
||||||
|
:initial-value-index="searchTimeStartIndex"
|
||||||
class="searchRadio"
|
class="searchRadio"
|
||||||
@change="updateTime"
|
@change="updateTime"
|
||||||
/>
|
/>
|
||||||
|
@ -26,6 +35,7 @@
|
||||||
:title="$t('Search Filters.Type.Type')"
|
:title="$t('Search Filters.Type.Type')"
|
||||||
:labels="typeLabels"
|
:labels="typeLabels"
|
||||||
:values="typeValues"
|
:values="typeValues"
|
||||||
|
:initial-value-index="searchTypeStartIndex"
|
||||||
class="searchRadio"
|
class="searchRadio"
|
||||||
@change="updateType"
|
@change="updateType"
|
||||||
/>
|
/>
|
||||||
|
@ -34,12 +44,21 @@
|
||||||
:title="$t('Search Filters.Duration.Duration')"
|
:title="$t('Search Filters.Duration.Duration')"
|
||||||
:labels="durationLabels"
|
:labels="durationLabels"
|
||||||
:values="durationValues"
|
:values="durationValues"
|
||||||
|
:initial-value-index="searchDurationStartIndex"
|
||||||
class="searchRadio"
|
class="searchRadio"
|
||||||
@change="updateDuration"
|
@change="updateDuration"
|
||||||
/>
|
/>
|
||||||
</ft-flex-box>
|
</ft-flex-box>
|
||||||
|
<div class="searchFilterCloseButtonContainer">
|
||||||
|
<ft-button
|
||||||
|
:label="$t('Close')"
|
||||||
|
background-color="var(--primary-color)"
|
||||||
|
text-color="var(--text-with-main-color)"
|
||||||
|
@click="hideSearchFilters"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ft-prompt>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./ft-search-filters.js" />
|
<script src="./ft-search-filters.js" />
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import { mapActions } from 'vuex'
|
import { mapActions } from 'vuex'
|
||||||
import FtInput from '../ft-input/ft-input.vue'
|
import FtInput from '../ft-input/ft-input.vue'
|
||||||
import FtSearchFilters from '../ft-search-filters/ft-search-filters.vue'
|
|
||||||
import FtProfileSelector from '../ft-profile-selector/ft-profile-selector.vue'
|
import FtProfileSelector from '../ft-profile-selector/ft-profile-selector.vue'
|
||||||
import TopNavEvents from './top-nav-events'
|
import TopNavEvents from './top-nav-events'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
@ -16,15 +15,12 @@ export default defineComponent({
|
||||||
name: 'TopNav',
|
name: 'TopNav',
|
||||||
components: {
|
components: {
|
||||||
FtInput,
|
FtInput,
|
||||||
FtSearchFilters,
|
|
||||||
FtProfileSelector
|
FtProfileSelector
|
||||||
},
|
},
|
||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
component: this,
|
component: this,
|
||||||
showSearchContainer: true,
|
showSearchContainer: true,
|
||||||
showFilters: false,
|
|
||||||
searchFilterValueChanged: false,
|
|
||||||
historyIndex: 1,
|
historyIndex: 1,
|
||||||
isForwardOrBack: false,
|
isForwardOrBack: false,
|
||||||
isArrowBackwardDisabled: true,
|
isArrowBackwardDisabled: true,
|
||||||
|
@ -85,6 +81,10 @@ export default defineComponent({
|
||||||
return this.$store.getters.getExpandSideBar
|
return this.$store.getters.getExpandSideBar
|
||||||
},
|
},
|
||||||
|
|
||||||
|
searchFilterValueChanged: function () {
|
||||||
|
return this.$store.getters.getSearchFilterValueChanged
|
||||||
|
},
|
||||||
|
|
||||||
forwardText: function () {
|
forwardText: function () {
|
||||||
return this.$t('Forward')
|
return this.$t('Forward')
|
||||||
},
|
},
|
||||||
|
@ -222,9 +222,6 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Close the filter panel
|
|
||||||
this.showFilters = false
|
|
||||||
},
|
},
|
||||||
|
|
||||||
focusSearch: function () {
|
focusSearch: function () {
|
||||||
|
@ -301,11 +298,6 @@ export default defineComponent({
|
||||||
|
|
||||||
toggleSearchContainer: function () {
|
toggleSearchContainer: function () {
|
||||||
this.showSearchContainer = !this.showSearchContainer
|
this.showSearchContainer = !this.showSearchContainer
|
||||||
this.showFilters = false
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSearchFilterValueChanged: function (filterValueChanged) {
|
|
||||||
this.searchFilterValueChanged = filterValueChanged
|
|
||||||
},
|
},
|
||||||
|
|
||||||
navigateHistory: function () {
|
navigateHistory: function () {
|
||||||
|
@ -360,14 +352,12 @@ export default defineComponent({
|
||||||
navigate: function (route) {
|
navigate: function (route) {
|
||||||
this.$router.push('/' + route)
|
this.$router.push('/' + route)
|
||||||
},
|
},
|
||||||
hideFilters: function () {
|
|
||||||
this.showFilters = false
|
|
||||||
},
|
|
||||||
updateSearchInputText: function ({ detail: { query } }) {
|
updateSearchInputText: function ({ detail: { query } }) {
|
||||||
this.$refs.searchInput.updateInputData(query)
|
this.$refs.searchInput.updateInputData(query)
|
||||||
},
|
},
|
||||||
...mapActions([
|
...mapActions([
|
||||||
'getYoutubeUrlInfo',
|
'getYoutubeUrlInfo',
|
||||||
|
'showSearchFilters'
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -89,15 +89,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.navFilterIcon {
|
.navFilterIcon {
|
||||||
$effect-distance: 10px;
|
$effect-distance: 20px;
|
||||||
|
|
||||||
margin-inline-start: $effect-distance;
|
margin-inline-start: $effect-distance;
|
||||||
|
|
||||||
&.filterChanged {
|
&.filterChanged {
|
||||||
box-shadow: 0 0 $effect-distance var(--primary-color);
|
box-shadow: 0 0 $effect-distance var(--primary-color);
|
||||||
|
color: var(--primary-color);
|
||||||
|
|
||||||
@include top-nav-is-colored {
|
@include top-nav-is-colored {
|
||||||
box-shadow: 0 0 $effect-distance var(--text-with-main-color);
|
box-shadow: 0 0 $effect-distance var(--text-with-main-color);
|
||||||
|
color: var(--text-with-main-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,18 +211,4 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchFilters {
|
|
||||||
inset-inline: 0;
|
|
||||||
margin-block: 10px 20px;
|
|
||||||
margin-inline: 220px 20px;
|
|
||||||
position: absolute;
|
|
||||||
transition: margin 150ms ease-in-out;
|
|
||||||
|
|
||||||
@media only screen and (width <= 680px) {
|
|
||||||
inset-inline: 0;
|
|
||||||
margin-block: 95px 0;
|
|
||||||
margin-inline: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,18 +94,13 @@
|
||||||
class="navFilterIcon navIcon"
|
class="navFilterIcon navIcon"
|
||||||
:class="{ filterChanged: searchFilterValueChanged }"
|
:class="{ filterChanged: searchFilterValueChanged }"
|
||||||
:icon="['fas', 'filter']"
|
:icon="['fas', 'filter']"
|
||||||
|
:title="$t('Search Filters.Search Filters')"
|
||||||
role="button"
|
role="button"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click="showFilters = !showFilters"
|
@click="showSearchFilters"
|
||||||
@keydown.enter.prevent="showFilters = !showFilters"
|
@keydown.enter.prevent="showSearchFilters"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ft-search-filters
|
|
||||||
v-if="!hideSearchBar"
|
|
||||||
v-show="showFilters"
|
|
||||||
class="searchFilters"
|
|
||||||
@filterValueUpdated="handleSearchFilterValueChanged"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<ft-profile-selector class="side profiles" />
|
<ft-profile-selector class="side profiles" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -146,7 +146,7 @@ function parseInvidiousCommentData(response) {
|
||||||
return response.comments.map((comment) => {
|
return response.comments.map((comment) => {
|
||||||
comment.showReplies = false
|
comment.showReplies = false
|
||||||
comment.authorLink = comment.authorId
|
comment.authorLink = comment.authorId
|
||||||
comment.authorThumb = youtubeImageUrlToInvidious(comment.authorThumbnails[1].url)
|
comment.authorThumb = youtubeImageUrlToInvidious(comment.authorThumbnails.at(-1).url)
|
||||||
comment.likes = comment.likeCount
|
comment.likes = comment.likeCount
|
||||||
comment.text = autolinker.link(stripHTML(invidiousImageUrlToInvidious(comment.contentHtml, getCurrentInstance())))
|
comment.text = autolinker.link(stripHTML(invidiousImageUrlToInvidious(comment.contentHtml, getCurrentInstance())))
|
||||||
comment.dataType = 'invidious'
|
comment.dataType = 'invidious'
|
||||||
|
|
|
@ -95,6 +95,7 @@ import {
|
||||||
faMonero
|
faMonero
|
||||||
} from '@fortawesome/free-brands-svg-icons'
|
} from '@fortawesome/free-brands-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||||
|
import PortalVue from 'portal-vue'
|
||||||
|
|
||||||
Vue.config.devtools = process.env.NODE_ENV === 'development'
|
Vue.config.devtools = process.env.NODE_ENV === 'development'
|
||||||
Vue.config.performance = process.env.NODE_ENV === 'development'
|
Vue.config.performance = process.env.NODE_ENV === 'development'
|
||||||
|
@ -201,6 +202,7 @@ new Vue({
|
||||||
i18n,
|
i18n,
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
})
|
})
|
||||||
|
Vue.use(PortalVue)
|
||||||
|
|
||||||
// to avoid accessing electron api from web app build
|
// to avoid accessing electron api from web app build
|
||||||
if (process.env.IS_ELECTRON) {
|
if (process.env.IS_ELECTRON) {
|
||||||
|
|
|
@ -16,14 +16,26 @@ const getters = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
async fetchInvidiousInstancesFromFile({ commit }) {
|
||||||
|
const url = createWebURL('/static/invidious-instances.json')
|
||||||
|
|
||||||
|
const fileData = await (await fetch(url)).json()
|
||||||
|
const instances = fileData.filter(e => {
|
||||||
|
return process.env.SUPPORTS_LOCAL_API || e.cors
|
||||||
|
}).map(e => {
|
||||||
|
return e.url
|
||||||
|
})
|
||||||
|
|
||||||
|
commit('setInvidiousInstancesList', instances)
|
||||||
|
},
|
||||||
|
|
||||||
|
/// fetch invidious instances from site and overwrite static file.
|
||||||
async fetchInvidiousInstances({ commit }) {
|
async fetchInvidiousInstances({ commit }) {
|
||||||
const requestUrl = 'https://api.invidious.io/instances.json'
|
const requestUrl = 'https://api.invidious.io/instances.json'
|
||||||
|
|
||||||
let instances = []
|
|
||||||
try {
|
try {
|
||||||
const response = await fetchWithTimeout(15_000, requestUrl)
|
const response = await fetchWithTimeout(15_000, requestUrl)
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
instances = json.filter((instance) => {
|
const instances = json.filter((instance) => {
|
||||||
return !(instance[0].includes('.onion') ||
|
return !(instance[0].includes('.onion') ||
|
||||||
instance[0].includes('.i2p') ||
|
instance[0].includes('.i2p') ||
|
||||||
!instance[1].api ||
|
!instance[1].api ||
|
||||||
|
@ -31,6 +43,12 @@ const actions = {
|
||||||
}).map((instance) => {
|
}).map((instance) => {
|
||||||
return instance[1].uri.replace(/\/$/, '')
|
return instance[1].uri.replace(/\/$/, '')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (instances.length !== 0) {
|
||||||
|
commit('setInvidiousInstancesList', instances)
|
||||||
|
} else {
|
||||||
|
console.warn('using static file for invidious instances')
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.name === 'TimeoutError') {
|
if (err.name === 'TimeoutError') {
|
||||||
console.error('Fetching the Invidious instance list timed out after 15 seconds. Falling back to local copy.')
|
console.error('Fetching the Invidious instance list timed out after 15 seconds. Falling back to local copy.')
|
||||||
|
@ -38,20 +56,6 @@ const actions = {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the invidious instance fetch isn't returning anything interpretable
|
|
||||||
if (instances.length === 0) {
|
|
||||||
console.warn('reading static file for invidious instances')
|
|
||||||
const url = createWebURL('/static/invidious-instances.json')
|
|
||||||
|
|
||||||
const fileData = await (await fetch(url)).json()
|
|
||||||
instances = fileData.filter(e => {
|
|
||||||
return process.env.SUPPORTS_LOCAL_API || e.cors
|
|
||||||
}).map(e => {
|
|
||||||
return e.url
|
|
||||||
})
|
|
||||||
}
|
|
||||||
commit('setInvidiousInstancesList', instances)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setRandomCurrentInvidiousInstance({ commit, state }) {
|
setRandomCurrentInvidiousInstance({ commit, state }) {
|
||||||
|
|
|
@ -33,6 +33,8 @@ const state = {
|
||||||
showProgressBar: false,
|
showProgressBar: false,
|
||||||
showAddToPlaylistPrompt: false,
|
showAddToPlaylistPrompt: false,
|
||||||
showCreatePlaylistPrompt: false,
|
showCreatePlaylistPrompt: false,
|
||||||
|
showSearchFilters: false,
|
||||||
|
searchFilterValueChanged: false,
|
||||||
progressBarPercentage: 0,
|
progressBarPercentage: 0,
|
||||||
toBeAddedToPlaylistVideoList: [],
|
toBeAddedToPlaylistVideoList: [],
|
||||||
newPlaylistDefaultProperties: {},
|
newPlaylistDefaultProperties: {},
|
||||||
|
@ -94,6 +96,10 @@ const getters = {
|
||||||
return state.searchSettings
|
return state.searchSettings
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSearchFilterValueChanged () {
|
||||||
|
return state.searchFilterValueChanged
|
||||||
|
},
|
||||||
|
|
||||||
getShowAddToPlaylistPrompt () {
|
getShowAddToPlaylistPrompt () {
|
||||||
return state.showAddToPlaylistPrompt
|
return state.showAddToPlaylistPrompt
|
||||||
},
|
},
|
||||||
|
@ -102,6 +108,10 @@ const getters = {
|
||||||
return state.showCreatePlaylistPrompt
|
return state.showCreatePlaylistPrompt
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getShowSearchFilters () {
|
||||||
|
return state.showSearchFilters
|
||||||
|
},
|
||||||
|
|
||||||
getToBeAddedToPlaylistVideoList () {
|
getToBeAddedToPlaylistVideoList () {
|
||||||
return state.toBeAddedToPlaylistVideoList
|
return state.toBeAddedToPlaylistVideoList
|
||||||
},
|
},
|
||||||
|
@ -168,7 +178,7 @@ const getters = {
|
||||||
|
|
||||||
getLastVideoRefreshTimestampByProfile: (state) => (profileId) => {
|
getLastVideoRefreshTimestampByProfile: (state) => (profileId) => {
|
||||||
return state.lastVideoRefreshTimestampByProfile[profileId]
|
return state.lastVideoRefreshTimestampByProfile[profileId]
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
@ -378,6 +388,14 @@ const actions = {
|
||||||
commit('setShowCreatePlaylistPrompt', false)
|
commit('setShowCreatePlaylistPrompt', false)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showSearchFilters ({ commit }) {
|
||||||
|
commit('setShowSearchFilters', true)
|
||||||
|
},
|
||||||
|
|
||||||
|
hideSearchFilters ({ commit }) {
|
||||||
|
commit('setShowSearchFilters', false)
|
||||||
|
},
|
||||||
|
|
||||||
updateShowProgressBar ({ commit }, value) {
|
updateShowProgressBar ({ commit }, value) {
|
||||||
commit('setShowProgressBar', value)
|
commit('setShowProgressBar', value)
|
||||||
},
|
},
|
||||||
|
@ -839,6 +857,10 @@ const mutations = {
|
||||||
state.showCreatePlaylistPrompt = payload
|
state.showCreatePlaylistPrompt = payload
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setShowSearchFilters (state, payload) {
|
||||||
|
state.showSearchFilters = payload
|
||||||
|
},
|
||||||
|
|
||||||
setToBeAddedToPlaylistVideoList (state, payload) {
|
setToBeAddedToPlaylistVideoList (state, payload) {
|
||||||
state.toBeAddedToPlaylistVideoList = payload
|
state.toBeAddedToPlaylistVideoList = payload
|
||||||
},
|
},
|
||||||
|
@ -899,6 +921,10 @@ const mutations = {
|
||||||
state.cachedPlaylist = value
|
state.cachedPlaylist = value
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setSearchFilterValueChanged (state, value) {
|
||||||
|
state.searchFilterValueChanged = value
|
||||||
|
},
|
||||||
|
|
||||||
setSearchSortBy (state, value) {
|
setSearchSortBy (state, value) {
|
||||||
state.searchSettings.sortBy = value
|
state.searchSettings.sortBy = value
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,19 +23,24 @@ export default defineComponent({
|
||||||
'general-settings': GeneralSettings,
|
'general-settings': GeneralSettings,
|
||||||
'theme-settings': ThemeSettings,
|
'theme-settings': ThemeSettings,
|
||||||
'player-settings': PlayerSettings,
|
'player-settings': PlayerSettings,
|
||||||
'external-player-settings': ExternalPlayerSettings,
|
|
||||||
'subscription-settings': SubscriptionSettings,
|
'subscription-settings': SubscriptionSettings,
|
||||||
'privacy-settings': PrivacySettings,
|
'privacy-settings': PrivacySettings,
|
||||||
'data-settings': DataSettings,
|
'data-settings': DataSettings,
|
||||||
'distraction-settings': DistractionSettings,
|
'distraction-settings': DistractionSettings,
|
||||||
'proxy-settings': ProxySettings,
|
|
||||||
'sponsor-block-settings': SponsorBlockSettings,
|
'sponsor-block-settings': SponsorBlockSettings,
|
||||||
'download-settings': DownloadSettings,
|
|
||||||
'parental-control-settings': ParentControlSettings,
|
'parental-control-settings': ParentControlSettings,
|
||||||
'experimental-settings': ExperimentalSettings,
|
|
||||||
'password-settings': PasswordSettings,
|
'password-settings': PasswordSettings,
|
||||||
'password-dialog': PasswordDialog,
|
'password-dialog': PasswordDialog,
|
||||||
'ft-toggle-switch': FtToggleSwitch
|
'ft-toggle-switch': FtToggleSwitch,
|
||||||
|
|
||||||
|
...(process.env.IS_ELECTRON
|
||||||
|
? {
|
||||||
|
'proxy-settings': ProxySettings,
|
||||||
|
'download-settings': DownloadSettings,
|
||||||
|
'external-player-settings': ExternalPlayerSettings,
|
||||||
|
'experimental-settings': ExperimentalSettings
|
||||||
|
}
|
||||||
|
: {})
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
@ -53,11 +58,14 @@ export default defineComponent({
|
||||||
type: 'player-settings',
|
type: 'player-settings',
|
||||||
title: this.$t('Settings.Player Settings.Player Settings')
|
title: this.$t('Settings.Player Settings.Player Settings')
|
||||||
},
|
},
|
||||||
{
|
...(process.env.IS_ELECTRON
|
||||||
type: 'external-player-settings',
|
? [
|
||||||
title: this.$t('Settings.External Player Settings.External Player Settings'),
|
{
|
||||||
usingElectron: true
|
type: 'external-player-settings',
|
||||||
},
|
title: this.$t('Settings.External Player Settings.External Player Settings')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
type: 'subscription-settings',
|
type: 'subscription-settings',
|
||||||
title: this.$t('Settings.Subscription Settings.Subscription Settings')
|
title: this.$t('Settings.Subscription Settings.Subscription Settings')
|
||||||
|
@ -74,16 +82,18 @@ export default defineComponent({
|
||||||
type: 'data-settings',
|
type: 'data-settings',
|
||||||
title: this.$t('Settings.Data Settings.Data Settings')
|
title: this.$t('Settings.Data Settings.Data Settings')
|
||||||
},
|
},
|
||||||
{
|
...(process.env.IS_ELECTRON
|
||||||
type: 'proxy-settings',
|
? [
|
||||||
title: this.$t('Settings.Proxy Settings.Proxy Settings'),
|
{
|
||||||
usingElectron: true
|
type: 'proxy-settings',
|
||||||
},
|
title: this.$t('Settings.Proxy Settings.Proxy Settings')
|
||||||
{
|
},
|
||||||
type: 'download-settings',
|
{
|
||||||
title: this.$t('Settings.Download Settings.Download Settings'),
|
type: 'download-settings',
|
||||||
usingElectron: true
|
title: this.$t('Settings.Download Settings.Download Settings')
|
||||||
},
|
}
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
type: 'parental-control-settings',
|
type: 'parental-control-settings',
|
||||||
title: this.$t('Settings.Parental Control Settings.Parental Control Settings')
|
title: this.$t('Settings.Parental Control Settings.Parental Control Settings')
|
||||||
|
@ -92,11 +102,14 @@ export default defineComponent({
|
||||||
type: 'sponsor-block-settings',
|
type: 'sponsor-block-settings',
|
||||||
title: this.$t('Settings.SponsorBlock Settings.SponsorBlock Settings'),
|
title: this.$t('Settings.SponsorBlock Settings.SponsorBlock Settings'),
|
||||||
},
|
},
|
||||||
{
|
...(process.env.IS_ELECTRON
|
||||||
type: 'experimental-settings',
|
? [
|
||||||
title: this.$t('Settings.Experimental Settings.Experimental Settings'),
|
{
|
||||||
usingElectron: true
|
type: 'experimental-settings',
|
||||||
},
|
title: this.$t('Settings.Experimental Settings.Experimental Settings')
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
type: 'password-settings',
|
type: 'password-settings',
|
||||||
title: this.$t('Settings.Password Settings.Password Settings')
|
title: this.$t('Settings.Password Settings.Password Settings')
|
||||||
|
@ -122,20 +135,13 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
settingsSectionComponents: function () {
|
settingsSectionComponents: function () {
|
||||||
let settingsSections
|
|
||||||
if (!process.env.IS_ELECTRON) {
|
|
||||||
settingsSections = this.settingsComponentsData.filter((settingsComponent) => !settingsComponent.usingElectron)
|
|
||||||
} else {
|
|
||||||
settingsSections = this.settingsComponentsData
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.settingsSectionSortEnabled) {
|
if (this.settingsSectionSortEnabled) {
|
||||||
return settingsSections.toSorted((a, b) =>
|
return this.settingsComponentsData.toSorted((a, b) =>
|
||||||
a.title.toLowerCase().localeCompare(b.title.toLowerCase(), this.locale)
|
a.title.toLowerCase().localeCompare(b.title.toLowerCase(), this.locale)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return settingsSections
|
return this.settingsComponentsData
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created: function () {
|
created: function () {
|
||||||
|
|
|
@ -23,10 +23,6 @@
|
||||||
"url": "https://inv.tux.pizza",
|
"url": "https://inv.tux.pizza",
|
||||||
"cors": true
|
"cors": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"url": "https://invidious.flokinet.to",
|
|
||||||
"cors": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"url": "https://invidious.privacydev.net",
|
"url": "https://invidious.privacydev.net",
|
||||||
"cors": true
|
"cors": true
|
||||||
|
@ -40,11 +36,11 @@
|
||||||
"cors": true
|
"cors": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://invidious.protokolla.fi",
|
"url": "https://iv.nboeck.de",
|
||||||
"cors": true
|
"cors": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://iv.nboeck.de",
|
"url": "https://invidious.protokolla.fi",
|
||||||
"cors": true
|
"cors": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -56,11 +52,7 @@
|
||||||
"cors": true
|
"cors": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://inv.n8pjl.ca",
|
"url": "https://inv.us.projectsegfau.lt",
|
||||||
"cors": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://iv.datura.network",
|
|
||||||
"cors": true
|
"cors": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -87,6 +79,10 @@
|
||||||
"url": "https://vid.lilay.dev",
|
"url": "https://vid.lilay.dev",
|
||||||
"cors": true
|
"cors": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "https://iv.datura.network",
|
||||||
|
"cors": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "https://yt.drgnz.club",
|
"url": "https://yt.drgnz.club",
|
||||||
"cors": true
|
"cors": true
|
||||||
|
|
|
@ -653,6 +653,7 @@ Settings:
|
||||||
zu verhindern
|
zu verhindern
|
||||||
Set Password: Passwort festlegen
|
Set Password: Passwort festlegen
|
||||||
Expand All Settings Sections: Alle Einstellungsabschnitte aufklappen
|
Expand All Settings Sections: Alle Einstellungsabschnitte aufklappen
|
||||||
|
Sort Settings Sections (A-Z): Einstellungsbereiche sortieren (A-Z)
|
||||||
About:
|
About:
|
||||||
#On About page
|
#On About page
|
||||||
About: Über
|
About: Über
|
||||||
|
@ -1258,3 +1259,4 @@ checkmark: ✓
|
||||||
Moments Ago: vor wenigen Augenblicken
|
Moments Ago: vor wenigen Augenblicken
|
||||||
Feed:
|
Feed:
|
||||||
Refresh Feed: '{subscriptionName} auffrischen'
|
Refresh Feed: '{subscriptionName} auffrischen'
|
||||||
|
Feed Last Updated: '{feedName} Feed zuletzt aktualisiert: {date}'
|
||||||
|
|
|
@ -6681,6 +6681,11 @@ pluralize@^8.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
|
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
|
||||||
integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
|
integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
|
||||||
|
|
||||||
|
portal-vue@^2.1.7:
|
||||||
|
version "2.1.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.7.tgz#ea08069b25b640ca08a5b86f67c612f15f4e4ad4"
|
||||||
|
integrity sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g==
|
||||||
|
|
||||||
postcss-calc@^9.0.1:
|
postcss-calc@^9.0.1:
|
||||||
version "9.0.1"
|
version "9.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-9.0.1.tgz#a744fd592438a93d6de0f1434c572670361eb6c6"
|
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-9.0.1.tgz#a744fd592438a93d6de0f1434c572670361eb6c6"
|
||||||
|
|
Loading…
Reference in New Issue