mirror of
https://github.com/TeamPiped/Piped.git
synced 2026-03-29 11:56:58 +00:00
@@ -24,52 +24,52 @@
|
||||
|
||||
<!-- mobile vertical view -->
|
||||
<div
|
||||
v-if="mobileLayout && getPreferenceString('mobileChapterLayout') == 'Vertical'"
|
||||
v-if="mobileLayout && getPreferenceString('mobileChapterLayout', 'Horizontal') == 'Vertical'"
|
||||
class="flex max-h-64 flex-col overflow-y-auto"
|
||||
>
|
||||
<h2 class="mb-2 bg-gray-500/50 p-2" aria-label="chapters" title="chapters">
|
||||
<h2 class="mb-2 bg-gray-500/50 p-2 text-sm font-semibold" aria-label="chapters" title="chapters">
|
||||
{{ $t("video.chapters") }} ({{ chapters.length }})
|
||||
</h2>
|
||||
<div
|
||||
v-for="(chapter, index) in chapters"
|
||||
:key="chapter.start"
|
||||
class="cursor-pointer self-center p-2.5 hover:bg-gray-500"
|
||||
class="flex cursor-pointer items-center gap-2 px-2 py-1.5 hover:bg-gray-500"
|
||||
:class="{ 'bg-red-500/50': isCurrentChapter(index) }"
|
||||
@click="$emit('seek', chapter.start)"
|
||||
>
|
||||
<div class="flex">
|
||||
<span class="mt-5 mr-2 text-current" v-text="index + 1" />
|
||||
<img class="h-[30%] w-[30%] shrink-0" :src="chapter.image" :alt="chapter.title" />
|
||||
<div class="m-2 flex flex-col">
|
||||
<span class="text-sm" :title="chapter.title" v-text="chapter.title" />
|
||||
<span class="text-sm font-bold text-blue-500" v-text="timeFormat(chapter.start)" />
|
||||
</div>
|
||||
<span class="w-5 shrink-0 text-center text-xs" v-text="index + 1" />
|
||||
<img class="h-10 w-16 shrink-0 rounded object-cover" :src="chapter.image" :alt="chapter.title" />
|
||||
<div class="flex min-w-0 flex-col">
|
||||
<span class="truncate text-sm" :title="chapter.title" v-text="chapter.title" />
|
||||
<span class="text-xs font-bold text-blue-500" v-text="timeFormat(chapter.start)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- mobile Horizontal view -->
|
||||
<div v-if="getPreferenceString('mobileChapterLayout') == 'Horizontal' && mobileLayout" class="flex overflow-x-auto">
|
||||
<div
|
||||
v-if="getPreferenceString('mobileChapterLayout', 'Horizontal') == 'Horizontal' && mobileLayout"
|
||||
class="flex gap-2 overflow-x-auto pb-2"
|
||||
>
|
||||
<div
|
||||
v-for="(chapter, index) in chapters"
|
||||
:key="chapter.start"
|
||||
class="cursor-pointer self-center p-2.5"
|
||||
class="w-32 flex-none cursor-pointer rounded p-1"
|
||||
:class="{ 'bg-red-500/50': isCurrentChapter(index) }"
|
||||
@click="$emit('seek', chapter.start)"
|
||||
>
|
||||
<img class="size-full" :src="chapter.image" :alt="chapter.title" />
|
||||
<div class="m-1 flex">
|
||||
<span
|
||||
class="inline-block w-[10em] truncate overflow-hidden text-sm"
|
||||
:title="chapter.title"
|
||||
v-text="chapter.title"
|
||||
/>
|
||||
<span class="px-1 text-sm font-bold text-blue-500" v-text="timeFormat(chapter.start)" />
|
||||
<img class="aspect-video w-full rounded object-cover" :src="chapter.image" :alt="chapter.title" />
|
||||
<div class="mt-1 px-0.5">
|
||||
<span class="line-clamp-2 text-xs leading-tight" :title="chapter.title" v-text="chapter.title" />
|
||||
<span class="text-xs font-bold text-blue-500" v-text="timeFormat(chapter.start)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { timeFormat } from "@/composables/useFormatting.js";
|
||||
import { getPreferenceString } from "@/composables/usePreferences.js";
|
||||
|
||||
const props = defineProps({
|
||||
chapters: {
|
||||
type: Object,
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
@focus="onInputFocus"
|
||||
@blur="onInputBlur"
|
||||
/>
|
||||
<ClearButton v-if="searchText" @clear="searchText = ''" />\n
|
||||
<ClearButton v-if="searchText" @clear="searchText = ''" />
|
||||
</div>
|
||||
<SearchSuggestions
|
||||
v-show="(searchText || showSearchHistory) && suggestionsVisible"
|
||||
|
||||
@@ -17,243 +17,236 @@
|
||||
<i18n-t keypath="info.next_video_countdown">{{ counter }}</i18n-t>
|
||||
</ToastComponent>
|
||||
</Transition>
|
||||
<div class="flex gap-5">
|
||||
<div class="flex-auto">
|
||||
<div v-show="!video.error">
|
||||
<Teleport defer to="#theaterModeSpot" :disabled="!theaterMode">
|
||||
<div class="flex flex-row">
|
||||
<keep-alive>
|
||||
<VideoPlayer
|
||||
ref="videoPlayer"
|
||||
:video="video"
|
||||
:sponsors="sponsors"
|
||||
:selected-auto-play="selectedAutoPlayEnabled"
|
||||
:selected-auto-loop="selectedAutoLoop"
|
||||
@timeupdate="onTimeUpdate"
|
||||
@ended="onVideoEnded"
|
||||
@navigate-next="navigateNext"
|
||||
/>
|
||||
</keep-alive>
|
||||
<button
|
||||
v-if="!isMobile"
|
||||
:class="theaterMode ? '-ml-5' : '-mr-5'"
|
||||
class="z-10 text-white"
|
||||
@click="
|
||||
theaterMode = !theaterMode;
|
||||
setPreference('theaterMode', theaterMode);
|
||||
"
|
||||
>
|
||||
<div>
|
||||
<i-fa6-solid-chevron-left v-if="theaterMode" />
|
||||
<i-fa6-solid-chevron-right v-else />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</Teleport>
|
||||
<div v-if="video && isMobile">
|
||||
<ChaptersBar
|
||||
v-if="video?.chapters?.length > 0 && showChapters"
|
||||
:mobile-layout="isMobile"
|
||||
:chapters="video.chapters"
|
||||
:player-position="currentTime"
|
||||
@seek="navigate"
|
||||
/>
|
||||
<PlaylistVideos
|
||||
v-if="playlist"
|
||||
:playlist-id="playlistId"
|
||||
:playlist="playlist"
|
||||
:selected-index="index"
|
||||
:prefer-listen="isListening"
|
||||
/>
|
||||
</div>
|
||||
<!-- video title -->
|
||||
<div class="mt-2 text-2xl font-bold wrap-break-word" v-text="video.title" />
|
||||
<div class="my-3 flex flex-wrap">
|
||||
<!-- views / date -->
|
||||
<div class="flex flex-auto gap-2">
|
||||
<span v-t="{ path: 'video.views', args: { views: addCommas(video.views) } }" />
|
||||
<span> | </span>
|
||||
<span :title="new Date(video.uploadDate).toLocaleString()" v-text="uploadDate" />
|
||||
</div>
|
||||
<!-- Likes/dilikes -->
|
||||
<div class="flex gap-2">
|
||||
<template v-if="video.likes >= 0">
|
||||
<div class="flex items-center">
|
||||
<i-fa6-solid-thumbs-up />
|
||||
<strong class="ml-1" v-text="addCommas(video.likes)" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<i-fa6-solid-thumbs-down />
|
||||
<strong
|
||||
class="ml-1"
|
||||
v-text="video.dislikes >= 0 ? addCommas(video.dislikes) : '?'"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="video.likes < 0">
|
||||
<div>
|
||||
<strong v-t="'video.ratings_disabled'" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Channel info & options flex container -->
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<!-- Channel Image & Info -->
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
loading="lazy"
|
||||
height="48"
|
||||
width="48"
|
||||
:src="video.uploaderAvatar"
|
||||
alt=""
|
||||
class="rounded-full"
|
||||
<div v-show="!video.error" class="flex gap-5">
|
||||
<div class="min-w-0 flex-auto">
|
||||
<Teleport defer to="#theaterModeSpot" :disabled="!theaterMode">
|
||||
<div class="flex flex-row">
|
||||
<keep-alive>
|
||||
<VideoPlayer
|
||||
ref="videoPlayer"
|
||||
:video="video"
|
||||
:sponsors="sponsors"
|
||||
:selected-auto-play="selectedAutoPlayEnabled"
|
||||
:selected-auto-loop="selectedAutoLoop"
|
||||
@timeupdate="onTimeUpdate"
|
||||
@ended="onVideoEnded"
|
||||
@navigate-next="navigateNext"
|
||||
/>
|
||||
<router-link
|
||||
v-if="video.uploaderUrl"
|
||||
class="ml-1.5 hover:text-red-500 focus:text-red-500 dark:hover:text-red-400 dark:focus:text-red-400"
|
||||
:to="video.uploaderUrl"
|
||||
>{{ video.uploader }}</router-link
|
||||
>
|
||||
<!-- Verified Badge -->
|
||||
<i-fa6-solid-check v-if="video.uploaderVerified" class="ml-1" />
|
||||
</div>
|
||||
<PlaylistAddModal
|
||||
v-if="showModal"
|
||||
:video-id="getVideoId()"
|
||||
:video-info="video"
|
||||
@close="showModal = !showModal"
|
||||
/>
|
||||
<ShareModal
|
||||
v-if="showShareModal"
|
||||
:video-id="getVideoId()"
|
||||
:current-time="currentTime"
|
||||
:playlist-id="playlistId"
|
||||
:playlist-index="index"
|
||||
@close="showShareModal = !showShareModal"
|
||||
/>
|
||||
<div class="ml-auto flex flex-wrap gap-1">
|
||||
<!-- Subscribe Button -->
|
||||
<button
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:hidden max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="downloadCurrentFrame"
|
||||
>
|
||||
{{ $t("actions.download_frame") }}<i-fa6-solid-download class="ml-1" />
|
||||
</button>
|
||||
<button
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showModal = !showModal"
|
||||
>
|
||||
{{ $t("actions.add_to_playlist") }}<i-fa6-solid-circle-plus class="ml-1" />
|
||||
</button>
|
||||
<button
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="subscribeHandler"
|
||||
v-text="
|
||||
$t('actions.' + (subscribed ? 'unsubscribe' : 'subscribe')) +
|
||||
' - ' +
|
||||
numberFormat(video.uploaderSubscriberCount)
|
||||
"
|
||||
/>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<!-- RSS Feed button -->
|
||||
<a
|
||||
v-if="video.uploaderUrl"
|
||||
aria-label="RSS feed"
|
||||
title="RSS feed"
|
||||
role="button"
|
||||
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${
|
||||
video.uploaderUrl.split('/')[2]
|
||||
}`"
|
||||
target="_blank"
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
>
|
||||
<i-fa6-solid-rss class="mx-1.5" />
|
||||
</a>
|
||||
<!-- Share Dialog -->
|
||||
<button
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showShareModal = !showShareModal"
|
||||
>
|
||||
<i18n-t class="max-lg:hidden" keypath="actions.share" tag="strong"></i18n-t>
|
||||
<i-fa6-solid-share class="mx-1.5" />
|
||||
</button>
|
||||
<!-- YouTube -->
|
||||
<WatchOnButton :link="youtubeVideoHref" />
|
||||
<!-- Odysee -->
|
||||
<WatchOnButton
|
||||
v-if="video.lbryId"
|
||||
:link="`https://odysee.com/${video.lbryId}`"
|
||||
platform="Odysee"
|
||||
/>
|
||||
<!-- listen / watch toggle -->
|
||||
<router-link
|
||||
:to="toggleListenUrl"
|
||||
:aria-label="(isListening ? 'Watch ' : 'Listen to ') + video.title"
|
||||
:title="(isListening ? 'Watch ' : 'Listen to ') + video.title"
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
>
|
||||
<div>
|
||||
<i-fa6-solid-tv v-if="isListening" class="mx-1.5" />
|
||||
<i-fa6-solid-headphones v-else class="mx-1.5" />
|
||||
</div>
|
||||
</router-link>
|
||||
</keep-alive>
|
||||
<button
|
||||
v-if="!isMobile"
|
||||
:class="theaterMode ? '-ml-5' : '-mr-5'"
|
||||
class="z-10 text-white"
|
||||
@click="
|
||||
theaterMode = !theaterMode;
|
||||
setPreference('theaterMode', theaterMode);
|
||||
"
|
||||
>
|
||||
<div>
|
||||
<i-fa6-solid-chevron-left v-if="theaterMode" />
|
||||
<i-fa6-solid-chevron-right v-else />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</Teleport>
|
||||
<div v-if="video && isMobile">
|
||||
<PlaylistVideos
|
||||
v-if="playlist"
|
||||
:playlist-id="playlistId"
|
||||
:playlist="playlist"
|
||||
:selected-index="index"
|
||||
:prefer-listen="isListening"
|
||||
/>
|
||||
<ChaptersBar
|
||||
v-if="video?.chapters?.length > 0 && showChapters"
|
||||
:mobile-layout="true"
|
||||
:chapters="video.chapters"
|
||||
:player-position="currentTime"
|
||||
@seek="navigate"
|
||||
/>
|
||||
</div>
|
||||
<!-- video title -->
|
||||
<div class="mt-2 text-2xl font-bold wrap-break-word" v-text="video.title" />
|
||||
<div class="my-3 flex flex-wrap">
|
||||
<!-- views / date -->
|
||||
<div class="flex flex-auto gap-2">
|
||||
<span v-t="{ path: 'video.views', args: { views: addCommas(video.views) } }" />
|
||||
<span> | </span>
|
||||
<span :title="new Date(video.uploadDate).toLocaleString()" v-text="uploadDate" />
|
||||
</div>
|
||||
<!-- Likes/dilikes -->
|
||||
<div class="flex gap-2">
|
||||
<template v-if="video.likes >= 0">
|
||||
<div class="flex items-center">
|
||||
<i-fa6-solid-thumbs-up />
|
||||
<strong class="ml-1" v-text="addCommas(video.likes)" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<i-fa6-solid-thumbs-down />
|
||||
<strong class="ml-1" v-text="video.dislikes >= 0 ? addCommas(video.dislikes) : '?'" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="video.likes < 0">
|
||||
<div>
|
||||
<strong v-t="'video.ratings_disabled'" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Channel info & options flex container -->
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<!-- Channel Image & Info -->
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
loading="lazy"
|
||||
height="48"
|
||||
width="48"
|
||||
:src="video.uploaderAvatar"
|
||||
alt=""
|
||||
class="rounded-full"
|
||||
/>
|
||||
<router-link
|
||||
v-if="video.uploaderUrl"
|
||||
class="ml-1.5 hover:text-red-500 focus:text-red-500 dark:hover:text-red-400 dark:focus:text-red-400"
|
||||
:to="video.uploaderUrl"
|
||||
>{{ video.uploader }}</router-link
|
||||
>
|
||||
<!-- Verified Badge -->
|
||||
<i-fa6-solid-check v-if="video.uploaderVerified" class="ml-1" />
|
||||
</div>
|
||||
<PlaylistAddModal
|
||||
v-if="showModal"
|
||||
:video-id="getVideoId()"
|
||||
:video-info="video"
|
||||
@close="showModal = !showModal"
|
||||
/>
|
||||
<ShareModal
|
||||
v-if="showShareModal"
|
||||
:video-id="getVideoId()"
|
||||
:current-time="currentTime"
|
||||
:playlist-id="playlistId"
|
||||
:playlist-index="index"
|
||||
@close="showShareModal = !showShareModal"
|
||||
/>
|
||||
<div class="ml-auto flex flex-wrap gap-1">
|
||||
<!-- Subscribe Button -->
|
||||
<button
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:hidden max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="downloadCurrentFrame"
|
||||
>
|
||||
{{ $t("actions.download_frame") }}<i-fa6-solid-download class="ml-1" />
|
||||
</button>
|
||||
<button
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showModal = !showModal"
|
||||
>
|
||||
{{ $t("actions.add_to_playlist") }}<i-fa6-solid-circle-plus class="ml-1" />
|
||||
</button>
|
||||
<button
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="subscribeHandler"
|
||||
v-text="
|
||||
$t('actions.' + (subscribed ? 'unsubscribe' : 'subscribe')) +
|
||||
' - ' +
|
||||
numberFormat(video.uploaderSubscriberCount)
|
||||
"
|
||||
/>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<!-- RSS Feed button -->
|
||||
<a
|
||||
v-if="video.uploaderUrl"
|
||||
aria-label="RSS feed"
|
||||
title="RSS feed"
|
||||
role="button"
|
||||
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${video.uploaderUrl.split('/')[2]}`"
|
||||
target="_blank"
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
>
|
||||
<i-fa6-solid-rss class="mx-1.5" />
|
||||
</a>
|
||||
<!-- Share Dialog -->
|
||||
<button
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showShareModal = !showShareModal"
|
||||
>
|
||||
<i18n-t class="max-lg:hidden" keypath="actions.share" tag="strong"></i18n-t>
|
||||
<i-fa6-solid-share class="mx-1.5" />
|
||||
</button>
|
||||
<!-- YouTube -->
|
||||
<WatchOnButton :link="youtubeVideoHref" />
|
||||
<!-- Odysee -->
|
||||
<WatchOnButton
|
||||
v-if="video.lbryId"
|
||||
:link="`https://odysee.com/${video.lbryId}`"
|
||||
platform="Odysee"
|
||||
/>
|
||||
<!-- listen / watch toggle -->
|
||||
<router-link
|
||||
:to="toggleListenUrl"
|
||||
:aria-label="(isListening ? 'Watch ' : 'Listen to ') + video.title"
|
||||
:title="(isListening ? 'Watch ' : 'Listen to ') + video.title"
|
||||
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
>
|
||||
<div>
|
||||
<i-fa6-solid-tv v-if="isListening" class="mx-1.5" />
|
||||
<i-fa6-solid-headphones v-else class="mx-1.5" />
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mb-2" />
|
||||
<hr class="mb-2" />
|
||||
|
||||
<div
|
||||
v-for="metaInfo in video?.metaInfo ?? []"
|
||||
:key="metaInfo.title"
|
||||
class="my-3 inline-block w-auto cursor-default rounded-sm bg-gray-300 px-4 py-2 text-gray-600 dark:bg-dark-400 dark:text-gray-400"
|
||||
>
|
||||
<span>{{ metaInfo.description ?? metaInfo.title }}</span>
|
||||
<a v-for="(link, linkIndex) in metaInfo.urls" :key="linkIndex" :href="link" class="underline">{{
|
||||
metaInfo.urlTexts[linkIndex]
|
||||
}}</a>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<button
|
||||
v-t="`actions.${showDesc ? 'minimize_description' : 'show_description'}`"
|
||||
class="mb-2 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showDesc = !showDesc"
|
||||
/>
|
||||
|
||||
<span
|
||||
v-show="video?.chapters?.length > 0"
|
||||
class="ml-2 inline-block w-auto cursor-default rounded-sm bg-gray-300 py-2 text-gray-600 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400"
|
||||
>
|
||||
<UiCheckbox id="showChapters" v-model="showChapters" />
|
||||
<label v-t="'actions.show_chapters'" class="ml-2" for="showChapters" />
|
||||
</span>
|
||||
|
||||
<template v-if="showDesc">
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div class="wrap-break-word [&_a]:underline [&_a]:brightness-75" v-html="purifiedDescription" />
|
||||
<br />
|
||||
|
||||
<div
|
||||
v-for="metaInfo in video?.metaInfo ?? []"
|
||||
:key="metaInfo.title"
|
||||
class="my-3 inline-block w-auto cursor-default rounded-sm bg-gray-300 px-4 py-2 text-gray-600 dark:bg-dark-400 dark:text-gray-400"
|
||||
>
|
||||
<span>{{ metaInfo.description ?? metaInfo.title }}</span>
|
||||
<a v-for="(link, linkIndex) in metaInfo.urls" :key="linkIndex" :href="link" class="underline">{{
|
||||
metaInfo.urlTexts[linkIndex]
|
||||
}}</a>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<button
|
||||
v-t="`actions.${showDesc ? 'minimize_description' : 'show_description'}`"
|
||||
class="mb-2 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showDesc = !showDesc"
|
||||
v-if="sponsors && sponsors.segments"
|
||||
v-text="`${$t('video.sponsor_segments')}: ${sponsors.segments.length}`"
|
||||
/>
|
||||
<div v-if="video.category" v-text="`${$t('video.category')}: ${video.category}`" />
|
||||
<div v-text="`${$t('video.license')}: ${video.license}`" />
|
||||
<div class="capitalize" v-text="`${$t('video.visibility')}: ${video.visibility}`" />
|
||||
|
||||
<span
|
||||
v-show="video?.chapters?.length > 0"
|
||||
class="ml-2 inline-block w-auto cursor-default rounded-sm bg-gray-300 py-2 text-gray-600 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400"
|
||||
>
|
||||
<UiCheckbox id="showChapters" v-model="showChapters" />
|
||||
<label v-t="'actions.show_chapters'" class="ml-2" for="showChapters" />
|
||||
</span>
|
||||
|
||||
<template v-if="showDesc">
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div class="wrap-break-word [&_a]:underline [&_a]:brightness-75" v-html="purifiedDescription" />
|
||||
<br />
|
||||
|
||||
<div
|
||||
v-if="sponsors && sponsors.segments"
|
||||
v-text="`${$t('video.sponsor_segments')}: ${sponsors.segments.length}`"
|
||||
/>
|
||||
<div v-if="video.category" v-text="`${$t('video.category')}: ${video.category}`" />
|
||||
<div v-text="`${$t('video.license')}: ${video.license}`" />
|
||||
<div class="capitalize" v-text="`${$t('video.visibility')}: ${video.visibility}`" />
|
||||
|
||||
<div v-if="video.tags" class="mt-2 flex flex-wrap gap-2">
|
||||
<router-link
|
||||
v-for="tag in video.tags"
|
||||
:key="tag"
|
||||
class="line-clamp-1 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 px-2 py-1 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
:to="`/results?search_query=${encodeURIComponent(tag)}`"
|
||||
>{{ tag }}</router-link
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="video.tags" class="mt-2 flex flex-wrap gap-2">
|
||||
<router-link
|
||||
v-for="tag in video.tags"
|
||||
:key="tag"
|
||||
class="line-clamp-1 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 px-2 py-1 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
:to="`/results?search_query=${encodeURIComponent(tag)}`"
|
||||
>{{ tag }}</router-link
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<hr />
|
||||
|
||||
@@ -273,12 +266,12 @@
|
||||
</select>
|
||||
|
||||
<hr />
|
||||
<a
|
||||
v-t="`actions.${showRecs ? 'minimize_recommendations' : 'show_recommendations'}`"
|
||||
class="mb-2 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showRecs = !showRecs"
|
||||
/>
|
||||
<div v-if="isMobile">
|
||||
<a
|
||||
v-t="`actions.${showRecs ? 'minimize_recommendations' : 'show_recommendations'}`"
|
||||
class="mb-2 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showRecs = !showRecs"
|
||||
/>
|
||||
<hr v-show="showRecs" />
|
||||
<div v-show="showRecs">
|
||||
<ContentItem
|
||||
@@ -326,7 +319,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="video && !isMobile" class="max-w-96 flex-none">
|
||||
<div v-if="video && showDesktopSidebar" class="w-96 flex-none">
|
||||
<ChaptersBar
|
||||
v-if="video?.chapters?.length > 0 && showChapters"
|
||||
:mobile-layout="isMobile"
|
||||
@@ -341,11 +334,6 @@
|
||||
:selected-index="index"
|
||||
:prefer-listen="isListening"
|
||||
/>
|
||||
<a
|
||||
v-t="`actions.${showRecs ? 'minimize_recommendations' : 'show_recommendations'}`"
|
||||
class="mb-2 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
|
||||
@click="showRecs = !showRecs"
|
||||
/>
|
||||
<hr v-show="showRecs" />
|
||||
<div v-show="showRecs">
|
||||
<ContentItem
|
||||
@@ -439,6 +427,13 @@ const selectedAutoPlayEnabled = computed(() => {
|
||||
return Number(selectedAutoPlay.value) >= 1;
|
||||
});
|
||||
|
||||
const showDesktopSidebar = computed(() => {
|
||||
return (
|
||||
!isMobile.value &&
|
||||
(showRecs.value || Boolean(playlist.value) || (video.value?.chapters?.length > 0 && showChapters.value))
|
||||
);
|
||||
});
|
||||
|
||||
const toggleListenUrl = computed(() => {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("listen", isListening.value ? "0" : "1");
|
||||
|
||||
Reference in New Issue
Block a user