Replaced vue-tooltip with v-tooltip and added confirm to queue cancel button.

This commit is contained in:
ArabCoders 2024-01-09 21:35:55 +03:00
parent 0d51d4d90a
commit c539bcfe04
9 changed files with 154 additions and 71 deletions

View file

@ -15,6 +15,7 @@
"@vueuse/core": "^10.6.1",
"core-js": "^3.8.3",
"cron-parser": "^4.9.0",
"floating-vue": "^5.0.2",
"hls.js": "^1.4.12",
"moment": "^2.29.4",
"plyr": "^3.7.8",
@ -25,7 +26,6 @@
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@creativebulma/bulma-tooltip": "^1.2.0",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-service": "^5.0.8",
@ -1825,12 +1825,6 @@
"node": ">=6.9.0"
}
},
"node_modules/@creativebulma/bulma-tooltip": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@creativebulma/bulma-tooltip/-/bulma-tooltip-1.2.0.tgz",
"integrity": "sha512-ooImbeXEBxf77cttbzA7X5rC5aAWm9UsXIGViFOnsqB+6M944GkB28S5R4UWRqjFd2iW4zGEkEifAU+q43pt2w==",
"dev": true
},
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@ -1887,6 +1881,27 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@floating-ui/core": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz",
"integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==",
"dependencies": {
"@floating-ui/utils": "^0.2.0"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.1.1.tgz",
"integrity": "sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw==",
"dependencies": {
"@floating-ui/core": "^1.1.0"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
},
"node_modules/@fortawesome/fontawesome-common-types": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz",
@ -6389,6 +6404,24 @@
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
"dev": true
},
"node_modules/floating-vue": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/floating-vue/-/floating-vue-5.0.2.tgz",
"integrity": "sha512-CY6emiecyIIvdoK4xYN8mDSNRWutetR+rM10mu6VGrTCqxSdvHyF6TX/zslIgXDC2eIjEkcrpAMg3Mxh724t9w==",
"dependencies": {
"@floating-ui/dom": "~1.1.1",
"vue-resize": "^2.0.0-alpha.1"
},
"peerDependencies": {
"@nuxt/kit": "^3.2.0",
"vue": "^3.2.0"
},
"peerDependenciesMeta": {
"@nuxt/kit": {
"optional": true
}
}
},
"node_modules/follow-redirects": {
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
@ -11237,6 +11270,14 @@
"node": ">=8"
}
},
"node_modules/vue-resize": {
"version": "2.0.0-alpha.1",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
"integrity": "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==",
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vue-style-loader": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",

View file

@ -16,6 +16,7 @@
"@vueuse/core": "^10.6.1",
"core-js": "^3.8.3",
"cron-parser": "^4.9.0",
"floating-vue": "^5.0.2",
"hls.js": "^1.4.12",
"moment": "^2.29.4",
"plyr": "^3.7.8",
@ -26,7 +27,6 @@
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@creativebulma/bulma-tooltip": "^1.2.0",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-service": "^5.0.8",

View file

@ -95,3 +95,7 @@
white-space: nowrap;
}
}
.is-borderless {
border: none;
}

View file

