feat: Local settings
This commit is contained in:
@@ -1,18 +1,22 @@
|
||||
<script lang="ts">
|
||||
import classNames from 'classnames';
|
||||
import { localSettings } from '../stores/localstorage.store';
|
||||
|
||||
export let hasFocus: boolean;
|
||||
let enabled = true;
|
||||
localSettings.subscribe((v) => (enabled = v.useCssTransitions));
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={classNames(
|
||||
'relative transition-all',
|
||||
'relative',
|
||||
{
|
||||
'scale-105': hasFocus
|
||||
// 'transition-all': enabled
|
||||
},
|
||||
$$restProps.class
|
||||
)}
|
||||
style="transition: transform 200ms;"
|
||||
style={enabled ? 'transition: transform 200ms;' : ''}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
on:enter
|
||||
class={classNames(
|
||||
'relative flex flex-shrink-0 rounded-xl group hover:text-inherit overflow-hidden text-left cursor-pointer',
|
||||
'transition-transform selectable',
|
||||
'selectable',
|
||||
{
|
||||
'aspect-video': orientation === 'landscape',
|
||||
'aspect-[2/3]': orientation === 'portrait',
|
||||
@@ -63,54 +63,51 @@
|
||||
src={backdropUrl}
|
||||
class="absolute inset-0 group-hover:scale-105 transition-transform"
|
||||
/>
|
||||
<div
|
||||
class="absolute inset-0 opacity-0 group-hover:opacity-30 transition-opacity bg-black"
|
||||
style="filter: blur(50px); transform: scale(3);"
|
||||
>
|
||||
<!-- This is the tinted and blurred hover overlay -->
|
||||
<LazyImg src={backdropUrl} />
|
||||
</div>
|
||||
<!-- <div
|
||||
style={`background-image: url(${backdropUrl}); background-size: cover; background-position: center; filter: blur(50px); transform: scale(3);`}
|
||||
class="absolute inset-0 opacity-0 group-hover:opacity-30 transition-opacity bg-black"
|
||||
/> -->
|
||||
<div
|
||||
class={classNames(
|
||||
'flex-1 flex flex-col justify-between bg-black bg-opacity-40 opacity-0 group-hover:opacity-100 transition-opacity z-[1]',
|
||||
{
|
||||
'py-2 px-3': true
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div class="flex justify-self-start justify-between">
|
||||
<slot name="top-left">
|
||||
<div>
|
||||
<h1 class="text-zinc-100 font-bold line-clamp-2 text-lg">{title}</h1>
|
||||
<h2 class="text-zinc-300 text-sm font-medium line-clamp-2">{subtitle}</h2>
|
||||
</div>
|
||||
</slot>
|
||||
<slot name="top-right">
|
||||
<div />
|
||||
</slot>
|
||||
</div>
|
||||
<div class="flex justify-self-end justify-between">
|
||||
<slot name="bottom-left">
|
||||
<div>
|
||||
{#if rating}
|
||||
<h2 class="flex items-center gap-1.5 text-sm text-zinc-300 font-medium">
|
||||
<Star />{rating.toFixed(1)}
|
||||
</h2>
|
||||
{/if}
|
||||
</div>
|
||||
</slot>
|
||||
<slot name="bottom-right">
|
||||
<div />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div
|
||||
class="absolute inset-0 bg-gradient-to-t from-darken group-hover:opacity-0 transition-opacity z-[1]"
|
||||
/> -->
|
||||
<!-- This is the tinted and blurred hover overlay -->
|
||||
<!-- <div-->
|
||||
<!-- class="absolute inset-0 opacity-0 group-hover:opacity-30 transition-opacity bg-black"-->
|
||||
<!-- style="filter: blur(50px); transform: scale(3);"-->
|
||||
<!-- >-->
|
||||
<!-- <LazyImg src={backdropUrl} />-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- Mouse hover details -->
|
||||
<!-- <div-->
|
||||
<!-- class={classNames(-->
|
||||
<!-- 'flex-1 flex flex-col justify-between bg-black bg-opacity-40 opacity-0 group-hover:opacity-100 transition-opacity z-[1]',-->
|
||||
<!-- {-->
|
||||
<!-- 'py-2 px-3': true-->
|
||||
<!-- }-->
|
||||
<!-- )}-->
|
||||
<!-- >-->
|
||||
<!-- <div class="flex justify-self-start justify-between">-->
|
||||
<!-- <slot name="top-left">-->
|
||||
<!-- <div>-->
|
||||
<!-- <h1 class="text-zinc-100 font-bold line-clamp-2 text-lg">{title}</h1>-->
|
||||
<!-- <h2 class="text-zinc-300 text-sm font-medium line-clamp-2">{subtitle}</h2>-->
|
||||
<!-- </div>-->
|
||||
<!-- </slot>-->
|
||||
<!-- <slot name="top-right">-->
|
||||
<!-- <div />-->
|
||||
<!-- </slot>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="flex justify-self-end justify-between">-->
|
||||
<!-- <slot name="bottom-left">-->
|
||||
<!-- <div>-->
|
||||
<!-- {#if rating}-->
|
||||
<!-- <h2 class="flex items-center gap-1.5 text-sm text-zinc-300 font-medium">-->
|
||||
<!-- <Star />{rating.toFixed(1)}-->
|
||||
<!-- </h2>-->
|
||||
<!-- {/if}-->
|
||||
<!-- </div>-->
|
||||
<!-- </slot>-->
|
||||
<!-- <slot name="bottom-right">-->
|
||||
<!-- <div />-->
|
||||
<!-- </slot>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- Play Button -->
|
||||
{#if jellyfinId}
|
||||
<div class="absolute inset-0 flex items-center justify-center z-[1]">
|
||||
<PlayButton
|
||||
|
||||
36
src/lib/components/Toggle.svelte
Normal file
36
src/lib/components/Toggle.svelte
Normal file
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import Container from '../../Container.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: boolean;
|
||||
}>();
|
||||
|
||||
export let checked: boolean;
|
||||
let input: HTMLInputElement;
|
||||
|
||||
const handleChange = (e: Event) => {
|
||||
checked = e.target?.checked;
|
||||
dispatch('change', e.target?.checked);
|
||||
};
|
||||
</script>
|
||||
|
||||
<Container
|
||||
class="relative inline-flex items-center cursor-pointer w-min h-min"
|
||||
on:enter={(e) => {
|
||||
e.detail.options.setFocusedElement = input;
|
||||
}}
|
||||
on:clickOrSelect={() => input?.click()}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked
|
||||
class="sr-only peer"
|
||||
bind:this={input}
|
||||
on:input={handleChange}
|
||||
/>
|
||||
<div
|
||||
class="w-11 h-6 rounded-full peer bg-zinc-600 bg-opacity-20 peer-checked:bg-amber-200 peer-checked:bg-opacity-30 peer-selectable
|
||||
after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px]"
|
||||
/>
|
||||
</Container>
|
||||
@@ -4,34 +4,50 @@
|
||||
import Button from '../components/Button.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { isTizen } from '../utils/browser-detection';
|
||||
import Toggle from '../components/Toggle.svelte';
|
||||
import { localSettings } from '../stores/localstorage.store';
|
||||
|
||||
let lastKeyCode = 0;
|
||||
let lastKey = '';
|
||||
let tizenMediaKey = '';
|
||||
|
||||
onMount(() => {
|
||||
if (isTizen()) {
|
||||
var myMediaKeyChangeListener = {
|
||||
onpressed: function (key: string) {
|
||||
console.log('Pressed key: ' + key);
|
||||
tizenMediaKey = key;
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
tizen.tvinputdevice.registerKey('MediaPlayPause');
|
||||
(tizen as any).mediakey.setMediaKeyEventListener(myMediaKeyChangeListener);
|
||||
}
|
||||
});
|
||||
// onMount(() => {
|
||||
// if (isTizen()) {
|
||||
// const myMediaKeyChangeListener = {
|
||||
// onpressed: function (key: string) {
|
||||
// console.log('Pressed key: ' + key);
|
||||
// tizenMediaKey = key;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // eslint-disable-next-line no-undef
|
||||
// tizen?.tvinputdevice?.registerKey?.('MediaPlayPause');
|
||||
// (tizen as any)?.mediakey?.setMediaKeyEventListener?.(myMediaKeyChangeListener);
|
||||
// }
|
||||
// });
|
||||
</script>
|
||||
|
||||
<Container class="pl-24 flex flex-col items-start" focusOnMount>
|
||||
User agent: {window.navigator.userAgent}
|
||||
User agent: {window?.navigator?.userAgent}
|
||||
<div>Last key code: {lastKeyCode}</div>
|
||||
<div>Last key: {lastKey}</div>
|
||||
{#if tizenMediaKey}
|
||||
<div>Tizen media key: {tizenMediaKey}</div>
|
||||
{/if}
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="mr-2">Animate scrolling</label>
|
||||
<Toggle
|
||||
checked={$localSettings.animateScrolling}
|
||||
on:change={({ detail }) => localSettings.update((p) => ({ ...p, animateScrolling: detail }))}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="mr-2">Use CSS Transitions</label>
|
||||
<Toggle
|
||||
checked={$localSettings.useCssTransitions}
|
||||
on:change={({ detail }) => localSettings.update((p) => ({ ...p, useCssTransitions: detail }))}
|
||||
/>
|
||||
</div>
|
||||
<Button on:clickOrSelect={appState.logOut} class="hover:bg-red-500">Log Out</Button>
|
||||
</Container>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { derived, get, type Readable, type Writable, writable } from 'svelte/store';
|
||||
import { getScrollParent } from './utils';
|
||||
import { localSettings } from './stores/localstorage.store';
|
||||
|
||||
export type Registerer = (htmlElement: HTMLElement) => { destroy: () => void };
|
||||
export type Registrar = (e: CustomEvent<Selectable>) => () => void;
|
||||
@@ -727,6 +728,8 @@ export const scrollElementIntoView = (htmlElement: HTMLElement, offsets: Offsets
|
||||
offsets.right = offsets.all;
|
||||
}
|
||||
|
||||
const scrollBehavior: ScrollBehavior = get(localSettings).animateScrolling ? 'smooth' : 'instant';
|
||||
|
||||
const boundingRect = htmlElement.getBoundingClientRect();
|
||||
const verticalParent = getScrollParent(htmlElement, 'vertical');
|
||||
const horizontalParent = getScrollParent(htmlElement, 'horizontal');
|
||||
@@ -763,7 +766,7 @@ export const scrollElementIntoView = (htmlElement: HTMLElement, offsets: Offsets
|
||||
|
||||
if (top !== -1) {
|
||||
verticalParent.scrollTo({
|
||||
behavior: 'smooth',
|
||||
behavior: scrollBehavior,
|
||||
top
|
||||
});
|
||||
}
|
||||
@@ -800,7 +803,7 @@ export const scrollElementIntoView = (htmlElement: HTMLElement, offsets: Offsets
|
||||
|
||||
if (left !== -1) {
|
||||
horizontalParent.scrollTo({
|
||||
behavior: 'smooth',
|
||||
behavior: scrollBehavior,
|
||||
left
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,3 +29,10 @@ export const videoPlayerSettings = createLocalStorageStore<{
|
||||
muted: false,
|
||||
volume: 1
|
||||
});
|
||||
export const localSettings = createLocalStorageStore<{
|
||||
animateScrolling: boolean;
|
||||
useCssTransitions: boolean;
|
||||
}>('settings', {
|
||||
animateScrolling: true,
|
||||
useCssTransitions: true
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user