mirror of
https://github.com/aleksilassila/reiverr.git
synced 2026-04-25 02:05:11 +02:00
feat: library page sections, sorting, view options
fix: tmdb library items not being cached
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
{/if}
|
||||
<AnimatedSelection hasFocus={$hasFocus}>
|
||||
<Container
|
||||
{...$$restProps}
|
||||
{disabled}
|
||||
on:clickOrSelect={() => {
|
||||
if (tmdbId || tvdbId) navigate(`/${type}/${tmdbId || tvdbId}`);
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
/>
|
||||
|
||||
<Container
|
||||
{...$$restProps}
|
||||
direction="grid"
|
||||
gridCols={cols}
|
||||
class={classNames(
|
||||
|
||||
66
src/lib/components/SelectButtonGroup.svelte
Normal file
66
src/lib/components/SelectButtonGroup.svelte
Normal file
@@ -0,0 +1,66 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import Container from './Container.svelte';
|
||||
import classNames from 'classnames';
|
||||
import { Check } from 'radix-icons-svelte';
|
||||
|
||||
type Option = {
|
||||
label: string;
|
||||
value?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export let options: Option[] = [];
|
||||
export let selected: string | undefined = undefined;
|
||||
export let name: string | undefined = undefined;
|
||||
export let style: 'primary' | 'secondary' = 'secondary';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
select: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if name}
|
||||
<h2 class="font-semibold text-sm text-secondary-400 mb-2">{name}</h2>
|
||||
{/if}
|
||||
<Container
|
||||
direction="vertical"
|
||||
class={classNames(
|
||||
'rounded-xl',
|
||||
{
|
||||
'bg-primary-900': style === 'secondary',
|
||||
'bg-secondary-800': style === 'primary'
|
||||
},
|
||||
$$restProps.class
|
||||
)}
|
||||
>
|
||||
{#each options as option, index}
|
||||
{@const first = index === 0}
|
||||
{@const last = index === options.length - 1}
|
||||
{#if !first}
|
||||
<div class="w-0.5 h-full bg-secondary-700" />
|
||||
{/if}
|
||||
<Container
|
||||
on:clickOrSelect={() => dispatch('select', option.value ?? option.label)}
|
||||
let:hasFocus
|
||||
>
|
||||
<div
|
||||
class={classNames('h-12 px-6 py-3 border-2 flex items-center justify-between', {
|
||||
'cursor-pointer hover:border-primary-500': !option.disabled,
|
||||
'cursor-not-allowed pointer-events-none opacity-40': option.disabled,
|
||||
'border-primary-500': hasFocus,
|
||||
'border-transparent': !hasFocus,
|
||||
'rounded-t-xl': first,
|
||||
'rounded-b-xl': last
|
||||
})}
|
||||
>
|
||||
<span class="font-medium">{option.label}</span>
|
||||
{#if selected === option.value}
|
||||
<Check size={24} />
|
||||
{/if}
|
||||
</div>
|
||||
</Container>
|
||||
{/each}
|
||||
</Container>
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type ComponentType } from 'svelte';
|
||||
import { derived, get, writable } from 'svelte/store';
|
||||
import LibraryPage from '../../pages/LibraryPage.svelte';
|
||||
import LibraryPage from '../../pages/LibraryPage/LibraryPage.svelte';
|
||||
import ManagePage from '../../pages/ManagePage/ManagePage.svelte';
|
||||
import MoviesHomePage from '../../pages/MoviesHomePage.svelte';
|
||||
import PageNotFound from '../../pages/PageNotFound.svelte';
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
}>();
|
||||
|
||||
export let checked: boolean;
|
||||
export let label: string | undefined = undefined;
|
||||
let input: HTMLInputElement;
|
||||
|
||||
const handleChange = (e: Event) => {
|
||||
@@ -17,22 +18,32 @@
|
||||
};
|
||||
</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-[3.25rem] h-7 rounded-full bg-secondary-700 peer-checked:bg-primary-500 peer-selectable
|
||||
<div class="flex items-center justify-between">
|
||||
<slot>
|
||||
{#if label}
|
||||
<label class="mr-2">
|
||||
{label}
|
||||
</label>
|
||||
{/if}
|
||||
</slot>
|
||||
|
||||
<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-[3.25rem] h-7 rounded-full bg-secondary-700 peer-checked:bg-primary-500 peer-selectable
|
||||
after:bg-white after:border-gray-300 after:border after:rounded-full after:h-6 after:w-6 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>
|
||||
/>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user