Merge pull request #233 from arabcoders/dev

Design update
This commit is contained in:
Abdulmohsen 2025-03-26 22:12:28 +03:00 committed by GitHub
commit 6d77de76cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 258 additions and 46 deletions

View file

@ -130,7 +130,6 @@ hr {
}
.progress-bar {
border-radius: 15px;
position: relative;
width: 100%;
height: 30px;
@ -164,6 +163,10 @@ hr {
color: #fff;
}
.progress,
.progress-percentage {
border-radius: unset !important;
}
@media (prefers-color-scheme: dark) {
.footer {

View file

@ -10,7 +10,7 @@
<div v-if="showCompleted">
<div class="columns is-multiline is-mobile has-text-centered" v-if="hasItems">
<div class="column is-half-mobile">
<div class="column is-half-mobile" v-if="display_style === 'cards'">
<button type="button" class="button is-fullwidth is-ghost is-inverted"
@click="masterSelectAll = !masterSelectAll">
<span class="icon-text is-block">
@ -74,7 +74,122 @@
</div>
</div>
<div class="columns is-multiline">
<div class="columns is-multiline" v-if="'list' === display_style">
<div class="column is-12" v-if="hasItems">
<div class="table-container">
<table class="table is-striped is-hoverable is-fullwidth is-bordered" style="table-layout: fixed;">
<thead>
<tr class="has-text-centered is-unselectable">
<th width="5%">
<a href="#" @click.prevent="masterSelectAll = !masterSelectAll">
<span class="icon-text is-block">
<span class="icon">
<i class="fa-regular"
:class="{ 'fa-square-check': !masterSelectAll, 'fa-square': masterSelectAll }" />
</span>
</span>
</a>
</th>
<th width="40%">Video Title</th>
<th width="15%">Status</th>
<th width="15%">Created</th>
<th width="10%">Size/Starts</th>
<th width="20%">Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="item in sortCompleted" :key="item._id">
<td class="is-vcentered has-text-centered">
<label class="checkbox is-block">
<input class="completed-checkbox" type="checkbox" v-model="selectedElms"
:id="'checkbox-' + item._id" :value="item._id">
</label>
</td>
<td class="is-vcentered">
<div class="is-text-overflow" v-tooltip="item.title">
<NuxtLink target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
</div>
<div v-if="item.error">
<span class="has-text-danger">{{ item.error }}</span>
</div>
<div v-if="showMessage(item)">
<span class="has-text-danger">{{ item.msg }}</span>
</div>
</td>
<td class="is-vcentered has-text-centered is-unselectable">
<span class="icon-text">
<span class="icon" :class="setIconColor(item)"><i :class="setIcon(item)" /></span>
<span>{{ setStatus(item) }}</span>
</span>
</td>
<td class="is-vcentered has-text-centered is-unselectable">
<span class="user-hint" :date-datetime="item.datetime"
v-tooltip="moment(item.datetime).format('YYYY-M-DD H:mm Z')">
{{ moment(item.datetime).fromNow() }}
</span>
</td>
<td class="is-vcentered has-text-centered is-unselectable"
v-if="item.live_in && 'not_live' === item.status">
<span :date-datetime="item.live_in" class="user-hint"
v-tooltip="'Starts at: ' + moment(item.live_in).format('YYYY-M-DD H:mm Z')">
{{ moment(item.live_in).fromNow() }}
</span>
</td>
<td class="is-vcentered has-text-centered is-unselectable" v-else>
{{ item.file_size ? formatBytes(item.file_size) : '-' }}
</td>
<td class="is-vcentered is-items-center">
<div class="field is-grouped is-grouped-centered">
<div class="control" v-if="'finished' === item.status || isEmbedable(item.url)">
<button v-if="'finished' === item.status" @click="playVideo(item)" v-tooltip="'Play video'"
class="button is-danger is-light is-small">
<span class="icon"><i class="fa-solid fa-play" /></span>
</button>
<button v-else @click="embed_url = getEmbedable(item.url)" v-tooltip="'Play video'"
class="button is-danger is-light is-small">
<span class="icon"><i class="fa-solid fa-play" /></span>
</button>
</div>
<div class="control" v-if="item.status != 'finished'">
<button class="button is-warning is-fullwidth is-small" v-tooltip="'Re-queue video'"
@click="reQueueItem(item)">
<span class="icon"><i class="fa-solid fa-rotate-right" /></span>
</button>
</div>
<div class="control" v-if="config.app?.keep_archive && item.status != 'finished'">
<button class="button is-danger is-light is-fullwidth is-small" v-tooltip="'Add link to archive'"
@click="archiveItem(item)">
<span class="icon"><i class="fa-solid fa-box-archive" /></span>
</button>
</div>
<div class="control" v-if="item.filename && item.status === 'finished'">
<a class="button is-link is-fullwidth is-small" :href="makeDownload(config, item)"
v-tooltip="'Download video'" :download="item.filename?.split('/').reverse()[0]">
<span class="icon"><i class="fa-solid fa-download" /></span>
</a>
</div>
<div class="control" v-if="item.url && !config.app.basic_mode">
<button class="button is-info is-fullwidth is-small" @click="emitter('getInfo', item.url)"
v-tooltip="'Show video information'">
<span class="icon"><i class="fa-solid fa-info" /></span>
</button>
</div>
<div class="control">
<button class="button is-danger is-fullwidth is-small" @click="removeItem(item)"
v-tooltip="'Remove video'">
<span class="icon"><i class="fa-solid fa-trash-can" /></span>
</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="columns is-multiline" v-else>
<LateLoader :unrender="true" :min-height="hideThumbnail ? 210 : 410" class="column is-6"
v-for="item in sortCompleted" :key="item._id">
<div class="card"
@ -166,7 +281,7 @@
</div>
<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 item.'" @click="reQueueItem(item)">
<a class="button is-warning is-fullwidth" @click="reQueueItem(item)">
<span class="icon-text is-block">
<span class="icon"><i class="fa-solid fa-rotate-right" /></span>
<span>Re-queue</span>
@ -182,8 +297,7 @@
</a>
</div>
<div class="column is-half-mobile" v-if="config.app?.keep_archive && item.status != 'finished'">
<a class="button is-danger is-light is-fullwidth" v-tooltip="'Add link to archive.'"
@click="archiveItem(item)">
<a class="button is-danger is-light is-fullwidth" @click="archiveItem(item)">
<span class="icon-text is-block">
<span class="icon"><i class="fa-solid fa-box-archive" /></span>
<span>Archive</span>
@ -268,6 +382,7 @@ const masterSelectAll = ref(false)
const showCompleted = useStorage('showCompleted', true)
const hideThumbnail = useStorage('hideThumbnailHistory', false)
const direction = useStorage('sortCompleted', 'desc')
const display_style = useStorage('display_style', 'cards')
const embed_url = ref('')
const video_item = ref(null)
@ -439,11 +554,11 @@ const setStatus = item => {
}
if ('cancelled' === item.status) {
return 'User Cancelled'
return display_style.value === 'cards' ? 'User Cancelled' : 'Cancelled'
}
if ('not_live' === item.status) {
return 'Live Stream'
return display_style.value === 'cards' ? 'Live Stream' : 'Live'
}
return item.status

View file

@ -10,7 +10,7 @@
<div v-if="showQueue">
<div class="columns is-multiline is-mobile has-text-centered" v-if="hasQueuedItems">
<div class="column is-half-mobile">
<div class="column is-half-mobile" v-if="'cards' === display_style">
<button type="button" class="button is-fullwidth is-ghost" @click="masterSelectAll = !masterSelectAll">
<span class="icon-text is-block">
<span class="icon">
@ -21,7 +21,7 @@
</span>
</button>
</div>
<div class="column is-half-mobile">
<div class="column is-half-mobile" v-if="('cards' === display_style || hasSelected)">
<button type="button" class="button is-fullwidth is-danger" :disabled="!hasSelected" @click="cancelSelected">
<span class="icon-text is-block">
<span class="icon">
@ -33,7 +33,90 @@
</div>
</div>
<div class="columns is-multiline">
<div class="columns is-multiline" v-if="'list' === display_style">
<div class="column is-12" v-if="hasQueuedItems">
<div class="table-container">
<table class="table is-striped is-hoverable is-fullwidth is-bordered" style="table-layout: fixed;">
<thead>
<tr class="has-text-centered is-unselectable">
<th width="5%">
<a href="#" @click.prevent="masterSelectAll = !masterSelectAll">
<span class="icon-text is-block">
<span class="icon">
<i class="fa-regular"
:class="{ 'fa-square-check': !masterSelectAll, 'fa-square': masterSelectAll }" />
</span>
</span>
</a>
</th>
<th width="40%">Video Title</th>
<th width="15%">Status</th>
<th width="20%">Progress</th>
<th width="15%">Created</th>
<th width="10%">Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="item in stateStore.queue" :key="item._id">
<td class="has-text-centered is-vcentered">
<label class="checkbox is-block">
<input class="completed-checkbox" type="checkbox" v-model="selectedElms"
:id="'checkbox-' + item._id" :value="item._id">
</label>
</td>
<td class="is-text-overflow is-vcentered" v-tooltip="item.title">
<NuxtLink target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
</td>
<td class="has-text-centered is-text-overflow is-unselectable">
<span class="icon-text">
<span class="icon" :class="setIconColor(item)">
<i class="fas fa-solid" :class="setIcon(item)" />
</span>
<span v-text="setStatus(item)" />
</span>
</td>
<td>
<div class="progress-bar is-unselectable">
<div class="progress-percentage">{{ updateProgress(item) }}</div>
<div class="progress" :style="{ width: percentPipe(item.percent) + '%' }"></div>
</div>
</td>
<td class="has-text-centered is-text-overflow is-unselectable">
<span :data-datetime="item.datetime"
v-tooltip="moment(item.datetime).format('MMMM Do YYYY, h:mm:ss a')">
{{ moment(item.datetime).fromNow() }}
</span>
</td>
<td class="is-vcentered is-items-center">
<div class="field is-grouped is-grouped-centered">
<div class="control" v-if="isEmbedable(item.url)">
<button @click="() => embed_url = getEmbedable(item.url)" v-tooltip="'Play video'"
class="button is-danger is-light is-small">
<span class="icon"><i class="fa-solid fa-play" /></span>
</button>
</div>
<div class="control">
<button class="button is-warning is-small" @click="confirmCancel(item);"
v-tooltip="'Cancel download'">
<span class="icon"><i class="fa-solid fa-eject" /></span>
</button>
</div>
<div class="control" v-if="item.url && !config.app.basic_mode">
<button class="button is-info is-small" @click="emitter('getInfo', item.url)"
v-tooltip="'Show video information'">
<span class="icon"><i class="fa-solid fa-info" /></span>
</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="columns is-multiline" v-else>
<LateLoader :unrender="true" :min-height="hideThumbnail ? 265 : 475" class="column is-6"
v-for="item in stateStore.queue" :key="item._id">
<div class="card">
@ -69,13 +152,13 @@
<div class="card-content">
<div class="columns is-multiline is-mobile">
<div class="column is-12">
<div class="progress-bar is-round">
<div class="progress-bar is-unselectable">
<div class="progress-percentage">{{ updateProgress(item) }}</div>
<div class="progress" :style="{ width: percentPipe(item.percent) + '%' }"></div>
</div>
</div>
<div class="column is-half-mobile has-text-centered is-text-overflow">
<span class="icon-text">
<span class="icon-text is-unselectable">
<span class="icon" :class="setIconColor(item)">
<i class="fas fa-solid" :class="setIcon(item)" />
</span>
@ -98,11 +181,9 @@
</div>
<div class="columns is-multiline is-mobile">
<div class="column is-half-mobile">
<button class="button is-danger is-fullwidth" @click="confirmCancel(item);">
<button class="button is-warning is-fullwidth" @click="confirmCancel(item);">
<span class="icon-text is-block">
<span class="icon">
<i class="fa-solid fa-trash-can" />
</span>
<span class="icon"><i class="fa-solid fa-eject" /></span>
<span>Cancel</span>
</span>
</button>
@ -152,7 +233,7 @@
<script setup>
import moment from 'moment'
import { set, useStorage } from '@vueuse/core'
import { useStorage } from '@vueuse/core'
import { ucFirst } from '~/utils/index'
import { isEmbedable, getEmbedable } from '~/utils/embedable'
@ -165,6 +246,8 @@ const selectedElms = ref([]);
const masterSelectAll = ref(false);
const showQueue = useStorage('showQueue', true)
const hideThumbnail = useStorage('hideThumbnailQueue', false)
const display_style = useStorage('display_style', 'cards')
const embed_url = ref('')
const bg_enable = useStorage('random_bg', true)
@ -344,7 +427,7 @@ watch(embed_url, v => {
if (!bg_enable.value) {
return
}
document.querySelector('body').setAttribute("style", `opacity: ${ v ? 1 : bg_opacity.value}`)
document.querySelector('body').setAttribute("style", `opacity: ${v ? 1 : bg_opacity.value}`)
})
</script>

View file

@ -9,13 +9,32 @@
</span>
</header>
<div class="card-content">
<div class="field">
<label class="label" for="random_bg">Color scheme</label>
<div class="control">
<label for="auto" class="radio">
<input id="auto" type="radio" v-model="selectedTheme" value="auto">
System Default
</label>
<label for="light" class="radio">
<input id="light" type="radio" v-model="selectedTheme" value="light">
Light
</label>
<label for="dark" class="radio">
<input id="dark" type="radio" v-model="selectedTheme" value="dark">
Dark
</label>
</div>
<p class="help">Select the color scheme for the WebUI.</p>
</div>
<div class="field">
<label class="label" for="random_bg">Backgrounds</label>
<div class="control">
<input id="random_bg" type="checkbox" class="switch is-success" v-model="bg_enable">
<label for="random_bg" class="is-unselectable">&nbsp;Enable</label>
<p class="help">Use random background image from your media backends.</p>
</div>
<p class="help">Use random background image from your media backends.</p>
</div>
<div class="field">
@ -25,8 +44,8 @@
<div class="control">
<input id="random_bg_opacity" style="width: 100%" type="range" v-model="bg_opacity" min="0.50" max="1.00"
step="0.05">
<p class="help">How visible the background image should be.</p>
</div>
<p class="help">How visible the background image should be.</p>
</div>
<div class="field" v-if="bg_enable">
@ -41,10 +60,9 @@
<span>Reload</span>
</span>
</button>
<p class="help">Change the displayed picture.</p>
</div>
<p class="help">Change the displayed picture.</p>
</div>
</div>
</div>
</div>
@ -65,5 +83,6 @@ defineProps({
const bg_enable = useStorage('random_bg', true)
const bg_opacity = useStorage('random_bg_opacity', 0.85)
const selectedTheme = useStorage('theme', 'auto')
</script>

View file

@ -59,21 +59,6 @@
</NuxtLink>
</div>
<div class="navbar-item">
<button class="button is-dark has-tooltip-bottom" v-tooltip.bottom="'Switch to Light theme'"
v-if="'auto' == selectedTheme" @click="selectTheme('light')">
<span class="icon has-text-warning"><i class="fas fa-sun" /></span>
</button>
<button class="button is-dark has-tooltip-bottom" v-tooltip.bottom="'Switch to Dark theme'"
v-if="'light' == selectedTheme" @click="selectTheme('dark')">
<span class="icon"><i class="fas fa-moon" /></span>
</button>
<button class="button is-dark has-tooltip-bottom" v-tooltip.bottom="'Switch to auto theme'"
v-if="'dark' == selectedTheme" @click="selectTheme('auto')">
<span class="icon"><i class="fas fa-microchip" /></span>
</button>
</div>
<div class="navbar-item is-hidden-mobile">
<button class="button is-dark" @click="reloadPage">
<span class="icon"><i class="fas fa-refresh"></i></span>
@ -191,6 +176,10 @@ watch(() => config.app.sentry_dsn, dsn => {
onMounted(async () => {
try {
await handleImage(bg_enable.value)
} catch (e) {
}
try {
applyPreferredColorScheme(selectedTheme.value)
} catch (e) {
}
@ -204,13 +193,6 @@ watch(selectedTheme, value => {
const reloadPage = () => window.location.reload()
const selectTheme = theme => {
selectedTheme.value = theme
if ('auto' === theme) {
return reloadPage()
}
}
watch(bg_enable, async v => await handleImage(v))
watch(bg_opacity, v => {
if (false === bg_enable.value) {

View file

@ -30,7 +30,6 @@
<div class="is-pulled-right" v-if="socket.isConnected && false === config.app.basic_mode">
<div class="field is-grouped">
<p class="control" v-if="config.app.has_cookies">
<button class="button is-purple" @click="checkCookies" v-tooltip.bottom="'Check youtube cookies status.'"
:disabled="isChecking">
@ -56,6 +55,14 @@
</button>
</p>
<p class="control">
<button v-tooltip.bottom="'Change display style'" class="button has-tooltip-bottom"
@click="() => changeDisplay()">
<span class="icon"><i class="fa-solid"
:class="{ 'fa-table': display_style === 'cards', 'fa-table-list': display_style === 'list' }" /></span>
</button>
</p>
</div>
</div>
<div class="is-hidden-mobile">
@ -86,6 +93,7 @@ const isChecking = ref(false)
const get_info = ref('')
const bg_enable = useStorage('random_bg', true)
const bg_opacity = useStorage('random_bg_opacity', 0.85)
const display_style = useStorage('display_style', 'cards')
onMounted(() => {
if (!config.app.ui_update_title) {
@ -149,4 +157,6 @@ watch(get_info, v => {
document.querySelector('body').setAttribute("style", `opacity: ${v ? 1 : bg_opacity.value}`)
})
const changeDisplay = () => display_style.value = display_style.value === 'cards' ? 'list' : 'cards'
</script>