@ -44,7 +44,7 @@
</div>
</div>
<div class="column is-4">
<div class="field has-addons" :data-tooltip="'Download path relative to ' + config.app.download_path">
<div class="field has-addons" v-tooltip="'Download path relative to ' + config.app.download_path">
<div class="control">
<a href="#" class="button is-static">Download Path</a>
</div>
@ -66,7 +66,7 @@
</div>
<div class="column">
<button type="submit" class="button is-info" @click="showAdvanced = !showAdvanced"
data-tooltip="Show advanced options" :class="{ 'is-loading': !config.isConnected }"
v-tooltip="'Show advanced options'" :class="{ 'is-loading': !config.isConnected }"
:disabled="!config.isConnected">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-cog" />
@ -78,7 +78,7 @@
<div class="column is-12">
<div class="field">
<label class="label is-inline" for="output_format"
:data-tooltip="'Default Format: ' + config.app.output_template">
v-tooltip="'Default Format: ' + config.app.output_template">
Output Format
</label>
<div class="control">
@ -94,7 +94,7 @@
<div class="column is-6">
<div class="field">
<label class="label is-inline" for="ytdlpConfig"
data-tooltip="Extends current global yt-dlp config. (JSON)">
v-tooltip="'Extends current global yt-dlp config. (JSON)'">
JSON yt-dlp config
</label>
<div class="control">
@ -111,7 +111,7 @@
</div>
<div class="column is-6">
<div class="field">
<label class="label is-inline" for="ytdlpCookies" data-tooltip="JSON exported cookies for downloading.">
<label class="label is-inline" for="ytdlpCookies" v-tooltip="'JSON exported cookies for downloading.'">
yt-dlp Cookies
</label>
<div class="control">
@ -128,7 +128,7 @@
<div class="field">
<div class="control">
<button type="submit" class="button is-danger" @click="resetConfig" :disabled="!config.isConnected"
data-tooltip="This configuration are stored locally in your browser.">
v-tooltip="'This configuration are stored locally in your browser.'">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-trash" />
</span>

View file

