Merge pull request #1698 from dragos-efy/efy

Improved design, Bug fixes, Color pickers, Custom max width, Extra Modules, Menu integration
This commit is contained in:
Bnyro 2022-11-08 18:29:32 +01:00 committed by GitHub
commit 2dcd5c26de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 346 additions and 245 deletions

View file

@ -1,3 +1,4 @@
dist
node_modules
efy
*piped.js

BIN
public/audio/dreamy.mp3 Normal file

Binary file not shown.

BIN
public/audio/fireworks.mp3 Normal file

Binary file not shown.

BIN
public/audio/forest.mp3 Normal file

Binary file not shown.

BIN
public/audio/people.mp3 Normal file

Binary file not shown.

BIN
public/audio/rain.mp3 Normal file

Binary file not shown.

Binary file not shown.

BIN
public/audio/underwater.mp3 Normal file

Binary file not shown.

BIN
public/audio/waves.mp3 Normal file

Binary file not shown.

View file

@ -18,23 +18,16 @@
--efy_color1_var: 239, 68, 68;
--efy_color2_var: 220, 38, 38;
--efy_radius: 12rem;
--efy_sidebar_button: right_middle;
--efy_sidebar_button: right_middle, off;
--efy_font_family: "nunito", sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial,
Noto Sans, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
--efy_body_width: unset;
--efy_body_width: 100%;
--efy_audio_path: ./audio;
--efy_modules: efy_quick, efy_mode, efy_filters, efy_backup, efy_accessibility, efy_audio;
--efy_module_quick: on;
--efy_module_mode: on;
--efy_module_filters: on;
--efy_module_backup: on;
--efy_module_accessibility: on;
--efy_module_audio: on;
--efy_modules: efy_quick, efy_mode, efy_filters, efy_backup, efy_accessibility, efy_audio, efy_keyboard, efy_extra;
}
body {
@apply max-w-100vw p-16rem;
@apply p-16rem;
}
/*Default Mode*/
@ -49,10 +42,8 @@ body {
input,
.btn,
button,
.shaka-video-container,
.shaka-video-container video,
.video-grid div,
.pp-show-recs div,
.pp-show-playlist,
:is(.video-grid, .pp-show-recs, .pp-show-playlist) div,
.grid .comment,
.shaka-scrim-container,
.suggestion-selected,
@ -60,12 +51,14 @@ button,
.shaka-text-container span > span > span {
border-radius: var(--efy_radius);
}
.shaka-video-container,
.shaka-video-container video,
video {
border-radius: var(--efy_radius) !important;
}
/*Radius 0*/
.video-grid img,
.thumbnail-overlay,
.thumbnail-left,
.thumbnail-right {
.video-grid img {
border-radius: var(--efy_radius0);
}
@ -74,6 +67,87 @@ button,
.modal-container {
border-radius: var(--efy_radius2);
}
.pp-full-width :is(.comment, .comment-content) {
width: 100%;
}
:is(.pp-trans, .pp-solid).shaka-text-container,
:is(.pp-trans, .pp-solid).shaka-text-container * {
background: transparent !important;
text-shadow: 0 0 15rem #000 !important;
backdrop-filter: none !important;
}
.pp-solid.shaka-text-container .shaka-text-wrapper * {
background: #000 !important;
backdrop-filter: none !important;
text-shadow: none !important;
}
.pp-video-card-title {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin: 0 0 5rem 0;
line-height: 22rem;
}
.pp-video-card-buttons {
display: flex;
flex-wrap: wrap;
gap: 10rem;
margin: 5rem 0 0;
}
.pp-video-card-buttons :is(a, button) {
padding: 4rem 8rem;
margin: 0;
border: var(--efy_border);
color: var(--efy_text);
-webkit-text-fill-color: var(--efy_text);
}
.pp-video-card-buttons :is(a:not(.pp-color), button:not(.pp-color)) {
background: var(--efy_bg1);
}
.pp-video-card-buttons .pp-color {
color: var(--efy_text2);
-webkit-text-fill-color: var(--efy_text2);
border: 0;
padding: 6rem 10rem;
height: 35rem;
}
.pp-video-card-channel > .pp-text {
line-height: 20rem;
background: var(--efy_bg1) !important;
border: var(--efy_border) !important;
display: flex;
width: fit-content;
height: 36rem;
place-items: center;
padding: 0 10rem;
overflow: hidden;
}
.pp-video-card-channel > .pp-text span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 160rem;
}
.pp-video-card-channel > .pp-text strong span {
font-weight: normal;
font-size: 14rem !important;
}
.pp-video-card-channel {
display: flex;
gap: 10rem;
place-items: center;
background: transparent;
margin: 10rem 0 0;
width: fit-content;
}
.pp-video-card-channel > a {
height: 36rem;
width: 36rem;
}
:is(.pp-video-card-channel > a, .pp-video-card-channel > .pp-text):empty {
display: none;
}
</style>
<script>

View file

@ -13,29 +13,30 @@
<span v-html="purifyHTML(urlify(channel.description))" />
</p>
<button
class="btn"
@click="subscribeHandler"
v-t="{
path: `actions.${subscribed ? 'unsubscribe' : 'subscribe'}`,
args: { count: numberFormat(channel.subscriberCount) },
}"
></button>
<div class="flex mt-4 mb-2 pp-channel-tabs">
<button
class="btn pp-subscribe"
@click="subscribeHandler"
v-t="{
path: `actions.${subscribed ? 'unsubscribe' : 'subscribe'}`,
args: { count: numberFormat(channel.subscriberCount) },
}"
></button>
<!-- RSS Feed button -->
<a
aria-label="RSS feed"
title="RSS feed"
role="button"
v-if="channel.id"
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${channel.id}`"
target="_blank"
class="btn flex-col ml-3"
>
<font-awesome-icon icon="rss" />
</a>
<div class="flex mt-4 mb-2">
<!-- RSS Feed button -->
<a
aria-label="RSS feed"
title="RSS feed"
role="button"
v-if="channel.id"
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${channel.id}`"
target="_blank"
class="btn flex-col ml-2"
style="display: inline; float: unset"
>
<font-awesome-icon icon="rss" />
</a>
<p>|</p>
<button
v-for="(tab, index) in tabs"
:key="tab.name"
@ -57,11 +58,20 @@
height="94"
width="168"
hide-channel
class="efy_trans_filter"
/>
</div>
</div>
</template>
<style>
.pp-channel-tabs > p {
place-self: center;
padding: 0 10rem;
-webkit-text-fill-color: var(--efy_text_trans2);
}
</style>
<script>
import ErrorHandler from "./ErrorHandler.vue";
import ContentItem from "./ContentItem.vue";
@ -236,9 +246,3 @@ export default {
},
};
</script>
<style>
.active {
border: 0.1rem outset red;
}
</style>

