feat: Local settings

This commit is contained in:
Aleksi Lassila
2024-04-22 01:59:50 +03:00
parent a0ddf08bf3
commit 423d8d9af4
6 changed files with 131 additions and 68 deletions

View File

@@ -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 />

View File

@@ -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

View 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>

View File

@@ -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>

View File

@@ -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
});
}

View File

@@ -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
});