mirror of
https://github.com/immich-app/immich.git
synced 2026-09-30 13:23:21 +08:00
refactor(web): use ui's Select and remove old settings dropdown component (#31841)
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Dropdown, { type RenderedOption } from '$lib/elements/Dropdown.svelte';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { quintOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
options: RenderedOption[];
|
||||
selectedOption: RenderedOption;
|
||||
isEdited?: boolean;
|
||||
disabled?: boolean;
|
||||
onToggle: (option: RenderedOption) => void;
|
||||
children?: Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
title,
|
||||
subtitle = '',
|
||||
options,
|
||||
selectedOption = $bindable(),
|
||||
isEdited = false,
|
||||
disabled = false,
|
||||
onToggle,
|
||||
children,
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex place-items-center justify-between" class:pointer-events-none={disabled} class:opacity-50={disabled}>
|
||||
<div>
|
||||
<div class="flex h-6.5 place-items-center gap-1">
|
||||
<label class="text-sm font-medium" for={title}>
|
||||
{title}
|
||||
</label>
|
||||
{#if isEdited}
|
||||
<div
|
||||
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
|
||||
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
|
||||
>
|
||||
{$t('unsaved_change')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<p class="text-sm dark:text-immich-dark-fg">{subtitle}</p>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
<div class="w-fit">
|
||||
<Dropdown
|
||||
{options}
|
||||
position="bottom-right"
|
||||
hideTextOnSmallScreen={false}
|
||||
bind:selectedOption
|
||||
render={(option) => {
|
||||
return {
|
||||
title: option.title,
|
||||
icon: option.icon,
|
||||
};
|
||||
}}
|
||||
onSelect={onToggle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,16 +0,0 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
id: string;
|
||||
label: string;
|
||||
name: string;
|
||||
value: string;
|
||||
group?: string | undefined;
|
||||
}
|
||||
|
||||
let { id, label, name, value, group = $bindable(undefined) }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="radio" {name} {id} {value} class="focus-visible:ring" bind:group />
|
||||
<label for={id} class="text-sm">{label}</label>
|
||||
</div>
|
||||
@@ -1,16 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { RenderedOption } from '$lib/elements/Dropdown.svelte';
|
||||
import { Field, FormModal, HelperText, NumberInput, Switch } from '@immich/ui';
|
||||
import {
|
||||
mdiArrowDownThin,
|
||||
mdiArrowUpThin,
|
||||
mdiFitToPageOutline,
|
||||
mdiFitToScreenOutline,
|
||||
mdiPanorama,
|
||||
mdiShuffle,
|
||||
} from '@mdi/js';
|
||||
import { Field, FormModal, HelperText, NumberInput, Select, Switch } from '@immich/ui';
|
||||
import { t } from 'svelte-i18n';
|
||||
import SettingDropdown from '../components/shared-components/settings/SettingDropdown.svelte';
|
||||
import {
|
||||
SlideshowLook,
|
||||
SlideshowMetadataOverlayMode,
|
||||
@@ -49,37 +39,28 @@
|
||||
let tempSlideshowShowMetadataOverlay = $state($slideshowShowMetadataOverlay);
|
||||
let tempSlideshowMetadataOverlayMode = $state($slideshowMetadataOverlayMode);
|
||||
|
||||
const navigationOptions: Record<SlideshowNavigation, RenderedOption> = {
|
||||
[SlideshowNavigation.Shuffle]: { icon: mdiShuffle, title: $t('shuffle') },
|
||||
[SlideshowNavigation.AscendingOrder]: { icon: mdiArrowUpThin, title: $t('backward') },
|
||||
[SlideshowNavigation.DescendingOrder]: { icon: mdiArrowDownThin, title: $t('forward') },
|
||||
};
|
||||
const navigationOptions = [
|
||||
{ value: SlideshowNavigation.Shuffle, label: $t('shuffle') },
|
||||
{ value: SlideshowNavigation.AscendingOrder, label: $t('backward') },
|
||||
{ value: SlideshowNavigation.DescendingOrder, label: $t('forward') },
|
||||
];
|
||||
|
||||
const lookOptions: Record<SlideshowLook, RenderedOption> = {
|
||||
[SlideshowLook.Contain]: { icon: mdiFitToScreenOutline, title: $t('contain') },
|
||||
[SlideshowLook.Cover]: { icon: mdiFitToPageOutline, title: $t('cover') },
|
||||
[SlideshowLook.BlurredBackground]: { icon: mdiPanorama, title: $t('blurred_background') },
|
||||
};
|
||||
const lookOptions = [
|
||||
{ value: SlideshowLook.Contain, label: $t('contain') },
|
||||
{ value: SlideshowLook.Cover, label: $t('cover') },
|
||||
{ value: SlideshowLook.BlurredBackground, label: $t('blurred_background') },
|
||||
];
|
||||
|
||||
const metadataOverlayModeOptions: Record<SlideshowMetadataOverlayMode, RenderedOption> = {
|
||||
[SlideshowMetadataOverlayMode.DescriptionOnly]: {
|
||||
title: $t('slideshow_metadata_overlay_mode_description_only'),
|
||||
const metadataOverlayModeOptions = [
|
||||
{
|
||||
value: SlideshowMetadataOverlayMode.DescriptionOnly,
|
||||
label: $t('slideshow_metadata_overlay_mode_description_only'),
|
||||
},
|
||||
[SlideshowMetadataOverlayMode.Full]: {
|
||||
title: $t('slideshow_metadata_overlay_mode_full'),
|
||||
{
|
||||
value: SlideshowMetadataOverlayMode.Full,
|
||||
label: $t('slideshow_metadata_overlay_mode_full'),
|
||||
},
|
||||
};
|
||||
|
||||
const handleToggle = <Type extends SlideshowNavigation | SlideshowLook | SlideshowMetadataOverlayMode>(
|
||||
record: RenderedOption,
|
||||
options: Record<Type, RenderedOption>,
|
||||
): undefined | Type => {
|
||||
for (const [key, option] of Object.entries(options)) {
|
||||
if (option === record) {
|
||||
return key as Type;
|
||||
}
|
||||
}
|
||||
};
|
||||
];
|
||||
|
||||
const onSubmit = () => {
|
||||
$slideshowDelay = tempSlideshowDelay;
|
||||
@@ -98,23 +79,13 @@
|
||||
|
||||
<FormModal size="small" title={$t('slideshow_settings')} {onClose} {onSubmit}>
|
||||
<div class="flex flex-col gap-4">
|
||||
<SettingDropdown
|
||||
title={$t('direction')}
|
||||
options={Object.values(navigationOptions)}
|
||||
selectedOption={navigationOptions[tempSlideshowNavigation]}
|
||||
onToggle={(option) => {
|
||||
tempSlideshowNavigation = handleToggle(option, navigationOptions) || tempSlideshowNavigation;
|
||||
}}
|
||||
/>
|
||||
<Field label={$t('direction')}>
|
||||
<Select bind:value={tempSlideshowNavigation} options={navigationOptions} />
|
||||
</Field>
|
||||
|
||||
<SettingDropdown
|
||||
title={$t('look')}
|
||||
options={Object.values(lookOptions)}
|
||||
selectedOption={lookOptions[tempSlideshowLook]}
|
||||
onToggle={(option) => {
|
||||
tempSlideshowLook = handleToggle(option, lookOptions) || tempSlideshowLook;
|
||||
}}
|
||||
/>
|
||||
<Field label={$t('look')}>
|
||||
<Select bind:value={tempSlideshowLook} options={lookOptions} />
|
||||
</Field>
|
||||
|
||||
<Field label={$t('autoplay_slideshow')}>
|
||||
<Switch bind:checked={tempSlideshowAutoplay} />
|
||||
@@ -136,16 +107,9 @@
|
||||
<Switch bind:checked={tempSlideshowShowMetadataOverlay} />
|
||||
</Field>
|
||||
|
||||
<SettingDropdown
|
||||
title={$t('slideshow_metadata_overlay_mode')}
|
||||
options={Object.values(metadataOverlayModeOptions)}
|
||||
selectedOption={metadataOverlayModeOptions[tempSlideshowMetadataOverlayMode]}
|
||||
disabled={!tempSlideshowShowMetadataOverlay}
|
||||
onToggle={(option) => {
|
||||
tempSlideshowMetadataOverlayMode =
|
||||
handleToggle(option, metadataOverlayModeOptions) || tempSlideshowMetadataOverlayMode;
|
||||
}}
|
||||
/>
|
||||
<Field label={$t('slideshow_metadata_overlay_mode')} disabled={!tempSlideshowShowMetadataOverlay}>
|
||||
<Select bind:value={tempSlideshowMetadataOverlayMode} options={metadataOverlayModeOptions} />
|
||||
</Field>
|
||||
|
||||
<Field label={$t('duration')}>
|
||||
<NumberInput min={1} bind:value={tempSlideshowDelay} />
|
||||
|
||||
Reference in New Issue
Block a user