refactor: move popover to separate button
This commit is contained in:
parent
044bad41e1
commit
d37cc6120a
3 changed files with 117 additions and 98 deletions
|
|
@ -98,32 +98,36 @@
|
|||
</label>
|
||||
</td>
|
||||
<td class="is-text-overflow is-vcentered">
|
||||
<div class="is-inline is-pulled-right"
|
||||
v-if="item.extras?.duration || getPath(config.app.download_path, item)">
|
||||
<div class="is-inline is-pulled-right" v-if="item.extras?.duration || show_popover">
|
||||
<span class="tag is-info is-unselectable" v-if="item.extras?.duration">
|
||||
{{ formatTime(item.extras.duration) }}
|
||||
</span>
|
||||
<span class="icon is-pointer" v-if="getPath(config.app.download_path, item)"
|
||||
v-tooltip="`Path: ${getPath(config.app.download_path, item)}`">
|
||||
<i class="fa-solid fa-folder-open" />
|
||||
</span>
|
||||
|
||||
<Popover :showDelay="400" :maxWidth="450" v-if="show_popover">
|
||||
<template #trigger>
|
||||
<span class="icon is-pointer"><i class="fa-solid fa-info-circle" /></span>
|
||||
</template>
|
||||
<template #title>
|
||||
<strong>
|
||||
{{ item.title }}
|
||||
<span class="tag is-info is-unselectable">{{ item.preset }}</span>
|
||||
</strong>
|
||||
</template>
|
||||
<p v-if="getPath(config.app.download_path, item)">
|
||||
<b>Path:</b> {{ getPath(config.app.download_path, item) }}
|
||||
</p>
|
||||
<hr
|
||||
v-if="(showThumbnails && getImage(config.app.download_path, item, false)) || item.description" />
|
||||
<img v-if="showThumbnails && getImage(config.app.download_path, item, false)"
|
||||
:src="getImage(config.app.download_path, item, false)" class="card-image mt-2 mb-2" />
|
||||
<p v-if="item.description">{{ item.description }}</p>
|
||||
</Popover>
|
||||
</div>
|
||||
<div v-if="show_popover">
|
||||
<div class="is-text-overflow">
|
||||
<Popover :showDelay="400" :maxWidth="450">
|
||||
<template #trigger>
|
||||
<NuxtLink class="is-text-overflow" target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</template>
|
||||
<template #title>
|
||||
<strong>
|
||||
{{ item.title }}
|
||||
<span class="tag is-info is-unselectable">{{ item.preset }}</span>
|
||||
</strong>
|
||||
</template>
|
||||
<img v-if="showThumbnails && getImage(config.app.download_path, item, false)"
|
||||
:src="getImage(config.app.download_path, item, false)" class="mt-2 mb-2" />
|
||||
<p v-if="item.description">{{ item.description }}</p>
|
||||
</Popover>
|
||||
<NuxtLink class="is-text-overflow" v-tooltip="`${item.preset}: ${item.title}`" target="_blank"
|
||||
:href="item.url">
|
||||
{{ item.title }}</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
|
@ -241,16 +245,7 @@
|
|||
:class="{ 'is-bordered-danger': item.status === 'error', 'is-bordered-info': item.live_in || item.is_live }">
|
||||
<header class="card-header">
|
||||
<div class="card-header-title is-text-overflow is-block">
|
||||
<Popover :showDelay="400" :maxWidth="550" v-if="show_popover">
|
||||
<template #trigger>
|
||||
<NuxtLink class="is-text-overflow" target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</template>
|
||||
<template #title><strong>{{ item.title }}</strong></template>
|
||||
<p v-if="item.description">{{ item.description }}</p>
|
||||
</Popover>
|
||||
<template v-else>
|
||||
<NuxtLink target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</template>
|
||||
<NuxtLink target="_blank" v-tooltip="item.title" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div class="card-header-icon">
|
||||
|
|
@ -261,10 +256,20 @@
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<div class="control" v-if="getPath(config.app.download_path, item)">
|
||||
<span class="icon" v-tooltip="`Path: ${getPath(config.app.download_path, item)}`">
|
||||
<i class="fa-solid fa-folder-open" />
|
||||
</span>
|
||||
<div class="control" v-if="show_popover && getPath(config.app.download_path, item)">
|
||||
<Popover :showDelay="400" :maxWidth="550" v-if="show_popover">
|
||||
<template #trigger>
|
||||
<span class="icon"><i class="fa-solid fa-info-circle" /></span>
|
||||
</template>
|
||||
<template #title><strong>{{ item.title }}</strong></template>
|
||||
<p v-if="getPath(config.app.download_path, item)">
|
||||
<b>Path:</b> {{ getPath(config.app.download_path, item) }}
|
||||
</p>
|
||||
<template v-if="item.description">
|
||||
<hr>
|
||||
<p>{{ item.description }}</p>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<div class="control">
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@
|
|||
<div v-if="isOpen" class="popover-portal" ref="portal">
|
||||
<div ref="popover" class="popover-card box" :class="placementClass" role="tooltip" :style="portalStyle"
|
||||
@mouseenter="handleHoverEnter" @mouseleave="handleHoverLeave">
|
||||
<button type="button" class="button is-bold is-fullwidth is-hidden-tablet" @click="closePopover">
|
||||
<span class="icon"><i class="fas fa-times" /></span>
|
||||
<span>Close</span>
|
||||
</button>
|
||||
|
||||
<header v-if="hasTitleContent" class="popover-title mb-2">
|
||||
<slot name="title">
|
||||
<p class="title is-6 mb-1">{{ title }}</p>
|
||||
|
|
@ -206,23 +211,47 @@ const updatePosition = () => {
|
|||
const triggerRect = triggerRef.value.getBoundingClientRect()
|
||||
const popoverRect = popover.value.getBoundingClientRect()
|
||||
const offset = props.offset
|
||||
const viewportWidth = window.innerWidth
|
||||
const viewportHeight = window.innerHeight
|
||||
|
||||
let effectivePlacement = props.placement
|
||||
|
||||
if ('top' === props.placement) {
|
||||
const spaceAbove = triggerRect.top - offset
|
||||
if (spaceAbove < popoverRect.height) {
|
||||
effectivePlacement = 'bottom'
|
||||
}
|
||||
} else if ('bottom' === props.placement) {
|
||||
const spaceBelow = viewportHeight - triggerRect.bottom - offset
|
||||
if (spaceBelow < popoverRect.height) {
|
||||
effectivePlacement = 'top'
|
||||
}
|
||||
} else if ('left' === props.placement) {
|
||||
const spaceLeft = triggerRect.left - offset
|
||||
if (spaceLeft < popoverRect.width) {
|
||||
effectivePlacement = 'right'
|
||||
}
|
||||
} else if ('right' === props.placement) {
|
||||
const spaceRight = viewportWidth - triggerRect.right - offset
|
||||
if (spaceRight < popoverRect.width) {
|
||||
effectivePlacement = 'left'
|
||||
}
|
||||
}
|
||||
|
||||
let top = triggerRect.bottom + offset
|
||||
let left = triggerRect.left + (triggerRect.width - popoverRect.width) / 2
|
||||
|
||||
if ('top' == props.placement) {
|
||||
if ('top' === effectivePlacement) {
|
||||
top = triggerRect.top - popoverRect.height - offset
|
||||
} else if ('left' == props.placement) {
|
||||
} else if ('left' === effectivePlacement) {
|
||||
top = triggerRect.top + (triggerRect.height - popoverRect.height) / 2
|
||||
left = triggerRect.left - popoverRect.width - offset
|
||||
} else if ('right' == props.placement) {
|
||||
} else if ('right' === effectivePlacement) {
|
||||
top = triggerRect.top + (triggerRect.height - popoverRect.height) / 2
|
||||
left = triggerRect.right + offset
|
||||
}
|
||||
|
||||
const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max)
|
||||
const viewportWidth = window.innerWidth
|
||||
const viewportHeight = window.innerHeight
|
||||
const maxLeft = viewportWidth - popoverRect.width - 8
|
||||
const maxTop = viewportHeight - popoverRect.height - 8
|
||||
|
||||
|
|
@ -284,7 +313,7 @@ onBeforeUnmount(() => {
|
|||
min-width: 0;
|
||||
}
|
||||
|
||||
.popover-trigger > * {
|
||||
.popover-trigger>* {
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,39 +68,34 @@
|
|||
</label>
|
||||
</td>
|
||||
<td class="is-text-overflow is-vcentered">
|
||||
<div class="is-inline is-pulled-right" v-if="item.downloaded_bytes || item.extras?.duration">
|
||||
<div class="is-inline is-pulled-right" v-if="item.downloaded_bytes || show_popover">
|
||||
<span class="tag" v-if="item.downloaded_bytes">{{ formatBytes(item.downloaded_bytes) }}</span>
|
||||
<span class="tag is-info" v-if="item.extras?.duration">
|
||||
{{ formatTime(item.extras.duration) }}
|
||||
</span>
|
||||
<span class="icon is-pointer" v-if="item.download_dir"
|
||||
v-tooltip="`Path: ${getPath(config.app.download_path, item)}`">
|
||||
<i class="fa-solid fa-folder-open" />
|
||||
</span>
|
||||
<Popover :showDelay="400" :maxWidth="450" v-if="show_popover">
|
||||
<template #trigger>
|
||||
<span class="icon is-pointer"><i class="fa-solid fa-info-circle" /></span>
|
||||
</template>
|
||||
<template #title>
|
||||
<strong>
|
||||
{{ item.title }}
|
||||
<span class="tag is-info is-unselectable">{{ item.preset }}</span>
|
||||
</strong>
|
||||
</template>
|
||||
<p v-if="item.extras?.duration">
|
||||
<b>Duration</b>: {{ formatTime(item.extras.duration) }}
|
||||
</p>
|
||||
<p v-if="getPath(config.app.download_path, item)">
|
||||
<b>Path:</b> {{ getPath(config.app.download_path, item) }}
|
||||
</p>
|
||||
<hr
|
||||
v-if="(showThumbnails && getImage(config.app.download_path, item, false)) || item.description" />
|
||||
<img v-if="showThumbnails && getImage(config.app.download_path, item, false)"
|
||||
:src="getImage(config.app.download_path, item, false)" class="card-image mt-2 mb-2" />
|
||||
<p v-if="item.description">{{ item.description }}</p>
|
||||
</Popover>
|
||||
</div>
|
||||
<div v-if="show_popover">
|
||||
<div class="is-text-overflow">
|
||||
<Popover :showDelay="400" :maxWidth="450">
|
||||
<template #trigger>
|
||||
<NuxtLink class="is-text-overflow" target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</template>
|
||||
<template #title>
|
||||
<strong>
|
||||
{{ item.title }}
|
||||
<span class="tag is-info is-unselectable">{{ item.preset }}</span>
|
||||
</strong>
|
||||
</template>
|
||||
<img v-if="showThumbnails && getImage(config.app.download_path, item)"
|
||||
:src="getImage(config.app.download_path, item)" class="mt-2 mb-2" />
|
||||
<p v-if="item.description">{{ item.description }}</p>
|
||||
</Popover>
|
||||
</div>
|
||||
<div class="is-text-overflow" v-tooltip="`[${item.preset}] - ${item.title}`">
|
||||
<NuxtLink target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="is-text-overflow" v-tooltip="`[${item.preset}] - ${item.title}`">
|
||||
<NuxtLink target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</div>
|
||||
</template>
|
||||
</td>
|
||||
<td class="has-text-centered is-text-overflow is-unselectable">
|
||||
<span class="icon" :class="setIconColor(item)">
|
||||
|
|
@ -176,16 +171,7 @@
|
|||
<div class="card">
|
||||
<header class="card-header">
|
||||
<div class="card-header-title is-text-overflow is-block">
|
||||
<Popover :showDelay="400" :maxWidth="550" v-if="show_popover">
|
||||
<template #trigger>
|
||||
<NuxtLink class="is-text-overflow" target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</template>
|
||||
<template #title><strong>{{ item.title }}</strong></template>
|
||||
<p v-if="item.description">{{ item.description }}</p>
|
||||
</Popover>
|
||||
<template v-else>
|
||||
<NuxtLink target="_blank" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</template>
|
||||
<NuxtLink target="_blank" v-tooltip="item.title" :href="item.url">{{ item.title }}</NuxtLink>
|
||||
</div>
|
||||
<div class="card-header-icon">
|
||||
<div class="field is-grouped">
|
||||
|
|
@ -194,11 +180,22 @@
|
|||
{{ formatTime(item.extras.duration) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="control" v-if="item.download_dir">
|
||||
<span class="icon" v-tooltip="`Path: ${getPath(config.app.download_path, item)}`">
|
||||
<i class="fa-solid fa-folder-open" />
|
||||
</span>
|
||||
</div>
|
||||
<Popover :showDelay="400" :maxWidth="450" v-if="show_popover">
|
||||
<template #trigger>
|
||||
<span class="icon is-pointer"><i class="fa-solid fa-info-circle" /></span>
|
||||
</template>
|
||||
<template #title>
|
||||
<strong>
|
||||
{{ item.title }}
|
||||
<span class="tag is-info is-unselectable">{{ item.preset }}</span>
|
||||
</strong>
|
||||
</template>
|
||||
<p v-if="getPath(config.app.download_path, item)">
|
||||
<b>Path:</b> {{ getPath(config.app.download_path, item) }}
|
||||
</p>
|
||||
<hr v-if="item.description" />
|
||||
<p v-if="item.description">{{ item.description }}</p>
|
||||
</Popover>
|
||||
<div class="control">
|
||||
<button @click="hideThumbnail = !hideThumbnail" v-if="thumbnails">
|
||||
<span class="icon"><i class="fa-solid"
|
||||
|
|
@ -252,8 +249,7 @@
|
|||
<span v-tooltip="moment(item.datetime).format('MMMM Do YYYY, h:mm:ss a')" :data-datetime="item.datetime"
|
||||
v-rtime="item.datetime" />
|
||||
</div>
|
||||
<div class="column is-half-mobile has-text-centered is-text-overflow is-unselectable"
|
||||
v-if="item.downloaded_bytes" v-tooltip="`Saving to: ${makePath(item)}`">
|
||||
<div class="column is-half-mobile has-text-centered is-unselectable" v-if="item.downloaded_bytes">
|
||||
{{ formatBytes(item.downloaded_bytes) }}
|
||||
</div>
|
||||
|
||||
|
|
@ -632,15 +628,4 @@ watch(embed_url, v => {
|
|||
}
|
||||
document.querySelector('body')?.setAttribute('style', `opacity: ${v ? 1 : bg_opacity.value}`)
|
||||
})
|
||||
|
||||
const makePath = (item: StoreItem) => {
|
||||
const parts = [
|
||||
eTrim(item.download_dir, '/').replace(config.app.download_path, ''),
|
||||
]
|
||||
if (item?.filename) {
|
||||
parts.push(eTrim(item.filename, '/'))
|
||||
}
|
||||
|
||||
return '/' + sTrim(parts.filter(p => !!p).map(p => p.replace(/\\/g, '/').replace(/\/+/g, '/')).join('/'), '/')
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in a new issue