Compare commits

..

1 Commits

Author SHA1 Message Date
Jason Rasmussen
d4ad523eb3 refactor(web): user app settings (#25177) 2026-01-10 07:58:50 -05:00
5 changed files with 87 additions and 118 deletions

View File

@@ -8,7 +8,6 @@
import AddToStackAction from '$lib/components/asset-viewer/actions/add-to-stack-action.svelte';
import ArchiveAction from '$lib/components/asset-viewer/actions/archive-action.svelte';
import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte';
import EditAction from '$lib/components/asset-viewer/actions/edit-action.svelte';
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
import RatingAction from '$lib/components/asset-viewer/actions/rating-action.svelte';
import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/remove-asset-from-stack.svelte';
@@ -21,7 +20,7 @@
import UnstackAction from '$lib/components/asset-viewer/actions/unstack-action.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { AppRoute, ProjectionType } from '$lib/constants';
import { AppRoute } from '$lib/constants';
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { getGlobalActions } from '$lib/services/app.service';
import { getAssetActions, handleReplaceAsset } from '$lib/services/asset.service';
@@ -73,7 +72,7 @@
onUndoDelete?: OnUndoDelete;
onRunJob: (name: AssetJobName) => void;
onPlaySlideshow: () => void;
onEdit: () => void;
// onEdit: () => void;
onClose?: () => void;
playOriginalVideo: boolean;
setPlayOriginalVideo: (value: boolean) => void;
@@ -93,7 +92,7 @@
onRunJob,
onPlaySlideshow,
onClose,
onEdit,
// onEdit,
playOriginalVideo = false,
setPlayOriginalVideo,
}: Props = $props();
@@ -116,17 +115,18 @@
const { Share, Download, SharedLinkDownload, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info } =
$derived(getAssetActions($t, asset));
let showEditorButton = $derived(
isOwner &&
asset.type === AssetTypeEnum.Image &&
!(
asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR ||
(asset.originalPath && asset.originalPath.toLowerCase().endsWith('.insp'))
) &&
!(asset.originalPath && asset.originalPath.toLowerCase().endsWith('.gif')) &&
!(asset.originalPath && asset.originalPath.toLowerCase().endsWith('.svg')) &&
!asset.livePhotoVideoId,
);
// TODO: Enable when edits are ready for release
// let showEditorButton = $derived(
// isOwner &&
// asset.type === AssetTypeEnum.Image &&
// !(
// asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR ||
// (asset.originalPath && asset.originalPath.toLowerCase().endsWith('.insp'))
// ) &&
// !(asset.originalPath && asset.originalPath.toLowerCase().endsWith('.gif')) &&
// !(asset.originalPath && asset.originalPath.toLowerCase().endsWith('.svg')) &&
// !asset.livePhotoVideoId,
// );
</script>
<CommandPaletteDefaultProvider
@@ -179,9 +179,9 @@
<RatingAction {asset} {onAction} />
{/if}
{#if showEditorButton}
<!-- {#if showEditorButton}
<EditAction onAction={onEdit} />
{/if}
{/if} -->
{#if isOwner}
<DeleteAction {asset} {onAction} {preAction} {onUndoDelete} />

View File

@@ -255,12 +255,12 @@
});
};
const showEditor = () => {
if (assetViewerManager.isShowActivityPanel) {
assetViewerManager.isShowActivityPanel = false;
}
isShowEditor = !isShowEditor;
};
// const showEditor = () => {
// if (assetViewerManager.isShowActivityPanel) {
// assetViewerManager.isShowActivityPanel = false;
// }
// isShowEditor = !isShowEditor;
// };
const handleRunJob = async (name: AssetJobName) => {
try {
@@ -431,7 +431,6 @@
onCopyImage={copyImage}
preAction={handlePreAction}
onAction={handleAction}
onEdit={showEditor}
{onUndoDelete}
onRunJob={handleRunJob}
onPlaySlideshow={() => ($slideshowState = SlideshowState.PlaySlideshow)}

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
import { Label, Text } from '@immich/ui';
import type { Snippet } from 'svelte';
import { t } from 'svelte-i18n';
import { quintOut } from 'svelte/easing';
@@ -28,25 +29,21 @@
}: Props = $props();
</script>
<div class="grid grid-cols-2">
<div>
<div class="flex h-6.5 place-items-center gap-1">
<label class="font-medium text-primary text-sm" 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>
<div>
<div class="flex h-6.5 place-items-center gap-1">
<Label>{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>
<div class="flex items-center">
<Text size="small" color="muted">{subtitle}</Text>
<div class="flex items-center mt-2 max-w-[300px]">
<Combobox label={title} hideLabel={true} {selectedOption} {options} placeholder={comboboxPlaceholder} {onSelect} />
{@render children?.()}
</div>

View File

@@ -4,6 +4,7 @@
import { defaultLang, langs } from '$lib/constants';
import { lang } from '$lib/stores/preferences.store';
import { getClosestAvailableLocale, langCodes } from '$lib/utils/i18n';
import { Label, Text } from '@immich/ui';
import { locale as i18nLocale, t } from 'svelte-i18n';
interface Props {
@@ -34,16 +35,14 @@
let closestLanguage = $derived(getClosestAvailableLocale([$lang], langCodes));
</script>
<div class={showSettingDescription ? 'grid grid-cols-2' : ''}>
<div class="max-w-[300px]">
{#if showSettingDescription}
<div>
<div class="flex h-6.5 place-items-center gap-1">
<label class="font-medium text-primary text-sm" for={$t('language')}>
{$t('language')}
</label>
<Label>{$t('language')}</Label>
</div>
<p class="text-sm dark:text-immich-dark-fg">{$t('language_setting_description')}</p>
<Text size="small" color="muted">{$t('language_setting_description')}</Text>
</div>
{/if}

View File

@@ -1,7 +1,6 @@
<script lang="ts">
import type { ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
import SettingCombobox from '$lib/components/shared-components/settings/setting-combobox.svelte';
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
import SettingsLanguageSelector from '$lib/components/shared-components/settings/settings-language-selector.svelte';
import { fallbackLocale, locales } from '$lib/constants';
import { themeManager } from '$lib/managers/theme-manager.svelte';
@@ -15,6 +14,7 @@
showDeleteModal,
} from '$lib/stores/preferences.store';
import { createDateFormatter, findLocale } from '$lib/utils';
import { Field, Switch, Text } from '@immich/ui';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
@@ -59,81 +59,55 @@
<section class="my-4">
<div in:fade={{ duration: 500 }}>
<div class="ms-4 mt-4 flex flex-col gap-4">
<div class="ms-4">
<SettingSwitch
title={$t('theme_selection')}
subtitle={$t('theme_selection_description')}
checked={themeManager.theme.system}
onToggle={(isChecked) => themeManager.setSystem(isChecked)}
/>
</div>
<div class="ms-8 mt-4 flex flex-col gap-4">
<Field label={$t('theme_selection')} description={$t('theme_selection_description')}>
<Switch checked={themeManager.theme.system} onCheckedChange={(checked) => themeManager.setSystem(checked)} />
</Field>
<div class="ms-4">
<SettingsLanguageSelector showSettingDescription />
</div>
<SettingsLanguageSelector showSettingDescription />
<Field label={$t('default_locale')} description={$t('default_locale_description')}>
<Switch checked={$locale == 'default'} onCheckedChange={handleToggleLocaleBrowser} />
<Text size="small" class="mt-2">{selectedDate}</Text>
</Field>
<div class="ms-4">
<SettingSwitch
title={$t('default_locale')}
subtitle={$t('default_locale_description')}
checked={$locale == 'default'}
onToggle={handleToggleLocaleBrowser}
>
<p class="mt-2 dark:text-gray-400">{selectedDate}</p>
</SettingSwitch>
</div>
{#if $locale !== 'default'}
<div class="ms-4">
<SettingCombobox
comboboxPlaceholder={$t('searching_locales')}
{selectedOption}
options={getAllLanguages()}
title={$t('custom_locale')}
subtitle={$t('custom_locale_description')}
onSelect={(combobox) => handleLocaleChange(combobox?.value)}
/>
</div>
<SettingCombobox
comboboxPlaceholder={$t('searching_locales')}
{selectedOption}
options={getAllLanguages()}
title={$t('custom_locale')}
subtitle={$t('custom_locale_description')}
onSelect={(combobox) => handleLocaleChange(combobox?.value)}
/>
{/if}
<div class="ms-4">
<SettingSwitch
title={$t('display_original_photos')}
subtitle={$t('display_original_photos_setting_description')}
bind:checked={$alwaysLoadOriginalFile}
/>
</div>
<div class="ms-4">
<SettingSwitch
title={$t('video_hover_setting')}
subtitle={$t('video_hover_setting_description')}
bind:checked={$playVideoThumbnailOnHover}
/>
</div>
<div class="ms-4">
<SettingSwitch
title={$t('setting_video_viewer_auto_play_title')}
subtitle={$t('setting_video_viewer_auto_play_subtitle')}
bind:checked={$autoPlayVideo}
/>
</div>
<div class="ms-4">
<SettingSwitch title={$t('loop_videos')} subtitle={$t('loop_videos_description')} bind:checked={$loopVideo} />
</div>
<div class="ms-4">
<SettingSwitch
title={$t('play_original_video')}
subtitle={$t('play_original_video_setting_description')}
bind:checked={$alwaysLoadOriginalVideo}
/>
</div>
<div class="ms-4">
<SettingSwitch
title={$t('permanent_deletion_warning')}
subtitle={$t('permanent_deletion_warning_setting_description')}
bind:checked={$showDeleteModal}
/>
</div>
<Field label={$t('display_original_photos')} description={$t('display_original_photos_setting_description')}>
<Switch bind:checked={$alwaysLoadOriginalFile} />
</Field>
<Field label={$t('video_hover_setting')} description={$t('video_hover_setting_description')}>
<Switch bind:checked={$playVideoThumbnailOnHover} />
</Field>
<Field
label={$t('setting_video_viewer_auto_play_title')}
description={$t('setting_video_viewer_auto_play_subtitle')}
>
<Switch bind:checked={$autoPlayVideo} />
</Field>
<Field label={$t('loop_videos')} description={$t('loop_videos_description')}>
<Switch bind:checked={$loopVideo} />
</Field>
<Field label={$t('play_original_video')} description={$t('play_original_video_setting_description')}>
<Switch bind:checked={$alwaysLoadOriginalVideo} />
</Field>
<Field label={$t('permanent_deletion_warning')} description={$t('permanent_deletion_warning_setting_description')}
><Switch bind:checked={$showDeleteModal} />
</Field>
</div>
</div>
</section>