* Implement divider for video "more dropdown menu" (#1748)
* * Implement divider for video "more dropdown menu" * * Update API for ft-icon-button * * Update existing ft-icon-button user to use new API for dropdown options * * Update ft-icon-button to remove unused old API * * Update divider to be less visible * * Update padding of list item * * Update WebpackDevServer option to avoid app reloading on MacOS .DS_Store file change
This commit is contained in:
parent
a8e517adfa
commit
713738b5ff
|
@ -119,7 +119,10 @@ function startRenderer(callback) {
|
||||||
static: {
|
static: {
|
||||||
directory: path.join(process.cwd(), 'static'),
|
directory: path.join(process.cwd(), 'static'),
|
||||||
watch: {
|
watch: {
|
||||||
ignored: /(dashFiles|storyboards)\/*/
|
ignored: [
|
||||||
|
/(dashFiles|storyboards)\/*/,
|
||||||
|
'/**/.DS_Store',
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
port
|
port
|
||||||
|
|
|
@ -44,11 +44,11 @@ export default Vue.extend({
|
||||||
type: String,
|
type: String,
|
||||||
default: 'bottom'
|
default: 'bottom'
|
||||||
},
|
},
|
||||||
dropdownNames: {
|
dropdownOptions: {
|
||||||
type: Array,
|
// Array of objects with these properties
|
||||||
default: () => { return [] }
|
// - type: ('labelValue'|'divider', default to 'labelValue' for less typing)
|
||||||
},
|
// - label: String (if type == 'labelValue')
|
||||||
dropdownValues: {
|
// - value: String (if type == 'labelValue')
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => { return [] }
|
default: () => { return [] }
|
||||||
}
|
}
|
||||||
|
@ -107,18 +107,18 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
handleIconClick: function () {
|
handleIconClick: function () {
|
||||||
if (this.forceDropdown || (this.dropdownNames.length > 0 && this.dropdownValues.length > 0)) {
|
if (this.forceDropdown || (this.dropdownOptions.length > 0)) {
|
||||||
this.toggleDropdown()
|
this.toggleDropdown()
|
||||||
} else {
|
} else {
|
||||||
this.$emit('click')
|
this.$emit('click')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDropdownClick: function (index) {
|
handleDropdownClick: function ({ url, index }) {
|
||||||
if (this.returnIndex) {
|
if (this.returnIndex) {
|
||||||
this.$emit('click', index)
|
this.$emit('click', index)
|
||||||
} else {
|
} else {
|
||||||
this.$emit('click', this.dropdownValues[index])
|
this.$emit('click', url)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.focusOut()
|
this.focusOut()
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
list-style-type: none
|
list-style-type: none
|
||||||
|
|
||||||
.listItem
|
.listItem
|
||||||
padding: 10px
|
padding: 8px 10px
|
||||||
margin: 0
|
margin: 0
|
||||||
white-space: nowrap
|
white-space: nowrap
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
@ -96,3 +96,11 @@
|
||||||
&:active
|
&:active
|
||||||
background-color: var(--side-nav-active-color)
|
background-color: var(--side-nav-active-color)
|
||||||
transition: background 0.1s ease-in
|
transition: background 0.1s ease-in
|
||||||
|
|
||||||
|
.listItemDivider
|
||||||
|
width: 95%
|
||||||
|
margin: 1px auto
|
||||||
|
border-top: 1px solid var(--tertiary-text-color)
|
||||||
|
// Too "visible" with current color
|
||||||
|
opacity: 50%
|
||||||
|
|
||||||
|
|
|
@ -28,16 +28,16 @@
|
||||||
>
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<ul
|
<ul
|
||||||
v-if="dropdownNames.length > 0"
|
v-if="dropdownOptions.length > 0"
|
||||||
class="list"
|
class="list"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
v-for="(label, index) in dropdownNames"
|
v-for="(option, index) in dropdownOptions"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="listItem"
|
:class="option.type === 'divider' ? 'listItemDivider' : 'listItem'"
|
||||||
@click="handleDropdownClick(index)"
|
@click="handleDropdownClick({url: option.value, index: index})"
|
||||||
>
|
>
|
||||||
{{ label }}
|
{{ option.type === 'divider' ? '' : option.label }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</slot>
|
</slot>
|
||||||
|
|
|
@ -59,20 +59,7 @@ export default Vue.extend({
|
||||||
isFavorited: false,
|
isFavorited: false,
|
||||||
isUpcoming: false,
|
isUpcoming: false,
|
||||||
isPremium: false,
|
isPremium: false,
|
||||||
hideViews: false,
|
hideViews: false
|
||||||
optionsValues: [
|
|
||||||
'history',
|
|
||||||
'openYoutube',
|
|
||||||
'copyYoutube',
|
|
||||||
'openYoutubeEmbed',
|
|
||||||
'copyYoutubeEmbed',
|
|
||||||
'openInvidious',
|
|
||||||
'copyInvidious',
|
|
||||||
'openYoutubeChannel',
|
|
||||||
'copyYoutubeChannel',
|
|
||||||
'openInvidiousChannel',
|
|
||||||
'copyInvidiousChannel'
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -130,27 +117,71 @@ export default Vue.extend({
|
||||||
return (this.watchProgress / this.data.lengthSeconds) * 100
|
return (this.watchProgress / this.data.lengthSeconds) * 100
|
||||||
},
|
},
|
||||||
|
|
||||||
optionsNames: function () {
|
dropdownOptions: function () {
|
||||||
const names = [
|
const options = []
|
||||||
this.$t('Video.Open in YouTube'),
|
|
||||||
this.$t('Video.Copy YouTube Link'),
|
|
||||||
this.$t('Video.Open YouTube Embedded Player'),
|
|
||||||
this.$t('Video.Copy YouTube Embedded Player Link'),
|
|
||||||
this.$t('Video.Open in Invidious'),
|
|
||||||
this.$t('Video.Copy Invidious Link'),
|
|
||||||
this.$t('Video.Open Channel in YouTube'),
|
|
||||||
this.$t('Video.Copy YouTube Channel Link'),
|
|
||||||
this.$t('Video.Open Channel in Invidious'),
|
|
||||||
this.$t('Video.Copy Invidious Channel Link')
|
|
||||||
]
|
|
||||||
|
|
||||||
if (this.watched) {
|
options.push(
|
||||||
names.unshift(this.$t('Video.Remove From History'))
|
{
|
||||||
} else {
|
label: this.watched
|
||||||
names.unshift(this.$t('Video.Mark As Watched'))
|
? this.$t('Video.Remove From History')
|
||||||
}
|
: this.$t('Video.Mark As Watched'),
|
||||||
|
value: 'history'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Copy YouTube Link'),
|
||||||
|
value: 'copyYoutube'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Copy YouTube Embedded Player Link'),
|
||||||
|
value: 'copyYoutubeEmbed'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Copy Invidious Link'),
|
||||||
|
value: 'copyInvidious'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Open in YouTube'),
|
||||||
|
value: 'openYoutube'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Open YouTube Embedded Player'),
|
||||||
|
value: 'openYoutubeEmbed'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Open in Invidious'),
|
||||||
|
value: 'openInvidious'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Copy YouTube Channel Link'),
|
||||||
|
value: 'copyYoutubeChannel'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Copy Invidious Channel Link'),
|
||||||
|
value: 'copyInvidiousChannel'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Open Channel in YouTube'),
|
||||||
|
value: 'openYoutubeChannel'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Video.Open Channel in Invidious'),
|
||||||
|
value: 'openInvidiousChannel'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return names
|
return options
|
||||||
},
|
},
|
||||||
|
|
||||||
thumbnail: function () {
|
thumbnail: function () {
|
||||||
|
|
|
@ -66,13 +66,13 @@
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<ft-icon-button
|
<ft-icon-button
|
||||||
class="optionsButton"
|
class="optionsButton"
|
||||||
|
icon="ellipsis-v"
|
||||||
title="More Options"
|
title="More Options"
|
||||||
theme="base-no-default"
|
theme="base-no-default"
|
||||||
:size="16"
|
:size="16"
|
||||||
:use-shadow="false"
|
:use-shadow="false"
|
||||||
dropdown-position-x="left"
|
dropdown-position-x="left"
|
||||||
:dropdown-names="optionsNames"
|
:dropdown-options="dropdownOptions"
|
||||||
:dropdown-values="optionsValues"
|
|
||||||
@click="handleOptionsClick"
|
@click="handleOptionsClick"
|
||||||
/>
|
/>
|
||||||
<router-link
|
<router-link
|
||||||
|
|
|
@ -118,12 +118,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
formatTypeLabel: 'VIDEO FORMATS',
|
formatTypeLabel: 'VIDEO FORMATS'
|
||||||
formatTypeValues: [
|
|
||||||
'dash',
|
|
||||||
'legacy',
|
|
||||||
'audio'
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -175,23 +170,29 @@ export default Vue.extend({
|
||||||
return this.inFavoritesPlaylist ? 'base favorite' : 'base'
|
return this.inFavoritesPlaylist ? 'base favorite' : 'base'
|
||||||
},
|
},
|
||||||
|
|
||||||
downloadLinkNames: function () {
|
downloadLinkOptions: function () {
|
||||||
return this.downloadLinks.map((download) => {
|
return this.downloadLinks.map((download) => {
|
||||||
return download.label
|
return {
|
||||||
|
label: download.label,
|
||||||
|
value: download.url
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
downloadLinkValues: function () {
|
formatTypeOptions: function () {
|
||||||
return this.downloadLinks.map((download) => {
|
|
||||||
return download.url
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
formatTypeNames: function () {
|
|
||||||
return [
|
return [
|
||||||
this.$t('Change Format.Use Dash Formats').toUpperCase(),
|
{
|
||||||
this.$t('Change Format.Use Legacy Formats').toUpperCase(),
|
label: this.$t('Change Format.Use Dash Formats').toUpperCase(),
|
||||||
this.$t('Change Format.Use Audio Formats').toUpperCase()
|
value: 'dash'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Change Format.Use Legacy Formats').toUpperCase(),
|
||||||
|
value: 'legacy'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Change Format.Use Audio Formats').toUpperCase(),
|
||||||
|
value: 'audio'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -409,8 +410,9 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDownload: function (index) {
|
handleDownload: function (index) {
|
||||||
const url = this.downloadLinkValues[index]
|
const selectedDownloadLinkOption = this.downloadLinkOptions[index]
|
||||||
const linkName = this.downloadLinkNames[index]
|
const url = selectedDownloadLinkOption.value
|
||||||
|
const linkName = selectedDownloadLinkOption.label
|
||||||
const extension = this.grabExtensionFromUrl(linkName)
|
const extension = this.grabExtensionFromUrl(linkName)
|
||||||
|
|
||||||
this.downloadMedia({
|
this.downloadMedia({
|
||||||
|
|
|
@ -100,8 +100,7 @@
|
||||||
theme="secondary"
|
theme="secondary"
|
||||||
icon="download"
|
icon="download"
|
||||||
:return-index="true"
|
:return-index="true"
|
||||||
:dropdown-names="downloadLinkNames"
|
:dropdown-options="downloadLinkOptions"
|
||||||
:dropdown-values="downloadLinkValues"
|
|
||||||
@click="handleDownload"
|
@click="handleDownload"
|
||||||
/>
|
/>
|
||||||
<ft-icon-button
|
<ft-icon-button
|
||||||
|
@ -110,8 +109,7 @@
|
||||||
class="option"
|
class="option"
|
||||||
theme="secondary"
|
theme="secondary"
|
||||||
icon="file-video"
|
icon="file-video"
|
||||||
:dropdown-names="formatTypeNames"
|
:dropdown-options="formatTypeOptions"
|
||||||
:dropdown-values="formatTypeValues"
|
|
||||||
@click="handleFormatChange"
|
@click="handleFormatChange"
|
||||||
/>
|
/>
|
||||||
<ft-share-button
|
<ft-share-button
|
||||||
|
|
Loading…
Reference in New Issue