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