Merge pull request #186 from WardPearce/fix/layout-and-code-layout

Fix/layout and code layout
This commit is contained in:
Ward
2024-04-30 17:37:13 +12:00
committed by GitHub
4 changed files with 620 additions and 590 deletions
+456
View File
@@ -0,0 +1,456 @@
<script lang="ts">
import { bookmarkletSaveToUrl } from '$lib/bookmarklet';
import 'beercss';
import 'material-dynamic-colors';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import {
darkModeStore,
deArrowEnabledStore,
deArrowInstanceStore,
deArrowThumbnailInstanceStore,
interfacePreviewVideoOnHoverStore,
interfaceSearchSuggestionsStore,
playerAlwaysLoopStore,
playerAutoPlayStore,
playerAutoplayNextByDefaultStore,
playerDashStore,
playerListenByDefaultStore,
playerProxyVideosStore,
playerSavePlaybackPositionStore,
playerTheatreModeByDefaultStore,
returnYTDislikesInstanceStore,
returnYtDislikesStore,
sponsorBlockCategoriesStore,
sponsorBlockStore,
sponsorBlockUrlStore,
synciousInstanceStore,
synciousStore,
themeColorStore
} from '../store';
let sponsorCategoriesList: string[] = [];
sponsorBlockCategoriesStore.subscribe((value) => (sponsorCategoriesList = value));
let sponsorBlockInstance = get(sponsorBlockUrlStore);
let synciousInstance = get(synciousInstanceStore);
let returnYTInstance = get(returnYTDislikesInstanceStore);
let deArrowUrl = get(deArrowInstanceStore);
let deArrowThumbnailUrl = get(deArrowThumbnailInstanceStore);
const sponsorCategories = [
{ name: $_('layout.sponsors.sponsor'), category: 'sponsor' },
{ name: $_('layout.sponsors.unpaidSelfPromotion'), category: 'selfpromo' },
{ name: $_('layout.sponsors.interactionReminder'), category: 'interaction' },
{ name: $_('layout.sponsors.intermissionIntroAnimation'), category: 'intro' },
{ name: $_('layout.sponsors.credits'), category: 'outro' },
{ name: $_('layout.sponsors.preViewRecapHook'), category: 'preview' },
{ name: $_('layout.sponsors.tangentJokes'), category: 'filler' }
];
function toggleSponsor(category: string) {
if (sponsorCategoriesList.includes(category)) {
sponsorBlockCategoriesStore.set(sponsorCategoriesList.filter((value) => value !== category));
} else {
sponsorCategoriesList.push(category);
sponsorBlockCategoriesStore.set(sponsorCategoriesList);
}
}
async function setColor(color: any) {
const target = color.target;
const hex = (target as { value: string }).value;
await ui('theme', hex);
themeColorStore.set(hex);
}
function toggleDarkMode() {
const isDark = get(darkModeStore);
if (isDark) {
ui('mode', 'light');
darkModeStore.set(false);
} else {
ui('mode', 'dark');
darkModeStore.set(true);
}
}
</script>
<dialog class="right" id="dialog-settings">
<nav>
<h4 class="max">{$_('layout.settings')}</h4>
<button class="circle transparent" data-ui="#dialog-settings"><i>close</i></button>
</nav>
<p>{$_('layout.customize')} Materialious</p>
<div class="settings">
<h6>{$_('layout.theme.theme')}</h6>
<button on:click={toggleDarkMode} class="no-margin">
{#if !$darkModeStore}
<i>dark_mode</i>
<span>{$_('layout.theme.darkMode')}</span>
{:else}
<i>light_mode</i>
<span>{$_('layout.theme.lightMode')}</span>
{/if}
</button>
<button>
<i>palette</i>
<span>{$_('layout.theme.color')}</span>
<input on:change={setColor} type="color" />
</button>
</div>
<div class="settings">
<h6>Interface</h6>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.searchSuggestions')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$interfaceSearchSuggestionsStore}
on:click={() => interfaceSearchSuggestionsStore.set(!$interfaceSearchSuggestionsStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.previewVideoOnHover')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$interfacePreviewVideoOnHoverStore}
on:click={() =>
interfacePreviewVideoOnHoverStore.set(!$interfacePreviewVideoOnHoverStore)}
/>
<span></span>
</label>
</nav>
</div>
</div>
<div class="settings">
<h6>{$_('layout.dataPreferences.dataPreferences')}</h6>
<p style="width: 240px;">
<a
href={`${import.meta.env.VITE_DEFAULT_INVIDIOUS_INSTANCE}/preferences`}
target="_blank"
rel="noopener noreferrer"
class="link"
>
{$_('layout.dataPreferences.content')}
</a>
</p>
</div>
<div class="settings">
<h6>{$_('layout.player.title')}</h6>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.autoPlay')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerAutoPlayStore}
on:click={() => playerAutoPlayStore.set(!$playerAutoPlayStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.alwaysLoopVideo')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerAlwaysLoopStore}
on:click={() => playerAlwaysLoopStore.set(!$playerAlwaysLoopStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.proxyVideos')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerProxyVideosStore}
on:click={() => playerProxyVideosStore.set(!$playerProxyVideosStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.savePlaybackPosition')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerSavePlaybackPositionStore}
on:click={() => playerSavePlaybackPositionStore.set(!$playerSavePlaybackPositionStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.listenByDefault')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerListenByDefaultStore}
on:click={() => playerListenByDefaultStore.set(!$playerListenByDefaultStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin m l">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.theatreModeByDefault')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerTheatreModeByDefaultStore}
on:click={() => playerTheatreModeByDefaultStore.set(!$playerTheatreModeByDefaultStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.autoPlayNextByDefault')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerAutoplayNextByDefaultStore}
on:click={() =>
playerAutoplayNextByDefaultStore.set(!$playerAutoplayNextByDefaultStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.dash')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerDashStore}
on:click={() => playerDashStore.set(!$playerDashStore)}
/>
<span></span>
</label>
</nav>
</div>
</div>
<div class="settings">
<h6>Return YT Dislikes</h6>
<form on:submit|preventDefault={() => returnYTDislikesInstanceStore.set(returnYTInstance)}>
<nav>
<div class="field label border max">
<input bind:value={returnYTInstance} name="returnyt-instance" type="text" />
<label for="returnyt-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
bind:checked={$returnYtDislikesStore}
on:click={() => returnYtDislikesStore.set(!$returnYtDislikesStore)}
type="checkbox"
/>
<span></span>
</label>
</nav>
</div>
<div class="settings">
<h6>Syncious</h6>
<form on:submit|preventDefault={() => synciousInstanceStore.set(synciousInstance)}>
<nav>
<div class="field label border max">
<input bind:value={synciousInstance} name="syncious-instance" type="text" />
<label for="syncious-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
bind:checked={$synciousStore}
on:click={() => synciousStore.set(!$synciousStore)}
type="checkbox"
/>
<span></span>
</label>
</nav>
</div>
<div class="settings">
<h6>Sponsorblock</h6>
<form on:submit|preventDefault={() => sponsorBlockUrlStore.set(sponsorBlockInstance)}>
<nav>
<div class="field label border max">
<input bind:value={sponsorBlockInstance} name="sponsorblock-instance" type="text" />
<label for="sponsorblock-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
bind:checked={$sponsorBlockStore}
on:click={() => sponsorBlockStore.set(!$sponsorBlockStore)}
type="checkbox"
/>
<span></span>
</label>
</nav>
{#each sponsorCategories as sponsor}
<div class="field middle-align no-margin">
<nav class="no-padding">
<div class="max">
<p>{sponsor.name}</p>
</div>
<label class="switch">
<input
type="checkbox"
checked={sponsorCategoriesList.includes(sponsor.category)}
on:click={() => toggleSponsor(sponsor.category)}
/>
<span></span>
</label>
</nav>
</div>
{/each}
</div>
<div class="settings">
<h6>{$_('layout.deArrow.title')}</h6>
<form on:submit|preventDefault={() => deArrowInstanceStore.set(deArrowUrl)}>
<nav>
<div class="field label border max">
<input bind:value={deArrowUrl} name="dearrow-instance" type="text" />
<label for="dearrow-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<form on:submit|preventDefault={() => deArrowThumbnailInstanceStore.set(deArrowThumbnailUrl)}>
<nav>
<div class="field label border max">
<input bind:value={deArrowThumbnailUrl} name="dearrow-thumbnail-instance" type="text" />
<label for="dearrow-thumbnail-instance">{$_('layout.deArrow.thumbnailInstanceUrl')}</label
>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
bind:checked={$deArrowEnabledStore}
on:click={() => deArrowEnabledStore.set(!$deArrowEnabledStore)}
type="checkbox"
/>
<span></span>
</label>
</nav>
</div>
<div class="settings">
<h6>{$_('layout.bookmarklet')}</h6>
<button
class="no-margin"
on:click={async () => await navigator.clipboard.writeText(bookmarkletSaveToUrl())}
>{$_('copyUrl')}</button
>
</div>
</dialog>
<style>
.settings h6 {
margin: 1em 0 0.3em 0;
}
form {
margin: 1em 0;
}
</style>
+146
View File
@@ -0,0 +1,146 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { peerJsOptions, removeWindowQueryFlag, setWindowQueryFlag } from '$lib/misc';
import type { PlayerEvents } from '$lib/player';
import 'beercss';
import 'material-dynamic-colors';
import type { DataConnection } from 'peerjs';
import Peer from 'peerjs';
import { onDestroy, onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import { syncPartyConnectionsStore, syncPartyPeerStore } from '../store';
function changeVideoEvent(conn: DataConnection) {
conn.on('data', (data) => {
const events = data as PlayerEvents;
const currentUrl = get(page).url;
events.events.forEach((event) => {
if (event.type === 'change-video' && event.videoId) {
currentUrl.pathname = `/watch/${event.videoId}`;
goto(currentUrl);
}
});
});
}
async function startWatchSync() {
if ($syncPartyPeerStore) {
$syncPartyPeerStore.destroy();
syncPartyPeerStore.set(null);
removeWindowQueryFlag('sync');
return;
}
const peerId = crypto.randomUUID();
setWindowQueryFlag('sync', peerId);
$syncPartyPeerStore = new Peer(peerId, peerJsOptions());
if ($syncPartyPeerStore) {
$syncPartyPeerStore.on('connection', (conn) => {
conn.on('open', () => {
ui('#sync-party-connection-join');
if ($page.url.pathname.startsWith('/watch')) {
const paths = $page.url.pathname.split('/');
if (paths.length > 2) {
conn.send({
events: [
{
type: 'change-video',
videoId: paths[2]
}
]
} as PlayerEvents);
}
}
changeVideoEvent(conn);
syncPartyConnectionsStore.set([...($syncPartyConnectionsStore || []), conn]);
});
conn.on('close', () => {
ui('#sync-party-connection-left');
});
});
}
}
onMount(async () => {
const currentUrl = get(page).url;
const syncId = currentUrl.searchParams.get('sync');
if (syncId) {
$syncPartyPeerStore = new Peer(crypto.randomUUID(), peerJsOptions());
$syncPartyPeerStore.on('open', () => {
if (!$syncPartyPeerStore) return;
const conn = $syncPartyPeerStore.connect(syncId);
syncPartyConnectionsStore.set([...($syncPartyConnectionsStore || []), conn]);
changeVideoEvent(conn);
});
$syncPartyPeerStore.on('disconnected', () => {
syncPartyPeerStore.set(null);
syncPartyConnectionsStore.set(null);
});
}
});
onDestroy(() => {
if ($syncPartyPeerStore) {
$syncPartyPeerStore.destroy();
$syncPartyPeerStore = null;
}
});
</script>
<dialog id="sync-party">
<h6>{$_('layout.syncParty')}</h6>
<p>{$_('layout.syncPartyWarning')}</p>
{#if $syncPartyPeerStore}
<nav>
<div class="field label border max">
<input
name="sync-share"
readonly
value={`${import.meta.env.VITE_DEFAULT_FRONTEND_URL}?sync=${$syncPartyPeerStore.id}`}
type="text"
/>
<label class="active" for="sync-share">Share URL</label>
</div>
<button
on:click={async () => {
await navigator.clipboard.writeText(
`${import.meta.env.VITE_DEFAULT_FRONTEND_URL}?sync=${$syncPartyPeerStore.id}`
);
}}
class="square round"
>
<i>content_copy</i>
</button>
</nav>
{/if}
<div class="space"></div>
<button
class="no-margin"
on:click={startWatchSync}
data-ui={`${$syncPartyPeerStore ? '#sync-party' : ''}`}
>{#if $syncPartyPeerStore}
{$_('layout.endSyncParty')}
{:else}
{$_('layout.startSyncParty')}
{/if}
</button>
</dialog>
<div class="snackbar" id="sync-party-connection-join">
<i>person_add</i>
<span>{$_('syncParty.userJoined')}</span>
</div>
<div class="snackbar" id="sync-party-connection-left">
<i>person_remove</i>
<span>{$_('syncParty.userLeft')}</span>
</div>
+9 -587
View File
@@ -1,20 +1,18 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { navigating, page } from '$app/stores';
import { navigating } from '$app/stores';
import { getFeed } from '$lib/Api/index';
import type { Notification } from '$lib/Api/model';
import Logo from '$lib/Logo.svelte';
import PageLoading from '$lib/PageLoading.svelte';
import Search from '$lib/Search.svelte';
import Settings from '$lib/Settings.svelte';
import SyncParty from '$lib/SyncParty.svelte';
import Thumbnail from '$lib/Thumbnail.svelte';
import { bookmarkletLoadFromUrl, bookmarkletSaveToUrl } from '$lib/bookmarklet';
import { peerJsOptions, removeWindowQueryFlag, setWindowQueryFlag } from '$lib/misc';
import type { PlayerEvents } from '$lib/player';
import { bookmarkletLoadFromUrl } from '$lib/bookmarklet';
import 'beercss';
import 'material-dynamic-colors';
import type { DataConnection } from 'peerjs';
import Peer from 'peerjs';
import { onDestroy, onMount } from 'svelte';
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import { pwaInfo } from 'virtual:pwa-info';
@@ -22,28 +20,7 @@
activePageStore,
authStore,
darkModeStore,
deArrowEnabledStore,
deArrowInstanceStore,
deArrowThumbnailInstanceStore,
interfacePreviewVideoOnHoverStore,
interfaceSearchSuggestionsStore,
playerAlwaysLoopStore,
playerAutoPlayStore,
playerAutoplayNextByDefaultStore,
playerDashStore,
playerListenByDefaultStore,
playerProxyVideosStore,
playerSavePlaybackPositionStore,
playerTheatreModeByDefaultStore,
returnYTDislikesInstanceStore,
returnYtDislikesStore,
sponsorBlockCategoriesStore,
sponsorBlockStore,
sponsorBlockUrlStore,
syncPartyConnectionsStore,
syncPartyPeerStore,
synciousInstanceStore,
synciousStore,
themeColorStore
} from '../store';
@@ -52,9 +29,6 @@
let currentPage: string | null = '';
activePageStore.subscribe((page) => (currentPage = page));
let sponsorCategoriesList: string[] = [];
sponsorBlockCategoriesStore.subscribe((value) => (sponsorCategoriesList = value));
let isLoggedIn = false;
authStore.subscribe((value) => {
isLoggedIn = value !== null;
@@ -62,12 +36,6 @@
let notifications: Notification[] = [];
let sponsorBlockInstance = get(sponsorBlockUrlStore);
let synciousInstance = get(synciousInstanceStore);
let returnYTInstance = get(returnYTDislikesInstanceStore);
let deArrowUrl = get(deArrowInstanceStore);
let deArrowThumbnailUrl = get(deArrowThumbnailInstanceStore);
const pages = [
{
icon: 'home',
@@ -101,99 +69,6 @@
}
];
const sponsorCategories = [
{ name: $_('layout.sponsors.sponsor'), category: 'sponsor' },
{ name: $_('layout.sponsors.unpaidSelfPromotion'), category: 'selfpromo' },
{ name: $_('layout.sponsors.interactionReminder'), category: 'interaction' },
{ name: $_('layout.sponsors.intermissionIntroAnimation'), category: 'intro' },
{ name: $_('layout.sponsors.credits'), category: 'outro' },
{ name: $_('layout.sponsors.preViewRecapHook'), category: 'preview' },
{ name: $_('layout.sponsors.tangentJokes'), category: 'filler' }
];
function changeVideoEvent(conn: DataConnection) {
conn.on('data', (data) => {
const events = data as PlayerEvents;
const currentUrl = get(page).url;
events.events.forEach((event) => {
if (event.type === 'change-video' && event.videoId) {
currentUrl.pathname = `/watch/${event.videoId}`;
goto(currentUrl);
}
});
});
}
async function startWatchSync() {
if ($syncPartyPeerStore) {
$syncPartyPeerStore.destroy();
syncPartyPeerStore.set(null);
removeWindowQueryFlag('sync');
return;
}
const peerId = crypto.randomUUID();
setWindowQueryFlag('sync', peerId);
$syncPartyPeerStore = new Peer(peerId, peerJsOptions());
if ($syncPartyPeerStore) {
$syncPartyPeerStore.on('connection', (conn) => {
conn.on('open', () => {
ui('#sync-party-connection-join');
if ($page.url.pathname.startsWith('/watch')) {
const paths = $page.url.pathname.split('/');
if (paths.length > 2) {
conn.send({
events: [
{
type: 'change-video',
videoId: paths[2]
}
]
} as PlayerEvents);
}
}
changeVideoEvent(conn);
syncPartyConnectionsStore.set([...($syncPartyConnectionsStore || []), conn]);
});
conn.on('close', () => {
ui('#sync-party-connection-left');
});
});
}
}
function toggleSponsor(category: string) {
if (sponsorCategoriesList.includes(category)) {
sponsorBlockCategoriesStore.set(sponsorCategoriesList.filter((value) => value !== category));
} else {
sponsorCategoriesList.push(category);
sponsorBlockCategoriesStore.set(sponsorCategoriesList);
}
}
async function setColor(color: any) {
const target = color.target;
const hex = (target as { value: string }).value;
await ui('theme', hex);
themeColorStore.set(hex);
}
function toggleDarkMode() {
const isDark = get(darkModeStore);
if (isDark) {
ui('mode', 'light');
darkModeStore.set(false);
} else {
ui('mode', 'dark');
darkModeStore.set(true);
}
}
darkModeStore.subscribe((isDark) => {
if (isDark) {
ui('mode', 'dark');
@@ -253,32 +128,6 @@
if (isLoggedIn) {
loadNotifications().catch(() => authStore.set(null));
}
const currentUrl = get(page).url;
const syncId = currentUrl.searchParams.get('sync');
if (syncId) {
$syncPartyPeerStore = new Peer(crypto.randomUUID(), peerJsOptions());
$syncPartyPeerStore.on('open', () => {
if (!$syncPartyPeerStore) return;
const conn = $syncPartyPeerStore.connect(syncId);
syncPartyConnectionsStore.set([...($syncPartyConnectionsStore || []), conn]);
changeVideoEvent(conn);
});
$syncPartyPeerStore.on('disconnected', () => {
syncPartyPeerStore.set(null);
syncPartyConnectionsStore.set(null);
});
}
});
onDestroy(() => {
if ($syncPartyPeerStore) {
$syncPartyPeerStore.destroy();
$syncPartyPeerStore = null;
}
});
$: webManifestLink = pwaInfo ? pwaInfo.webManifest.linkTag : '';
@@ -315,7 +164,7 @@
>
<Logo classes="m l" />
<h6 class="m l">Materialious</h6>
<h6 class="l">Materialious</h6>
<div class="max m l"></div>
@@ -330,7 +179,7 @@
{#if mobileSearchShow}
<Search on:searchCancelled={() => (mobileSearchShow = false)} />
{:else}
<button data-ui="#sync-party" class="m l circle large transparent">
<button data-ui="#sync-party" class="circle large transparent">
<i class:primary-text={$syncPartyPeerStore}>group</i>
<div class="tooltip bottom">{$_('layout.syncParty')}</div>
</button>
@@ -370,373 +219,7 @@
{/each}
</nav>
<dialog class="right" id="dialog-settings">
<nav>
<h4 class="max">{$_('layout.settings')}</h4>
<button class="circle transparent" data-ui="#dialog-settings"><i>close</i></button>
</nav>
<p>{$_('layout.customize')} Materialious</p>
<div class="settings">
<h6>{$_('layout.theme.theme')}</h6>
<button on:click={toggleDarkMode} class="no-margin">
{#if !$darkModeStore}
<i>dark_mode</i>
<span>{$_('layout.theme.darkMode')}</span>
{:else}
<i>light_mode</i>
<span>{$_('layout.theme.lightMode')}</span>
{/if}
</button>
<button>
<i>palette</i>
<span>{$_('layout.theme.color')}</span>
<input on:change={setColor} type="color" />
</button>
</div>
<div class="settings">
<h6>Interface</h6>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.searchSuggestions')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$interfaceSearchSuggestionsStore}
on:click={() => interfaceSearchSuggestionsStore.set(!$interfaceSearchSuggestionsStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.previewVideoOnHover')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$interfacePreviewVideoOnHoverStore}
on:click={() =>
interfacePreviewVideoOnHoverStore.set(!$interfacePreviewVideoOnHoverStore)}
/>
<span></span>
</label>
</nav>
</div>
</div>
<div class="settings">
<h6>{$_('layout.dataPreferences.dataPreferences')}</h6>
<p style="width: 240px;">
<a
href={`${import.meta.env.VITE_DEFAULT_INVIDIOUS_INSTANCE}/preferences`}
target="_blank"
rel="noopener noreferrer"
class="link"
>
{$_('layout.dataPreferences.content')}
</a>
</p>
</div>
<div class="settings">
<h6>{$_('layout.player.title')}</h6>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.autoPlay')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerAutoPlayStore}
on:click={() => playerAutoPlayStore.set(!$playerAutoPlayStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.alwaysLoopVideo')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerAlwaysLoopStore}
on:click={() => playerAlwaysLoopStore.set(!$playerAlwaysLoopStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.proxyVideos')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerProxyVideosStore}
on:click={() => playerProxyVideosStore.set(!$playerProxyVideosStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.savePlaybackPosition')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerSavePlaybackPositionStore}
on:click={() => playerSavePlaybackPositionStore.set(!$playerSavePlaybackPositionStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.listenByDefault')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerListenByDefaultStore}
on:click={() => playerListenByDefaultStore.set(!$playerListenByDefaultStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin m l">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.theatreModeByDefault')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerTheatreModeByDefaultStore}
on:click={() => playerTheatreModeByDefaultStore.set(!$playerTheatreModeByDefaultStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.autoPlayNextByDefault')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerAutoplayNextByDefaultStore}
on:click={() =>
playerAutoplayNextByDefaultStore.set(!$playerAutoplayNextByDefaultStore)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>{$_('layout.player.dash')}</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerDashStore}
on:click={() => playerDashStore.set(!$playerDashStore)}
/>
<span></span>
</label>
</nav>
</div>
</div>
<div class="settings">
<h6>Return YT Dislikes</h6>
<form on:submit|preventDefault={() => returnYTDislikesInstanceStore.set(returnYTInstance)}>
<nav>
<div class="field label border max">
<input bind:value={returnYTInstance} name="returnyt-instance" type="text" />
<label for="returnyt-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
bind:checked={$returnYtDislikesStore}
on:click={() => returnYtDislikesStore.set(!$returnYtDislikesStore)}
type="checkbox"
/>
<span></span>
</label>
</nav>
</div>
<div class="settings">
<h6>Syncious</h6>
<form on:submit|preventDefault={() => synciousInstanceStore.set(synciousInstance)}>
<nav>
<div class="field label border max">
<input bind:value={synciousInstance} name="syncious-instance" type="text" />
<label for="syncious-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
bind:checked={$synciousStore}
on:click={() => synciousStore.set(!$synciousStore)}
type="checkbox"
/>
<span></span>
</label>
</nav>
</div>
<div class="settings">
<h6>Sponsorblock</h6>
<form on:submit|preventDefault={() => sponsorBlockUrlStore.set(sponsorBlockInstance)}>
<nav>
<div class="field label border max">
<input bind:value={sponsorBlockInstance} name="sponsorblock-instance" type="text" />
<label for="sponsorblock-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
bind:checked={$sponsorBlockStore}
on:click={() => sponsorBlockStore.set(!$sponsorBlockStore)}
type="checkbox"
/>
<span></span>
</label>
</nav>
{#each sponsorCategories as sponsor}
<div class="field middle-align no-margin">
<nav class="no-padding">
<div class="max">
<p>{sponsor.name}</p>
</div>
<label class="switch">
<input
type="checkbox"
checked={sponsorCategoriesList.includes(sponsor.category)}
on:click={() => toggleSponsor(sponsor.category)}
/>
<span></span>
</label>
</nav>
</div>
{/each}
</div>
<div class="settings">
<h6>{$_('layout.deArrow.title')}</h6>
<form on:submit|preventDefault={() => deArrowInstanceStore.set(deArrowUrl)}>
<nav>
<div class="field label border max">
<input bind:value={deArrowUrl} name="dearrow-instance" type="text" />
<label for="dearrow-instance">{$_('layout.instanceUrl')}</label>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<form on:submit|preventDefault={() => deArrowThumbnailInstanceStore.set(deArrowThumbnailUrl)}>
<nav>
<div class="field label border max">
<input bind:value={deArrowThumbnailUrl} name="dearrow-thumbnail-instance" type="text" />
<label for="dearrow-thumbnail-instance">{$_('layout.deArrow.thumbnailInstanceUrl')}</label
>
</div>
<button class="square round">
<i>done</i>
</button>
</nav>
</form>
<nav class="no-padding">
<div class="max">
<p>{$_('enabled')}</p>
</div>
<label class="switch">
<input
bind:checked={$deArrowEnabledStore}
on:click={() => deArrowEnabledStore.set(!$deArrowEnabledStore)}
type="checkbox"
/>
<span></span>
</label>
</nav>
</div>
<div class="settings">
<h6>{$_('layout.bookmarklet')}</h6>
<button
class="no-margin"
on:click={async () => await navigator.clipboard.writeText(bookmarkletSaveToUrl())}
>{$_('copyUrl')}</button
>
</div>
</dialog>
<Settings />
<dialog class="right" id="dialog-notifications">
<nav>
@@ -780,54 +263,7 @@
{/each}
</dialog>
<dialog id="sync-party">
<h6>{$_('layout.syncParty')}</h6>
<p>{$_('layout.syncPartyWarning')}</p>
{#if $syncPartyPeerStore}
<nav>
<div class="field label border max">
<input
name="sync-share"
readonly
value={`${import.meta.env.VITE_DEFAULT_FRONTEND_URL}?sync=${$syncPartyPeerStore.id}`}
type="text"
/>
<label class="active" for="sync-share">Share URL</label>
</div>
<button
on:click={async () => {
await navigator.clipboard.writeText(
`${import.meta.env.VITE_DEFAULT_FRONTEND_URL}?sync=${$syncPartyPeerStore.id}`
);
}}
class="square round"
>
<i>content_copy</i>
</button>
</nav>
{/if}
<div class="space"></div>
<button
class="no-margin"
on:click={startWatchSync}
data-ui={`${$syncPartyPeerStore ? '#sync-party' : ''}`}
>{#if $syncPartyPeerStore}
{$_('layout.endSyncParty')}
{:else}
{$_('layout.startSyncParty')}
{/if}
</button>
</dialog>
<div class="snackbar" id="sync-party-connection-join">
<i>person_add</i>
<span>{$_('syncParty.userJoined')}</span>
</div>
<div class="snackbar" id="sync-party-connection-left">
<i>person_remove</i>
<span>{$_('syncParty.userLeft')}</span>
</div>
<SyncParty />
<main class="responsive max root">
{#if $navigating}
@@ -841,18 +277,4 @@
nav.left a {
font-size: 0.8em;
}
.settings h6 {
margin: 1em 0 0.3em 0;
}
form {
margin: 1em 0;
}
@media screen and (max-width: 650px) {
dialog.right {
width: 100%;
}
}
</style>
+9 -3
View File
@@ -31,6 +31,11 @@
display: none !important;
}
main.root {
max-height: 100vh;
overflow-y: scroll;
}
@media screen and (max-width: 580px) {
main {
padding-left: 0.1em !important;
@@ -38,7 +43,8 @@
}
}
main.root {
max-height: 100vh;
overflow-y: scroll;
@media screen and (max-width: 650px) {
dialog.right {
width: 100% !important;
}
}