@ -9,11 +9,11 @@
</h1>
<div v-if="showCompleted">
<div class="columns has-text-centered" v-if="hasItems">
<div class="column">
<div class="columns is-multiline is-mobile has-text-centered" v-if="hasItems">
<div class="column is-half-mobile">
<button type="button" class="button is-fullwidth is-ghost is-inverted"
@click="masterSelectAll = !masterSelectAll">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon :icon="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
</span>
@ -22,10 +22,10 @@
</span>
</button>
</div>
<div class="column">
<div class="column is-half-mobile">
<button type="button" class="button is-fullwidth is-danger is-inverted" :disabled="!hasSelected"
@click="$emit('deleteItem', 'completed', selectedElms); selectedElms = []">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-trash-can" />
</span>
@ -33,9 +33,9 @@
</span>
</button>
</div>
<div class="column" v-if="hasCompleted">
<div class="column is-half-mobile" v-if="hasCompleted">
<button type="button" class="button is-fullwidth is-primary is-inverted" @click="clearCompleted">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-circle-check" />
</span>
@ -43,9 +43,9 @@
</span>
</button>
</div>
<div class="column" v-if="hasFailed">
<div class="column is-half-mobile" v-if="hasFailed">
<button type="button" class="button is-fullwidth is-info is-inverted" @click="clearFailed">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-circle-xmark" />
</span>
@ -53,9 +53,9 @@
</span>
</button>
</div>
<div class="column" v-if="hasFailed">
<div class="column is-half-mobile" v-if="hasFailed">
<button type="button" class="button is-fullwidth is-warning is-inverted" @click="requeueFailed">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-rotate-right" />
</span>
@ -63,9 +63,9 @@
</span>
</button>
</div>
<div class="column is-1">
<div class="column is-1-tablet">
<button type="button" class="button is-fullwidth" @click="direction = direction === 'desc' ? 'asc' : 'desc'">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon
:icon="direction === 'desc' ? 'fa-solid fa-arrow-down-a-z' : 'fa-solid fa-arrow-up-a-z'" />
@ -78,7 +78,7 @@
<div class="columns is-multiline">
<div class="column is-6" v-for="item in sortCompleted" :key="item._id">
<div class="card" :class="{ 'is-bordered-danger': hasError(item), 'is-bordered-info': item.live_in }">
<header class="card-header has-tooltip" :data-tooltip="item.title">
<header class="card-header has-tooltip" v-tooltip="item.title">
<div class="card-header-title has-text-centered is-text-overflow is-block">
<a v-if="item.filename" referrerpolicy="no-referrer" :href="makeDownload(config, item, 'm3u8')"
@click.prevent="$emit('playItem', item)">
@ -88,7 +88,7 @@
</div>
</header>
<div class="card-content">
<div class="columns is-multiline">
<div class="columns is-mobile is-multiline">
<div class="column is-12" v-if="item.live_in">
<span class="has-text-info">
LIVE stream is scheduled to start at {{ moment(item.datetime).format() }}
@ -100,7 +100,7 @@
<div class="column is-12" v-if="showMessage(item)">
<span class="has-text-danger">{{ item.msg }}</span>
</div>
<div class="column has-text-centered">
<div class="column is-half-mobile has-text-centered">
<span v-if="!item.live_in">
<span class="icon-text">
<span class="icon"
@ -120,21 +120,21 @@
</span>
</span>
</div>
<div class="column has-text-centered">
<span :date-datetime="item.datetime" :data-tooltip="moment(item.datetime).format('YYYY-M-DD H:mm Z')">
<div class="column is-half-mobile has-text-centered">
<span :date-datetime="item.datetime" v-tooltip="moment(item.datetime).format('YYYY-M-DD H:mm Z')">
{{ moment(item.datetime).fromNow() }}
</span>
</div>
<div class="column has-text-centered" v-if="item.live_in && item.status != 'finished'">
<div class="column is-half-mobile has-text-centered" v-if="item.live_in && item.status != 'finished'">
<span :date-datetime="item.datetime"
:data-tooltip="'Will start at: ' + moment(item.live_in).format('YYYY-M-DD H:mm Z')">
v-tooltip="'Will start at: ' + moment(item.live_in).format('YYYY-M-DD H:mm Z')">
{{ moment(item.live_in).fromNow() }}
</span>
</div>
<div class="column has-text-centered" v-if="item.file_size">
<div class="column is-half-mobile has-text-centered" v-if="item.file_size">
{{ formatBytes(item.file_size) }}
</div>
<div class="column has-text-centered">
<div class="column is-half-mobile has-text-centered">
<label class="checkbox is-block">
<input class="completed-checkbox" type="checkbox" v-model="selectedElms" :id="'checkbox-' + item._id"
:value="item._id">
@ -142,9 +142,9 @@
</label>
</div>
</div>
<div class="columns">
<div class="column" v-if="item.status != 'finished'">
<a class="button is-warning is-fullwidth" data-tooltip="Re-queue failed download."
<div class="columns is-mobile is-multiline">
<div class="column is-half-mobile" v-if="item.status != 'finished'">
<a class="button is-warning is-fullwidth" v-tooltip="'Re-queue failed download.'"
@click="reQueueItem(item)">
<span class="icon-text">
<span class="icon">
@ -154,7 +154,7 @@
</span>
</a>
</div>
<div class="column" v-if="item.filename">
<div class="column is-half-mobile" v-if="item.filename">
<a class="button is-fullwidth is-primary" :href="makeDownload(config, item)"
:download="item.filename?.split('/').reverse()[0]">
<span class="icon-text">
@ -165,7 +165,7 @@
</span>
</a>
</div>
<div class="column">
<div class="column is-half-mobile">
<a class="button is-danger is-fullwidth" @click="$emit('deleteItem', 'completed', item._id)">
<span class="icon-text">
<span class="icon">
@ -175,7 +175,7 @@
</span>
</a>
</div>
<div class="column">
<div class="column is-half-mobile">
<a referrerpolicy="no-referrer" class="button is-link is-fullwidth" target="_blank" :href="item.url">
<span class="icon-text">
<span class="icon">
@ -185,6 +185,15 @@
</span>
</a>
</div>
<div class="column is-1-tablet is-half-mobile">
<button class="button is-fullwidth is-borderless" @click="copyId(item)" v-tooltip="'Copy link ID'">
<span class="icon-text">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-asterisk" />
</span>
</span>
</button>
</div>
</div>
</div>
</div>

View file