View file

@ -25,11 +25,6 @@
</div>
</div>
<div class="whitespace-pre-wrap" v-html="urlify(comment.commentText)" />
<div class="comment-footer mt-1 flex items-center">
<div class="i-fa-solid:thumbs-up" />
<span class="ml-1" v-text="numberFormat(comment.likeCount)" />
<font-awesome-icon class="ml-1" v-if="comment.hearted" icon="heart" />
</div>
<template v-if="comment.repliesPage && (!loadingReplies || !showingReplies)">
<div @click="loadReplies" class="cursor-pointer">
<a v-text="`${$t('actions.reply_count', comment.replyCount)}`" />

View file

@ -1,24 +1,24 @@
<template>
<footer>
<footer class="efy_trans_filter">
<a aria-label="GitHub" href="https://github.com/TeamPiped/Piped" target="_blank">
<font-awesome-icon :icon="['fab', 'github']" />
<span class="ml-2" v-t="'actions.source_code'" />
<span v-t="'actions.source_code'" />
</a>
<a href="https://piped-docs.kavin.rocks/" target="_blank">
<font-awesome-icon :icon="['fa', 'book']" />
<span class="ml-2" v-t="'actions.documentation'" />
<span v-t="'actions.documentation'" />
</a>
<a href="https://github.com/TeamPiped/Piped#donations" target="_blank">
<font-awesome-icon :icon="['fab', 'bitcoin']" />
<span class="ml-2" v-t="'actions.donations'" />
<span v-t="'actions.donations'" />
</a>
<a v-if="statusPageHref" :href="statusPageHref">
<font-awesome-icon :icon="['fa', 'server']" />
<span class="ml-2" v-t="'actions.status_page'" />
<span v-t="'actions.status_page'" />
</a>
<a v-if="donationHref" :href="donationHref">
<font-awesome-icon :icon="['fa', 'donate']" />
<span class="ml-2" v-t="'actions.instance_donations'" />
<span v-t="'actions.instance_donations'" />
</a>
</footer>
</template>
@ -47,16 +47,23 @@ export default {
<style>
footer {
text-align: center;
display: flex;
flex-wrap: wrap;
gap: 15rem;
justify-content: center;
width: 100%;
margin-top: 30rem;
margin-bottom: 10rem;
margin: 15rem 0 0 0;
background: var(--efy_bg1);
border-radius: var(--efy_radius);
padding: 15rem 5rem;
border: var(--efy_border);
}
footer > a {
margin: 0 15rem;
margin: 0;
}
footer a {
color: var(--efy_text) !important;
-webkit-text-fill-color: var(--efy_text) !important;
background: transparent !important;
}
</style>

View file

@ -1,12 +1,12 @@
<template>
<h1 class="font-bold text-center" v-t="'titles.history'" />
<div class="flex">
<div>
<div class="flex place-items-center">
<div class="mr-2">
<button class="btn" v-t="'actions.clear_history'" @click="clearHistory" />
</div>
<div class="right-1">
<div class="mr-2">
<SortingSelector by-key="watchedAt" @apply="order => videos.sort(order)" />
</div>
</div>

View file

@ -1,6 +1,6 @@
<template>
<div>
<form>
<form style="display: grid; gap: 15rem">
<div>
<input ref="fileSelector" type="file" @change="fileChange" />
</div>

View file

@ -5,7 +5,7 @@
><img alt="logo" src="/img/icons/logo.svg" height="32" width="32" />iped</router-link
>
</div>
<div class="lt-md:hidden">
<div class="lt-md:hidden flex flex-1 justify-start">
<input
v-model="searchText"
type="text"
@ -20,50 +20,39 @@
/>
</div>
<!-- hamburger menu on mobile -->
<button class="pp-mobile-btn flex flex-col justify-end mr-3" @click="showTopNav = !showTopNav">
<button class="pp-mobile-btn" efy_sidebar_btn="relative, pp-mobile">
<i efy_icon="menu" />
</button>
<!-- navigation bar for large screen devices -->
<ul class="flex-1 flex justify-end flex text-1xl children:pl-3">
<li v-if="shouldShowTrending">
<router-link v-t="'titles.trending'" to="/trending" />
</li>
<li>
<router-link v-t="'titles.preferences'" to="/preferences" />
</li>
<li v-if="shouldShowLogin">
<p
class="cursor-pointer font-bold"
v-if="shouldShowLogin"
v-t="'titles.account'"
@click="showLoginModal = !showLoginModal"
/>
</li>
<li v-if="shouldShowHistory">
<router-link v-t="'titles.history'" to="/history" />
</li>
<li v-if="authenticated">
<router-link v-t="'titles.playlists'" to="/playlists" />
</li>
<li v-if="!shouldShowTrending">
<router-link v-t="'titles.feed'" to="/feed" />
</li>
</ul>
<div class="pp-menu flex justify-end children:pl-3">
<router-link v-if="shouldShowTrending" v-t="'titles.trending'" to="/trending" />
<router-link v-t="'titles.preferences'" to="/preferences" />
<p
v-if="shouldShowLogin"
class="cursor-pointer font-bold"
v-t="'titles.account'"
@click="showLoginModal = !showLoginModal"
/>
<router-link v-if="shouldShowHistory" v-t="'titles.history'" to="/history" />
<router-link v-if="authenticated" v-t="'titles.playlists'" to="/playlists" />
<router-link v-if="!shouldShowTrending" v-t="'titles.feed'" to="/feed" />
<button
efy_sidebar_btn="relative, pp-desktop"
style="
background: transparent;
-webkit-text-fill-color: var(--efy_text);
padding: 0;
margin: -5rem 0 0 0;
border: 0;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
"
>
<i efy_icon="menu" style="margin: 0" />
</button>
</div>
</nav>
<!-- navigation bar for mobile devices -->
<div v-if="showTopNav" class="pp-mobile-nav flex flex-col" @click="showTopNav = false">
<router-link v-if="shouldShowTrending" v-t="'titles.trending'" to="/trending" />
<router-link v-t="'titles.preferences'" to="/preferences" />
<p
class="cursor-pointer font-bold"
v-if="shouldShowLogin"
v-t="'titles.account'"
@click="showLoginModal = !showLoginModal"
/>
<router-link v-if="shouldShowHistory" v-t="'titles.history'" to="/history" />
<router-link v-if="authenticated" v-t="'titles.playlists'" to="/playlists" />
<router-link v-if="!shouldShowTrending" v-t="'titles.feed'" to="/feed" />
</div>
<!-- search suggestions for mobile devices -->
<div class="w-{full - 4} md:hidden mx-2">
<input
@ -87,6 +76,36 @@
<LoginModal v-if="showLoginModal" @close="showLoginModal = !showLoginModal" />
</template>
<style>
.pp-nav {
margin-bottom: 15rem;
gap: 15rem;
}
.pp-nav > .pp-logo > a {
font-size: 25rem;
font-family: "nunito";
background: transparent;
}
.pp-nav > div input {
margin: 0 !important;
width: 300rem;
}
.pp-nav .pp-menu {
list-style: none;
display: flex;
gap: 15rem;
margin: 0;
padding: 0;
}
.pp-nav .pp-menu > * {
margin: 0;
}
.pp-logo img {
width: auto;
margin: 0 -5rem;
}
</style>
<script>
import SearchSuggestions from "./SearchSuggestions.vue";
import hotkeys from "hotkeys-js";

View file

@ -7,7 +7,7 @@
<div class="flex justify-between items-center">
<div>
<router-link class="link" :to="playlist.uploaderUrl || '/'">
<img :src="playlist.uploaderAvatar" loading="lazy" class="rounded-full" />
<img :src="playlist.uploaderAvatar" loading="lazy" />
<strong v-text="playlist.uploader" />
</router-link>
</div>

View file

@ -1,5 +1,6 @@
<template>
<div class="overflow-x-scroll h-screen-sm" ref="scrollable">
<h6 efy_card style="padding: 5rem 10rem 3rem; margin: 0 0 15rem 0">Playlist</h6>
<div class="overflow-y-scroll h-screen-sm pp-show-playlist" ref="scrollable">
<VideoItem
v-for="(related, index) in playlist.relatedStreams"
:key="related.url"

View file

@ -6,24 +6,21 @@
<button v-t="'actions.create_playlist'" class="btn" @click="createPlaylist" />
<div class="video-grid">
<div v-for="playlist in playlists" :key="playlist.id">
<div v-for="playlist in playlists" :key="playlist.id" class="efy_trans_filter">
<router-link :to="`/playlist?list=${playlist.id}`">
<img class="w-full" :src="playlist.thumbnail" alt="thumbnail" />
<div class="relative text-sm">
<span
class="thumbnail-overlay thumbnail-right"
v-text="`${playlist.videos} ${$t('video.videos')}`"
/>
</div>
<p
style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical"
class="my-2 overflow-hidden flex link"
class="flex link"
:title="playlist.name"
v-text="playlist.name"
/>
</router-link>
<button class="btn h-auto" @click="renamePlaylist(playlist.id)" v-t="'actions.rename_playlist'" />
<button class="btn h-auto ml-2" @click="deletePlaylist(playlist.id)" v-t="'actions.delete_playlist'" />
<div class="pp-video-card-buttons flex gap-15rem children:m-0" style="flex-wrap: wrap">
<button class="thumbnail-overlay thumbnail-right" v-text="`${playlist.videos} ${$t('video.videos')}`" />
<button class="pp-color h-auto" @click="renamePlaylist(playlist.id)" v-t="'actions.rename_playlist'" />
<button class="pp-color h-auto" @click="deletePlaylist(playlist.id)" v-t="'actions.delete_playlist'" />
</div>
</div>
</div>
<br />

View file

@ -1,6 +1,6 @@
<template>
<div class="pp-pref-cards">
<div efy_card>
<div efy_card="grid">
<h2>Quick</h2>
<label class="pref" for="ddlLanguageSelection">
<strong v-t="'actions.language_selection'" />
@ -100,7 +100,7 @@
<!-- options that are visible only when logged in -->
<div v-if="this.authenticated">
<label class="pp-delete-account pref" for="txtDeleteAccountPassword" efy_card>
<label class="pp-delete-account pref" for="txtDeleteAccountPassword" efy_card="grid">
<h6 v-t="'actions.delete_account'" />
<input
id="txtDeleteAccountPassword"
@ -119,7 +119,7 @@
</div>
</div>
<div efy_card>
<div efy_card="grid">
<h2 v-t="'titles.player'" />
<label class="pref" for="chkAutoPlayVideo">
<strong v-t="'actions.autoplay_video'" />
@ -238,7 +238,7 @@
</label>
</div>
<div efy_card>
<div efy_card="grid">
<h2>SponsorBlock</h2>
<p>
<span v-t="'actions.uses_api_from'" /><a class="link" href="https://sponsor.ajay.app/"

View file

@ -1,7 +1,7 @@
<template>
<h1 class="text-center my-2" v-text="$route.query.search_query" />
<label for="ddlSearchFilters">
<label for="ddlSearchFilters" class="mr-2">
<strong v-text="`${$t('actions.filter')}:`" />
</label>
<select id="ddlSearchFilters" v-model="selectedFilter" default="all" class="select w-auto" @change="updateFilter()">

View file

@ -1,6 +1,6 @@
<template>
<label for="ddlSortBy" v-t="'actions.sort_by'" class="mr-2" />
<select id="ddlSortBy" v-model="selectedSort" class="select w-auto">
<select id="ddlSortBy" v-model="selectedSort" class="select w-auto m-0">
<option v-for="(value, key) in options" v-t="`actions.${key}`" :key="key" :value="value" />
</select>
</template>

View file

@ -1,5 +1,5 @@
<template>
<div v-if="showVideo">
<div v-if="showVideo" class="efy_trans_filter">
<router-link
:to="{
path: '/watch',
@ -17,37 +17,17 @@
:class="{ 'shorts-img': item.isShort }"
loading="lazy"
/>
<div class="relative text-sm">
<span
class="thumbnail-overlay thumbnail-right"
v-if="item.duration > 0"
v-text="timeFormat(item.duration)"
/>
<!-- shorts thumbnail -->
<span class="thumbnail-overlay thumbnail-left" v-if="item.isShort" v-t="'video.shorts'" />
<span
class="thumbnail-overlay thumbnail-right"
v-else-if="item.duration >= 0"
v-text="timeFormat(item.duration)"
/>
<i18n-t v-else keypath="video.live" class="thumbnail-overlay thumbnail-right live-badge" tag="div">
<font-awesome-icon :icon="['fas', 'broadcast-tower']" />
</i18n-t>
<span v-if="item.watched" class="thumbnail-overlay bottom-5px left-5px" v-t="'video.watched'" />
</div>
<div>
<p
style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical"
class="my-2 overflow-hidden flex link"
:title="item.title"
v-text="item.title"
/>
</div>
<p class="pp-video-card-title my-2 overflow-hidden flex link" :title="item.title" v-text="item.title" />
</router-link>
<div class="float-right m-0 inline-block children:px-1">
<div class="pp-video-card-buttons">
<button v-if="item.duration > 0" v-text="timeFormat(item.duration)" tabindex="-1" />
<button v-if="item.views >= 0" tabindex="-1">
<font-awesome-icon icon="eye" />
<span class="pl-0.5" v-text="`${numberFormat(item.views)}`" />
</button>
<router-link
class="btn"
:to="{
path: '/watch',
query: {
@ -73,52 +53,39 @@
>
<font-awesome-icon icon="circle-minus" />
</button>
<button v-if="item.uploadedDate" class="pl-0.5" v-text="item.uploadedDate" tabindex="-1" />
<button class="pp-color" v-if="item.isShort" v-t="'video.shorts'" tabindex="-1" />
<button v-else-if="item.duration < 0" v-t="'video.live'" class="pp-color" tabindex="-1" />
<button v-if="item.watched" v-t="'video.watched'" class="pp-color" tabindex="-1" />
</div>
<div class="flex">
<router-link :to="item.uploaderUrl">
<img
v-if="item.uploaderAvatar"
:src="item.uploaderAvatar"
loading="lazy"
:alt="item.uploaderName"
class="rounded-full mr-0.5 mt-0.5 w-32px h-32px"
width="68"
height="68"
/>
</router-link>
<router-link
:to="item.uploaderUrl"
class="pp-video-card-channel"
v-if="item.uploaderUrl && item.uploaderName && !hideChannel"
>
<img
v-if="item.uploaderAvatar"
:src="item.uploaderAvatar"
loading="lazy"
:alt="item.uploaderName"
class="mt-0.5 w-36rem h-36rem"
width="36"
height="36"
/>
<div class="w-[calc(100%-32px-1rem)]">
<router-link
v-if="item.uploaderUrl && item.uploaderName && !hideChannel"
class="link-secondary overflow-hidden block"
:to="item.uploaderUrl"
:title="item.uploaderName"
>
<span v-text="item.uploaderName" />
<font-awesome-icon class="ml-1.5" v-if="item.uploaderVerified" icon="check" />
</router-link>
<strong v-if="item.views >= 0 || item.uploadedDate" class="text-sm">
<span v-if="item.views >= 0">
<font-awesome-icon icon="eye" />
<span class="pl-0.5" v-text="`${numberFormat(item.views)} •`" />
</span>
<span v-if="item.uploaded > 0" class="pl-0.5" v-text="timeAgo(item.uploaded)" />
<span v-else-if="item.uploadedDate" class="pl-0.5" v-text="item.uploadedDate" />
</strong>
<div class="pp-text" title="item.uploaderName">
<span v-text="item.uploaderName" />
<font-awesome-icon class="ml-1.5" v-if="item.uploaderVerified" icon="check" />
</div>
</div>
</router-link>
</div>
<PlaylistAddModal v-if="showModal" :video-id="video.url.substr(-11)" @close="showModal = !showModal" />
</template>
<style>
.thumbnail-overlay {
@apply absolute;
}
.shorts-img {
@apply max-h-[17.5vh] w-full object-contain;
@apply w-full object-contain;
}
</style>

View file

@ -2,7 +2,7 @@
<div
ref="container"
data-shaka-player-container
class="w-full max-h-screen flex justify-center"
class="w-full max-h-screen flex justify-center efy_trans_filter_off"
:class="{ 'player-container': !isEmbed }"
>
<video ref="videoEl" class="w-full" data-shaka-player :autoplay="shouldAutoPlay" :loop="selectedAutoLoop" />
@ -652,10 +652,11 @@ export default {
<style>
.player-container {
@apply max-h-75vh min-h-64 bg-black;
@apply max-h-75vh min-h-64;
background: #000;
}
[efy_theme="dark_black"] .player-container {
box-shadow: 0 0 0 1.5rem var(--efy_color_border);
box-shadow: 0 0 0 1.5rem var(--efy_bg1);
}
.shaka-video-container:-webkit-full-screen {
max-height: none !important;
@ -664,15 +665,19 @@ export default {
/*Captions*/
.shaka-text-wrapper * {
text-align: left !important;
font-family: "nunito" !important;
}
.shaka-text-wrapper > span {
background: #0008;
background: #0008 !important;
backdrop-filter: blur(20rem);
border: 1.5rem solid var(--efy_color_border);
border-radius: var(--efy_radius);
padding: 8rem 12rem;
line-height: 28rem;
}
.shaka-text-wrapper > span:empty {
display: none !important;
}
/* apply to all spans that don't include multiple other spans to avoid the style being applied to the text container too when the subtitles are two lines */
.shaka-text-wrapper > span > span *:first-child:last-child {
background: transparent !important;
@ -727,4 +732,7 @@ html .shaka-range-element:focus {
background: var(--efy_bg1) !important;
box-shadow: inset 0 0 0 1.5px var(--efy_bg1);
}
.shaka-controls-container {
border-radius: var(--efy_radius) !important;
}
</style>

View file

@ -39,7 +39,7 @@
<div class="pp-video-title font-bold mt-2 text-2xl break-words" v-text="video.title" />
<div class="pp-bellow-video flex flex-wrap mt-3 mb-3">
<!-- views / date -->
<div class="flex flex-auto children:ml-2">
<div class="flex flex-auto">
<span v-t="{ path: 'video.views', args: { views: addCommas(video.views) } }" />
<span> </span>
<span v-text="uploadDate" />
@ -133,6 +133,8 @@
<div efy_select>
<input id="showDesc" type="checkbox" v-model="showDesc" />
<label for="showDesc" v-t="'actions.show_description'" />
<input id="showComments" type="checkbox" v-model="showComments" @click="toggleComments" />
<label for="showComments" v-t="'actions.show_comments'" />
<input id="showRecs" type="checkbox" v-model="showRecs" />
<label for="showRecs" v-t="'actions.show_recommendations'" />
<input id="chkAutoLoop" v-model="selectedAutoLoop" type="checkbox" @change="onChange($event)" />
@ -146,35 +148,36 @@
</div>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-show="showDesc" class="break-words mb-2" v-html="purifyHTML(video.description)" />
<div
v-show="showDesc"
class="break-words mb-2"
v-html="purifyHTML(video.description)"
style="border-top: var(--efy_border); margin: 15rem 0; padding: 15rem 0"
/>
<div
v-if="showDesc && sponsors && sponsors.segments"
v-text="`${$t('video.sponsor_segments')}: ${sponsors.segments.length}`"
/>
</div>
<hr />
<div class="grid pp-rec-vids">
<div class="xl:col-span-4 sm:col-span-3">
<button
class="btn mb-2"
@click="toggleComments"
v-t="`actions.${showComments ? 'minimize_comments' : 'show_comments'}`"
/>
</div>
<div v-if="!showComments" class="w-full"></div>
<div v-else-if="!comments" class="">
<div v-if="!comments" class="">
<p class="text-center mt-8" v-t="'comment.loading'"></p>
</div>
<div v-else-if="comments.disabled" class="">
<p class="text-center mt-8" v-t="'comment.disabled'"></p>
</div>
<div v-else ref="comments" v-show="showComments" class="">
<div v-else ref="comments" v-show="showComments" class="pp-comments">
<CommentItem
v-for="comment in comments.comments"
:key="comment.commentId"
:comment="comment"
:uploader="video.uploader"
:video-id="getVideoId()"
class="efy_trans_filter"
/>
</div>
@ -185,8 +188,8 @@
:playlist="playlist"
:selected-index="index"
/>
<hr v-show="showRecs" />
<div v-show="showRecs" class="pp-show-recs">
<h6 efy_card style="padding: 5rem 10rem 3rem; margin: 0">Recommended</h6>
<ContentItem
v-for="related in video.relatedStreams"
:key="related.url"

View file

@ -65,7 +65,7 @@
"auto_play_next_video": "Auto Play next Video",
"donations": "Development donations",
"minimize_comments": "Minimize Comments",
"show_comments": "Show Comments",
"show_comments": "Comments",
"minimize_description": "Minimize Description",
"show_description": "Description",
"minimize_recommendations": "Minimize Recommendations",

View file

@ -55,6 +55,7 @@ import "uno.css";
import "../efy/efy.css";
import "./piped.css";
import "../efy/efy.js";
import "./piped.js";
import App from "./App.vue";

View file

@ -2,21 +2,19 @@
/*End of EFY Template - Documentation on how to use it coming soon at https://efy.ooo/ui . Your own css starts bellow*/
/*BG: Transparent*/ .video-grid div div, .pp-show-recs div div {background: transparent}
/*BG 1*/ .comment, .video-grid div, .pp-show-recs div, .pp-mobile-nav a, .pp-mobile-nav p, .suggestion-selected, .pp-chapters .chapter:not(.pp-chapter-active, .chapter:hover), .pp-chapters [title=chapters] {background: var(--efy_bg1)}
/*BG 1*/ .comment, .pp-mobile-nav a, .pp-mobile-nav p, .suggestion-selected, .pp-chapters .chapter:not(.pp-chapter-active, .chapter:hover), .pp-chapters [title=chapters] {background: var(--efy_bg1)}
/*Bold*/ .btn {font-weight: bold}
/*Margin: 0*/ .pp-watch-buttons .btn, .suggestions-container li, .suggestions-container ul, .pp-nav > ul, .pp-mobile-btn i, .pp-mobile-nav a, .pp-mobile-nav p, .modal-container button:first-of-type svg {margin: 0}
/*Margin: 0*/ .pp-watch-buttons .btn, .suggestions-container li, .suggestions-container ul, .pp-mobile-btn i, .pp-mobile-nav a, .pp-mobile-nav p, .modal-container button:first-of-type svg {margin: 0}
/*Text-Align: Center*/ .btn, .pp-import-channel, .pp-sortby-feed, .pp-playlist-add-modal-top, .pp-nav, .pp-nav > div.flex-1.flex.justify-start > a, .pp-watch-bellow-options .flex.items-center, .pp-channel-page-author {align-items: center; text-align: center}
/*Justify-Content: Space-Between*/ .pp-playlist-add-modal-top, .pp-watch-bellow-options, .pp-nav {justify-content: space-between}
/*Display: Flex*/ .pp-watch-buttons, .pp-nav, .pp-nav>div.flex-1.flex.justify-start>a, .pp-watch-bellow-options .flex.items-center, .pp-nav > ul, .pp-channel-page-author, .grid .comment, .pp-chapters {display: flex}
/*Gap: 15rem*/ .pp-show-recs, .pp-rec-vids, .pp-mobile-nav, .pp-delete-account .flex, .pp-playlist-add-modal-top, .pp-pref-cards, .pp-nav, .pp-watch-bellow-options {gap: 15rem}
/*Display: Flex*/ .pp-watch-buttons, .pp-watch-bellow-options .flex.items-center, .pp-channel-page-author, .grid .comment, .pp-chapters {display: flex}
/*Gap: 15rem*/ .pp-show-playlist, .pp-rec-vids, .pp-mobile-nav, .pp-delete-account .flex, .pp-playlist-add-modal-top, .pp-pref-cards, .pp-watch-bellow-options {gap: 15rem}
/*Color: Text*/ .video-grid div a, .pp-show-recs div a, .video-grid div button:not(.modal button, .btn), .pp-show-recs div button:not(.modal button, .btn), .svg-inline--fa:not(.video-grid svg, .btn svg, button svg) {color: var(--efy_text)}
/*Border*/ .modal-container, .video-grid>div {border: 1.5px solid var(--efy_bg1);}
/*Text-Fill-Color: Text*/ p, .pp-mobile-nav a, .pp-mobile-nav p, .video-grid div a, .pp-show-recs div a, .thumbnail-left, .thumbnail-right, .comment a, .pp-watch-bellow-options a, .pp-nav > ul a, .pp-nav > div.flex-1.flex.justify-start > a {-webkit-text-fill-color: var(--efy_text); text-decoration: none}
/*Text-Fill-Color: Text*/ p, .pp-mobile-nav a, .pp-mobile-nav p, .video-grid div a, .pp-show-recs div a, .thumbnail-left, .thumbnail-right, .comment a, .pp-watch-bellow-options a, .pp-logo a, .pp-nav .pp-menu > * {-webkit-text-fill-color: var(--efy_text); text-decoration: none}
/*Text-Fill-Color: Text2*/ .btn, .btn a, a.btn, .modal button {-webkit-text-fill-color: var(--efy_text2); text-decoration: none}
/*BG: efy*/ .btn, .pp-chapter-active, .pp-chapters .chapter:hover {background: linear-gradient(165deg, var(--efy_color), var(--efy_color2)); background-clip: padding-box; color: var(--efy_text2)}
@ -25,13 +23,13 @@
/*Avatar*/ .comment-avatar, .pp-import-channel img {width: 40rem; height: 40rem}
/*Video Grid */ .video-grid {display: grid; gap: 16rem; grid-template-columns: repeat(auto-fit, minmax(224rem, 1fr))}
/*Video Grid */ .video-grid {display: grid; gap: 16rem; grid-template-columns: repeat(auto-fill, minmax(240rem, 1fr))}
tbody:nth-child(odd) {background: var(--efy_bg1)!important; box-shadow: inset 0 0 0 1.5px var(--efy_bg1)}
/*Bellow*/ .pp-watch-bellow-options {margin-top: 15rem}
.pp-watch-buttons {flex-wrap: wrap; gap: 10rem}
.pp-watch-buttons .btn {padding: 6rem 15rem; border: 0; color: var(--efy_text2); min-height: 36rem; max-height: 36rem; place-self: center}
.pp-watch-buttons .btn {padding: 6rem 15rem; border: 0; color: var(--efy_text2); min-height: 36rem; max-height: 36rem; place-self: center; place-content: center}
.pp-bellow-video, .pp-bellow-video .flex {gap:10rem}
.pp-likes .flex {gap: 0rem}
@ -44,20 +42,6 @@ tbody:nth-child(odd) {background: var(--efy_bg1)!important; box-shadow: inset 0
/*Animation: pulse2*/ .video-grid>div:active {animation: pulse2 0.1s ease-in-out backwards}
/*Top bar*/
.pp-nav {margin-bottom: 15rem}
.pp-nav > div.flex-1.flex.justify-start > a {font-size: 25rem}
.pp-nav > div.flex-1.flex.justify-start > a img {margin-right: -5rem}
.pp-nav > div input {margin: 0!important; width: 300rem}
.pp-nav > ul {list-style: none; padding: 0}
.pp-logo img {width: auto}
/*Cards*/ .video-grid > div > .flex > a > img {width: 32rem; height: 32rem}
.pp-video-title {font-size: 24rem; line-height: unset; margin-top: 10rem}
/*Avatar below video*/ .pp-watch-bellow-options .flex.items-center > a {margin: 0 0 0 10rem; font-size: 20rem}
@ -66,7 +50,17 @@ tbody:nth-child(odd) {background: var(--efy_bg1)!important; box-shadow: inset 0
/*Avatar Channel Page*/ .pp-channel-page-author {gap: 10rem; margin-top: 10rem}
.pp-channel-page-author > img {width: 48rem; height: 48rem}
/*Comments*/ .grid .comment {width: fit-content; margin: 0 0 15px 0; gap: 10rem; padding: 12rem; border: 1.5rem solid var(--efy_color_border)}
.pp-channel-tabs {flex-wrap: wrap}
.pp-channel-tabs button:not(.active, .pp-subscribe) {
background: var(--efy_gradient), linear-gradient(165deg, var(--efy_color_trans), var(--efy_color2_trans));
-webkit-background-clip: text, padding-box;
-moz-background-clip: text, padding-box;
-webkit-text-fill-color: transparent;
box-shadow: inset 0 0 0 1.5rem var(--efy_color_border)!important;
border: 0!important;
}
/*Comments*/ .grid .comment {width: fit-content; margin: 0 0 15px 0; gap: 10rem; padding: 12rem; border: var(--efy_border)}
.comment-author {flex-wrap: wrap}
.comment-meta {margin: 0 5rem}
.comment .comment {margin-top: 10rem}
@ -77,10 +71,10 @@ tbody:nth-child(odd) {background: var(--efy_bg1)!important; box-shadow: inset 0
.suggestions-container li {padding: 3rem 10rem}
.suggestion-selected {box-shadow: 0 0 0 1.5rem var(--efy_color_border), 0 0 0 1.5rem var(--efy_color_border)}
/*Thumbnail Overlay*/ .thumbnail-overlay, .thumbnail-left , .thumbnail-right {background: var(--efy_text2)!important; padding: 12rem 6rem!important}
/* .thumbnail-overlay, .thumbnail-left , .thumbnail-right {background: var(--efy_text2)!important; padding: 12rem 6rem!important}
.thumbnail-right {bottom: 15px; right: 8px}
.thumbnail-left {bottom: 16rem; left: 8rem}
.live-badge {padding: 6rem 7rem!important}
.live-badge {padding: 6rem 7rem!important}*/
/*Recommended Videos*/ .pp-rec-vids {display: grid; grid-template-columns: 1fr 300rem}
.order-first {-webkit-box-ordinal-group: -9998; -webkit-order: -9999; order: -9999}
@ -89,8 +83,8 @@ tbody:nth-child(odd) {background: var(--efy_bg1)!important; box-shadow: inset 0
table {margin-top: 0}
/*Chapters*/ .pp-chapters {margin-left: 15rem; max-width: 400rem; gap: 10rem; border-radius: var(--efy_radius)}
.pp-chapters .chapter {padding: 10rem; border-radius: var(--efy_radius); border: 1.5rem solid var(--efy_color_border)}
.pp-chapters [title=chapters] {padding: 5rem 10rem; border-radius: var(--efy_radius); border: 1.5rem solid var(--efy_color_border)}
.pp-chapters .chapter {padding: 10rem; border-radius: var(--efy_radius); border: var(--efy_border)}
.pp-chapters [title=chapters] {padding: 5rem 10rem; border-radius: var(--efy_radius); border: var(--efy_border)}
.pp-chapters .chapter .flex {gap: 0 15rem}
.pp-chapters.pp-mobile {margin: 15rem 0 0 0; max-width: 100%}
@ -106,13 +100,15 @@ table {margin-top: 0}
/*Subscribtions*/ .pp-import-channel {gap: 10rem}
/*Other*/ .pp-show-recs {display: grid}
.video-grid div, .pp-show-recs div {padding: 16rem; border: 1.5rem solid var(--efy_color_border)}
.video-grid div div, .pp-show-recs div div {padding: 0; border: none}
/*Other*/ .pp-show-recs, .pp-show-playlist, .pp-show-playlist {display: grid; gap: 15rem}
.pp-show-playlist {margin-bottom: 15rem}
:is(.video-grid, .pp-show-recs, .pp-show-playlist) div {padding: 15rem; background: var(--efy_bg1); border: var(--efy_border)}
:is(.video-grid, .pp-show-recs, .pp-show-playlist) div div {padding: 0; border: none; background: transparent}
.svg-inline--fa{vertical-align: -2.5rem}
.children\:px-1>*, .px-1 {padding-left: 4rem; padding-right: 4rem}
.video-grid div button:not(.modal button, .btn), .pp-show-recs div button:not(.modal button, .btn) {background: transparent!important; border: 0}
/*Fullscreen*/ .shaka-video-container:fullscreen, .shaka-video-container:fullscreen * {border-radius: 0 !important}
/*Variables*/
.mr-0\.5 {margin-right: 15rem}
@ -120,12 +116,11 @@ table {margin-top: 0}
.ml-1, .ml-1\.5 {margin-left: 5rem}
.mb-2 {margin-bottom: 15rem}
.mt-2 {margin-top: 15rem}
.mr-2 {margin-right: 10rem}
.mr-1, .mr-2 {margin-right: 10rem}
.children\:pb-3>* {padding-bottom: 15rem}
.children\:ml-2>*, .ml-2 {margin-left: 10rem}
.pp-mobile-btn {display: none; padding: 10rem 12rem}
.pp-mobile-nav {margin: 0 0 15rem 0}
.pp-mobile-nav a, .pp-mobile-nav p {padding: var(--efy_padding); width: 100%; border-radius: var(--efy_radius)}
.pp-mobile-btn {display: none; margin: 0!important; padding: 8rem 10rem}
/*Convergence*/
@media (max-width: 990px) {
@ -138,7 +133,7 @@ table {margin-top: 0}
}
@media (max-width: 639px) {
.pp-rec-vids {grid-template-columns: 1fr}
.pp-nav > ul {display: none}
.pp-nav .pp-menu {display: none!important}
.pp-mobile-btn {display: block}
}
@media (min-width: 640px){

29
src/piped.js Normal file
View file

@ -0,0 +1,29 @@
import {$, $all, $ready_once, $insert, $add, $append} from '../efy/efy.js';
$ready_once('#efy_sidebar').then(()=>{
$insert($('#efy_sidebar'), 'afterbegin', $add('div', { id: 'piped_efy_module' }));
/*Custom Menu*/ $append($('#efy_modules'), $add('div', {id: 'custom_sidebar_menu'}));
for (let a = ['preferences', 'history', 'playlists', 'feed'], b = ['Preferences', 'History', 'Playlists', 'Feed'], c = $('#custom_sidebar_menu'), i = 0; i < a.length; i++){ $append(c, $add('a', {href: `./${a[i]}`}, [b[i]]))}
/*Custom Settings*/ $append($('#efy_modules'), $add('details', {id: 'piped_style'}, [
$add('summary', {}, [$add('i', {efy_icon: 'dots'}), 'Piped Style (Alpha)']), $add('div', {efy_tabs: 'piped_style'})]),
);
/*Tabs*/ for (let a = ['option1', 'option2', 'option3'], b = ['Tab 1', 'Tab 2', 'Tab 3'], c = $('[efy_tabs=piped_style]'), i = 0; i < a.length; i++) {
$append(c, $add('button', {efy_tab: a[i]}, [b[i]]));
}
for (let a = ['option1', 'option2', 'option3'], c = $('[efy_tabs=piped_style]'), i = 0; i < a.length; i++) {
$append(c, $add('div', {efy_content: a[i], efy_select: '', id: `efy_${a[i]}`}))
}
/*Active*/ for (let a = ['[efy_tab=option1]', '[efy_content=option1]'], b = '[efy_tabs=piped_style] > ', i = 0; i < a.length; i++){$(b + a[i]).setAttribute('efy_active', '')}
/*Tab1*/ for (let a = 'comments_full captions-trans captions-solid'.split(' '), b = ['Comments - Full Width', 'Captions - No Background', 'Captions - Black Background'], c = $('[efy_tabs=piped_style] [efy_content=option1]'), i = 0; i < a.length; i++) {
$append(c, $add('input', {type: 'checkbox', name: 'piped_style_option1', id: `piped_style_${a[i]}`}));
$append(c, $add('label', {for: `piped_style_${a[i]}`}, [b[i]]));
}
/*Comments & Captions*/ for (let a = ['comments_full', 'captions-trans', 'captions-solid'], b = ['.pp-comments', '.shaka-text-container', '.shaka-text-container'], c = ['pp-full-width', 'pp-trans', 'pp-solid'], i = 0; i < a.length; i++) {
$(`#piped_style_${a[i]}`).addEventListener('click', ()=>{
$all(b[i]).forEach( (e)=>{ e.classList.toggle(c[i]) })
})
}
});