@ -9,10 +9,10 @@
</h1>
<div v-if="showQueue">
<div class="columns has-text-centered" v-if="hasQueuedItems">
<div class="column">
<div class="columns is-multiline is-mobile has-text-centered" v-if="hasQueuedItems">
<div class="column is-half-mobile">
<button type="button" class="button is-fullwidth is-ghost" @click="masterSelectAll = !masterSelectAll">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon :icon="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
</span>
@ -21,10 +21,10 @@
</span>
</button>
</div>
<div class="column">
<div class="column is-half-mobile">
<button type="button" class="button is-fullwidth is-danger" :disabled="!hasSelected"
@click="$emit('deleteItem', 'queue', selectedElms); selectedElms = []">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-trash-can" />
</span>
@ -37,20 +37,20 @@
<div class="columns is-multiline">
<div class="column is-6" v-for="item in queue" :key="item._id">
<div class="card">
<header class="card-header has-tooltip" :data-tooltip="item.title">
<header class="card-header has-tooltip" v-tooltip="item.title">
<div class="card-header-title has-text-centered is-text-overflow is-block">
{{ item.title }}
</div>
</header>
<div class="card-content">
<div class="columns is-multiline">
<div class="columns is-multiline is-mobile">
<div class="column is-12">
<div id="progress-bar" class="is-round">
<div id="progress-percentage">{{ updateProgress(item) }}</div>
<div id="progress" :style="{ width: percentPipe(item.percent) + '%' }"></div>
</div>
</div>
<div class="column is-4 has-text-centered">
<div class="column is-half-mobile has-text-centered">
<span class="icon-text">
<span class="icon" :class="{ 'has-text-success': item.status == 'downloading' }">
<font-awesome-icon
@ -59,13 +59,12 @@
<span>{{ capitalize(item.status) }}</span>
</span>
</div>
<div class="column is-4 has-text-centered">
<span :data-datetime="item.datetime"
:data-tooltip="moment(item.datetime).format('MMMM Do YYYY, h:mm:ss a')">
<div class="column is-half-mobile has-text-centered">
<span :data-datetime="item.datetime" v-tooltip="moment(item.datetime).format('MMMM Do YYYY, h:mm:ss a')">
{{ moment(item.datetime).fromNow() }}
</span>
</div>
<div class="column is-4 has-text-centered">
<div class="column is-half-mobile has-text-centered">
<label class="checkbox is-block">
<input class="completed-checkbox" type="checkbox" v-model="selectedElms" :id="'checkbox-' + item._id"
:value="item._id">
@ -73,20 +72,20 @@
</label>
</div>
</div>
<div class="columns">
<div class="column">
<a class="button is-danger is-fullwidth" @click="$emit('deleteItem', 'queue', item._id)">
<span class="icon-text">
<div class="columns is-multiline is-mobile">
<div class="column is-half-mobile">
<button class="button is-danger is-fullwidth" @click="confirmDelete(item);">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-trash-can" />
</span>
<span>Cancel</span>
</span>
</a>
</button>
</div>
<div class="column">
<div class="column is-half-mobile">
<a referrerpolicy="no-referrer" class="button is-link is-fullwidth" target="_blank" :href="item.url">
<span class="icon-text">
<span class="icon-text is-block">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-up-right-from-square" />
</span>
@ -94,6 +93,15 @@
</span>
</a>
</div>
<div class="column is-1-tablet is-half-mobile">
<button class="button is-fullwidth is-borderless" @click="copyId(item)" v-tooltip="'Copy link ID'">
<span class="icon-text">
<span class="icon">
<font-awesome-icon icon="fa-solid fa-asterisk" />
</span>
</span>
</button>
</div>
</div>
</div>
</div>
@ -126,7 +134,7 @@ import { defineProps, defineEmits, ref, watch, computed } from 'vue';
import moment from "moment";
import { useStorage } from '@vueuse/core'
defineEmits(['deleteItem']);
const emit = defineEmits(['deleteItem']);
const props = defineProps({
queue: {
@ -211,4 +219,14 @@ const updateProgress = (item) => {
return string;
}
const confirmDelete = (item) => {
if (!confirm(`Are you sure you want to delete (${item.title})?`)) {
return false;
}
emit('deleteItem', 'queue', item._id);
return true;
}
</script>

View file

@ -2,25 +2,25 @@
<nav class="navbar is-mobile is-dark">
<div class="navbar-brand pl-5">
<a class="navbar-item has-tooltip-bottom" :class="config.isConnected ? 'has-text-success' : 'has-text-danger'"
:data-tooltip="config.isConnected ? 'Connected' : 'Connecting'" href="javascript:void(0);">
v-tooltip="config.isConnected ? 'Connected' : 'Connecting'" href="javascript:void(0);">
<b>YTPTube</b>
</a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<button data-tooltip="Show/Hide Add Form" class="button is-dark has-tooltip-bottom" @click="$emit('toggleForm')">
<button v-tooltip="'Show/Hide Add Form'" class="button is-dark has-tooltip-bottom" @click="$emit('toggleForm')">
<font-awesome-icon icon="fa-solid fa-plus" />
</button>
</div>
<div class="navbar-item" v-if="config.tasks.length > 0">
<button data-tooltip="Show/Hide Tasks" class="button is-dark has-tooltip-bottom" @click="$emit('toggleTasks')">
<button v-tooltip="'Show/Hide Tasks'" class="button is-dark has-tooltip-bottom" @click="$emit('toggleTasks')">
<font-awesome-icon icon="fa-solid fa-tasks" />
</button>
</div>
<div class="navbar-item">
<button data-tooltip="Switch to Light theme" class="button is-dark has-tooltip-bottom"
<button v-tooltip="'Switch to Light theme'" class="button is-dark has-tooltip-bottom"
@click="selectedTheme = 'light'" v-if="selectedTheme == 'dark'">🌞</button>
<button data-tooltip="Switch to Dark theme" class="button is-dark has-tooltip-bottom"
<button v-tooltip="'Switch to Dark theme'" class="button is-dark has-tooltip-bottom"
@click="selectedTheme = 'dark'" v-if="selectedTheme == 'light'">🌚</button>
</div>
</div>

View file

@ -31,7 +31,7 @@
</a>
</td>
<td class="has-text-centered" v-if="item.timer">
<span :data-tooltip="'Timer: ' + item.timer">
<span v-tooltip="'Timer: ' + item.timer">
{{ moment(parseExpression(item.timer).next().toISOString()).fromNow() }}
</span>
</td>

View file

@ -1,11 +1,12 @@
import { createApp } from 'vue'
import App from './App.vue'
import Toast from 'vue-toastification'
import FloatingVue from 'floating-vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import {
faCog, faTrash, faLink, faPlus, faTrashCan, faCircleXmark, faCircleCheck, faRotateRight, faDownload, faUpRightFromSquare,
faSpinner, faArrowUp, faArrowDown, faTasks, faCalendar, faArrowUpAZ, faArrowDownAZ
faSpinner, faArrowUp, faArrowDown, faTasks, faCalendar, faArrowUpAZ, faArrowDownAZ, faAsterisk
} from '@fortawesome/free-solid-svg-icons'
import { faSquare, faSquareCheck } from '@fortawesome/free-regular-svg-icons'
@ -14,13 +15,14 @@ import 'vue-toastification/dist/index.css'
import './assets/css/bulma-light.css'
import './assets/css/bulma-dark.css'
import './assets/css/style.css'
import '@creativebulma/bulma-tooltip/dist/bulma-tooltip.min.css';
import 'floating-vue/dist/style.css'
library.add(faCog, faTrash, faLink, faPlus, faTrashCan, faCircleXmark, faCircleCheck, faRotateRight, faDownload, faUpRightFromSquare,
faSquare, faSquareCheck, faSpinner, faArrowUp, faArrowDown, faTasks, faCalendar, faArrowUpAZ, faArrowDownAZ)
faSquare, faSquareCheck, faSpinner, faArrowUp, faArrowDown, faTasks, faCalendar, faArrowUpAZ, faArrowDownAZ, faAsterisk)
const app = createApp(App);
app.config.globalProperties.capitalize = s => s && s[0].toUpperCase() + s.slice(1);
app.config.globalProperties.copyId = item => navigator.clipboard.writeText(item.id);
app.config.globalProperties.makeDownload = (config, item, base = 'download') => {
let baseDir = `${base}/`;
@ -50,6 +52,15 @@ app.use(Toast, {
newestOnTop: true
});
app.use(FloatingVue, {
themes: {
tooltip: {
placement: 'top',
triggers: ['hover', 'focus', 'touch', 'click'],
}
}
})
app.component('font-awesome-icon', FontAwesomeIcon)
app.mount('#app')