mirror of
https://github.com/immich-app/immich.git
synced 2024-11-24 08:52:28 +02:00
chore(web): unique ID generation (#9932)
* chore(web): automatically generate unique IDs * fix: revert changes to Slider * chore: add test for id store
This commit is contained in:
parent
4e16e2520d
commit
01f52c9021
@ -43,7 +43,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
id="delete-user-confirmation-modal"
|
|
||||||
title="Delete user"
|
title="Delete user"
|
||||||
confirmText={forceDelete ? 'Permanently Delete' : 'Delete'}
|
confirmText={forceDelete ? 'Permanently Delete' : 'Delete'}
|
||||||
onConfirm={handleDeleteUser}
|
onConfirm={handleDeleteUser}
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
id="restore-user-modal"
|
|
||||||
title="Restore user"
|
title="Restore user"
|
||||||
confirmText="Continue"
|
confirmText="Continue"
|
||||||
confirmColor="green"
|
confirmColor="green"
|
||||||
|
@ -42,12 +42,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if isConfirmOpen}
|
{#if isConfirmOpen}
|
||||||
<ConfirmDialog
|
<ConfirmDialog title="Disable login" onCancel={() => (isConfirmOpen = false)} onConfirm={() => handleSave(true)}>
|
||||||
id="disable-login-modal"
|
|
||||||
title="Disable login"
|
|
||||||
onCancel={() => (isConfirmOpen = false)}
|
|
||||||
onConfirm={() => handleSave(true)}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="prompt">
|
<svelte:fragment slot="prompt">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<p>Are you sure you want to disable all login methods? Login will be completely disabled.</p>
|
<p>Are you sure you want to disable all login methods? Login will be completely disabled.</p>
|
||||||
@ -82,13 +77,7 @@
|
|||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch {disabled} title="ENABLE" subtitle="Login with OAuth" bind:checked={config.oauth.enabled} />
|
||||||
id="login-with-oauth"
|
|
||||||
{disabled}
|
|
||||||
title="ENABLE"
|
|
||||||
subtitle="Login with OAuth"
|
|
||||||
bind:checked={config.oauth.enabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{#if config.oauth.enabled}
|
{#if config.oauth.enabled}
|
||||||
<hr />
|
<hr />
|
||||||
@ -177,7 +166,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="auto-register-new-users"
|
|
||||||
title="AUTO REGISTER"
|
title="AUTO REGISTER"
|
||||||
subtitle="Automatically register new users after signing in with OAuth"
|
subtitle="Automatically register new users after signing in with OAuth"
|
||||||
bind:checked={config.oauth.autoRegister}
|
bind:checked={config.oauth.autoRegister}
|
||||||
@ -185,7 +173,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="auto-launch-oauth"
|
|
||||||
title="AUTO LAUNCH"
|
title="AUTO LAUNCH"
|
||||||
subtitle="Start the OAuth login flow automatically upon navigating to the login page"
|
subtitle="Start the OAuth login flow automatically upon navigating to the login page"
|
||||||
disabled={disabled || !config.oauth.enabled}
|
disabled={disabled || !config.oauth.enabled}
|
||||||
@ -193,7 +180,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="mobile-redirect-uri-override"
|
|
||||||
title="MOBILE REDIRECT URI OVERRIDE"
|
title="MOBILE REDIRECT URI OVERRIDE"
|
||||||
subtitle="Enable when 'app.immich:/' is an invalid redirect URI."
|
subtitle="Enable when 'app.immich:/' is an invalid redirect URI."
|
||||||
disabled={disabled || !config.oauth.enabled}
|
disabled={disabled || !config.oauth.enabled}
|
||||||
@ -219,7 +205,6 @@
|
|||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<div class="ml-4 mt-4 flex flex-col">
|
<div class="ml-4 mt-4 flex flex-col">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-password-login"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Login with email and password"
|
subtitle="Login with email and password"
|
||||||
|
@ -234,7 +234,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="two-pass-encoding"
|
|
||||||
title="TWO-PASS ENCODING"
|
title="TWO-PASS ENCODING"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Transcode in two passes to produce better encoded videos. When max bitrate is enabled (required for it to work with H.264 and HEVC), this mode uses a bitrate range based on the max bitrate and ignores CRF. For VP9, CRF can be used if max bitrate is disabled."
|
subtitle="Transcode in two passes to produce better encoded videos. When max bitrate is enabled (required for it to work with H.264 and HEVC), this mode uses a bitrate range based on the max bitrate and ignores CRF. For VP9, CRF can be used if max bitrate is disabled."
|
||||||
@ -277,7 +276,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="hardware-decoding"
|
|
||||||
title="HARDWARE DECODING"
|
title="HARDWARE DECODING"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Applies only to NVENC and RKMPP. Enables end-to-end acceleration instead of only accelerating encoding. May not work on all videos."
|
subtitle="Applies only to NVENC and RKMPP. Enables end-to-end acceleration instead of only accelerating encoding. May not work on all videos."
|
||||||
@ -299,7 +297,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="temporal-aq"
|
|
||||||
title="TEMPORAL AQ"
|
title="TEMPORAL AQ"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Applies only to NVENC. Increases quality of high-detail, low-motion scenes. May not be compatible with older devices."
|
subtitle="Applies only to NVENC. Increases quality of high-detail, low-motion scenes. May not be compatible with older devices."
|
||||||
|
@ -93,7 +93,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="prefer-wide-gamut"
|
|
||||||
title="PREFER WIDE GAMUT"
|
title="PREFER WIDE GAMUT"
|
||||||
subtitle="Use Display P3 for thumbnails. This better preserves the vibrance of images with wide colorspaces, but images may appear differently on old devices with an old browser version. sRGB images are kept as sRGB to avoid color shifts."
|
subtitle="Use Display P3 for thumbnails. This better preserves the vibrance of images with wide colorspaces, but images may appear differently on old devices with an old browser version. sRGB images are kept as sRGB to avoid color shifts."
|
||||||
checked={config.image.colorspace === Colorspace.P3}
|
checked={config.image.colorspace === Colorspace.P3}
|
||||||
@ -103,7 +102,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="prefer-embedded"
|
|
||||||
title="PREFER EMBEDDED PREVIEW"
|
title="PREFER EMBEDDED PREVIEW"
|
||||||
subtitle="Use embedded previews in RAW photos as the input to image processing when available. This can produce more accurate colors for some images, but the quality of the preview is camera-dependent and the image may have more compression artifacts."
|
subtitle="Use embedded previews in RAW photos as the input to image processing when available. This can produce more accurate colors for some images, but the quality of the preview is camera-dependent and the image may have more compression artifacts."
|
||||||
checked={config.image.extractEmbedded}
|
checked={config.image.extractEmbedded}
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
<form autocomplete="off" on:submit|preventDefault>
|
<form autocomplete="off" on:submit|preventDefault>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="watch-filesystem"
|
|
||||||
title="Watch filesystem"
|
title="Watch filesystem"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Watch external libraries for file changes"
|
subtitle="Watch external libraries for file changes"
|
||||||
@ -65,7 +64,6 @@
|
|||||||
<form autocomplete="off" on:submit|preventDefault>
|
<form autocomplete="off" on:submit|preventDefault>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="periodic-library-scan"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Enable periodic library scanning"
|
subtitle="Enable periodic library scanning"
|
||||||
|
@ -20,13 +20,7 @@
|
|||||||
<div in:fade={{ duration: 500 }}>
|
<div in:fade={{ duration: 500 }}>
|
||||||
<form autocomplete="off" on:submit|preventDefault>
|
<form autocomplete="off" on:submit|preventDefault>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch title="ENABLED" {disabled} subtitle="Logging" bind:checked={config.logging.enabled} />
|
||||||
id="enable-logging"
|
|
||||||
title="ENABLED"
|
|
||||||
{disabled}
|
|
||||||
subtitle="Logging"
|
|
||||||
bind:checked={config.logging.enabled}
|
|
||||||
/>
|
|
||||||
<SettingSelect
|
<SettingSelect
|
||||||
label="LEVEL"
|
label="LEVEL"
|
||||||
desc="When enabled, what log level to use."
|
desc="When enabled, what log level to use."
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
<form autocomplete="off" on:submit|preventDefault class="mx-4 mt-4">
|
<form autocomplete="off" on:submit|preventDefault class="mx-4 mt-4">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-machine-learning"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
subtitle="If disabled, all ML features will be disabled regardless of the below settings."
|
subtitle="If disabled, all ML features will be disabled regardless of the below settings."
|
||||||
{disabled}
|
{disabled}
|
||||||
@ -53,7 +52,6 @@
|
|||||||
>
|
>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-clip"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
subtitle="If disabled, images will not be encoded for smart search."
|
subtitle="If disabled, images will not be encoded for smart search."
|
||||||
bind:checked={config.machineLearning.clip.enabled}
|
bind:checked={config.machineLearning.clip.enabled}
|
||||||
@ -85,7 +83,6 @@
|
|||||||
>
|
>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-duplicate-detection"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
subtitle="If disabled, exactly identical assets will still be de-duplicated."
|
subtitle="If disabled, exactly identical assets will still be de-duplicated."
|
||||||
bind:checked={config.machineLearning.duplicateDetection.enabled}
|
bind:checked={config.machineLearning.duplicateDetection.enabled}
|
||||||
@ -116,7 +113,6 @@
|
|||||||
>
|
>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-facial-recognition"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
subtitle="If disabled, images will not be encoded for facial recognition and will not populate the People section in the Explore page."
|
subtitle="If disabled, images will not be encoded for facial recognition and will not populate the People section in the Explore page."
|
||||||
bind:checked={config.machineLearning.facialRecognition.enabled}
|
bind:checked={config.machineLearning.facialRecognition.enabled}
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
<SettingAccordion key="map" title="Map Settings" subtitle="Manage map settings">
|
<SettingAccordion key="map" title="Map Settings" subtitle="Manage map settings">
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-map-features"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Enable map features"
|
subtitle="Enable map features"
|
||||||
@ -67,7 +66,6 @@
|
|||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-reverse-geocoding"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Enable reverse geocoding"
|
subtitle="Enable reverse geocoding"
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
<form autocomplete="off" on:submit|preventDefault>
|
<form autocomplete="off" on:submit|preventDefault>
|
||||||
<div class="ml-4 mt-4">
|
<div class="ml-4 mt-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-new-version-check"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
subtitle="Enable periodic requests to GitHub to check for new releases"
|
subtitle="Enable periodic requests to GitHub to check for new releases"
|
||||||
bind:checked={config.newVersionCheck.enabled}
|
bind:checked={config.newVersionCheck.enabled}
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
<SettingAccordion key="email" title="Email" subtitle="Settings for sending email notifications">
|
<SettingAccordion key="email" title="Email" subtitle="Settings for sending email notifications">
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-smtp"
|
|
||||||
title="Enabled"
|
title="Enabled"
|
||||||
subtitle="Enable email notifications"
|
subtitle="Enable email notifications"
|
||||||
{disabled}
|
{disabled}
|
||||||
@ -76,7 +75,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-ignore-cert"
|
|
||||||
title="Ignore certificate errors"
|
title="Ignore certificate errors"
|
||||||
subtitle="Ignore TLS certificate validation errors (not recommended)"
|
subtitle="Ignore TLS certificate validation errors (not recommended)"
|
||||||
disabled={disabled || !config.notifications.smtp.enabled}
|
disabled={disabled || !config.notifications.smtp.enabled}
|
||||||
|
@ -107,7 +107,6 @@
|
|||||||
{#await getTemplateOptions() then}
|
{#await getTemplateOptions() then}
|
||||||
<div id="directory-path-builder" class="flex flex-col gap-4 {minified ? '' : 'ml-4 mt-4'}">
|
<div id="directory-path-builder" class="flex flex-col gap-4 {minified ? '' : 'ml-4 mt-4'}">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="storage-template-enabled"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Enable storage template engine"
|
subtitle="Enable storage template engine"
|
||||||
@ -117,7 +116,6 @@
|
|||||||
|
|
||||||
{#if !minified}
|
{#if !minified}
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="hash-verification-enabled"
|
|
||||||
title="HASH VERIFICATION ENABLED"
|
title="HASH VERIFICATION ENABLED"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Enables hash verification, don't disable this unless you're certain of the implications"
|
subtitle="Enables hash verification, don't disable this unless you're certain of the implications"
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
<form autocomplete="off" on:submit|preventDefault>
|
<form autocomplete="off" on:submit|preventDefault>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="enable-trash-features"
|
|
||||||
title="ENABLED"
|
title="ENABLED"
|
||||||
{disabled}
|
{disabled}
|
||||||
subtitle="Enable Trash features"
|
subtitle="Enable Trash features"
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="album-options-modal" title="Options" onClose={() => dispatch('close')}>
|
<FullScreenModal title="Options" onClose={() => dispatch('close')}>
|
||||||
<div class="items-center justify-center">
|
<div class="items-center justify-center">
|
||||||
<div class="py-2">
|
<div class="py-2">
|
||||||
<h2 class="text-gray text-sm mb-2">SETTINGS</h2>
|
<h2 class="text-gray text-sm mb-2">SETTINGS</h2>
|
||||||
@ -64,7 +64,6 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="comments-likes"
|
|
||||||
title="Comments & likes"
|
title="Comments & likes"
|
||||||
subtitle="Let others respond"
|
subtitle="Let others respond"
|
||||||
checked={album.isActivityEnabled}
|
checked={album.isActivityEnabled}
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !selectedRemoveUser}
|
{#if !selectedRemoveUser}
|
||||||
<FullScreenModal id="share-info-modal" title="Options" {onClose}>
|
<FullScreenModal title="Options" {onClose}>
|
||||||
<section class="immich-scrollbar max-h-[400px] overflow-y-auto pb-4">
|
<section class="immich-scrollbar max-h-[400px] overflow-y-auto pb-4">
|
||||||
<div class="flex w-full place-items-center justify-between gap-4 p-5">
|
<div class="flex w-full place-items-center justify-between gap-4 p-5">
|
||||||
<div class="flex place-items-center gap-4">
|
<div class="flex place-items-center gap-4">
|
||||||
@ -156,7 +156,6 @@
|
|||||||
|
|
||||||
{#if selectedRemoveUser && selectedRemoveUser?.id === currentUser?.id}
|
{#if selectedRemoveUser && selectedRemoveUser?.id === currentUser?.id}
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
id="leave-album-modal"
|
|
||||||
title="Leave album?"
|
title="Leave album?"
|
||||||
prompt="Are you sure you want to leave {album.albumName}?"
|
prompt="Are you sure you want to leave {album.albumName}?"
|
||||||
confirmText="Leave"
|
confirmText="Leave"
|
||||||
@ -167,7 +166,6 @@
|
|||||||
|
|
||||||
{#if selectedRemoveUser && selectedRemoveUser?.id !== currentUser?.id}
|
{#if selectedRemoveUser && selectedRemoveUser?.id !== currentUser?.id}
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
id="remove-user-modal"
|
|
||||||
title="Remove user?"
|
title="Remove user?"
|
||||||
prompt="Are you sure you want to remove {selectedRemoveUser.name}?"
|
prompt="Are you sure you want to remove {selectedRemoveUser.name}?"
|
||||||
confirmText="Remove"
|
confirmText="Remove"
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="user-selection-modal" title="Invite to album" showLogo {onClose}>
|
<FullScreenModal title="Invite to album" showLogo {onClose}>
|
||||||
{#if Object.keys(selectedUsers).length > 0}
|
{#if Object.keys(selectedUsers).length > 0}
|
||||||
<div class="mb-2 py-2 sticky">
|
<div class="mb-2 py-2 sticky">
|
||||||
<p class="text-xs font-medium">SELECTED</p>
|
<p class="text-xs font-medium">SELECTED</p>
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="merge-people-modal" title="Merge people - {title}" onClose={() => dispatch('close')}>
|
<FullScreenModal title="Merge people - {title}" onClose={() => dispatch('close')}>
|
||||||
<div class="flex items-center justify-center py-4 md:h-36 md:py-4">
|
<div class="flex items-center justify-center py-4 md:h-36 md:py-4">
|
||||||
{#if !choosePersonToMerge}
|
{#if !choosePersonToMerge}
|
||||||
<div class="flex h-20 w-20 items-center px-1 md:h-24 md:w-24 md:px-2">
|
<div class="flex h-20 w-20 items-center px-1 md:h-24 md:w-24 md:px-2">
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="set-birth-date-modal" title="Set date of birth" icon={mdiCake} onClose={handleCancel}>
|
<FullScreenModal title="Set date of birth" icon={mdiCake} onClose={handleCancel}>
|
||||||
<div class="text-immich-primary dark:text-immich-dark-primary">
|
<div class="text-immich-primary dark:text-immich-dark-primary">
|
||||||
<p class="text-sm dark:text-immich-dark-fg">
|
<p class="text-sm dark:text-immich-dark-fg">
|
||||||
Date of birth is used to calculate the age of this person at the time of a photo.
|
Date of birth is used to calculate the age of this person at the time of a photo.
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="api-key-modal" {title} icon={mdiKeyVariant} onClose={handleCancel}>
|
<FullScreenModal {title} icon={mdiKeyVariant} onClose={handleCancel}>
|
||||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off" id="api-key-form">
|
<form on:submit|preventDefault={handleSubmit} autocomplete="off" id="api-key-form">
|
||||||
<div class="mb-4 flex flex-col gap-2">
|
<div class="mb-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="name">Name</label>
|
<label class="immich-form-label" for="name">Name</label>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
const handleDone = () => dispatch('done');
|
const handleDone = () => dispatch('done');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="api-key-secret-modal" title="API key" icon={mdiKeyVariant} onClose={() => handleDone()}>
|
<FullScreenModal title="API key" icon={mdiKeyVariant} onClose={() => handleDone()}>
|
||||||
<div class="text-immich-primary dark:text-immich-dark-primary">
|
<div class="text-immich-primary dark:text-immich-dark-primary">
|
||||||
<p class="text-sm dark:text-immich-dark-fg">
|
<p class="text-sm dark:text-immich-dark-fg">
|
||||||
This value will only be shown once. Please be sure to copy it before closing the window.
|
This value will only be shown once. Please be sure to copy it before closing the window.
|
||||||
|
@ -74,7 +74,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="create-new-user-modal" title="Create new user" showLogo {onClose}>
|
<FullScreenModal title="Create new user" showLogo {onClose}>
|
||||||
<form on:submit|preventDefault={registerUser} autocomplete="off" id="create-new-user-form">
|
<form on:submit|preventDefault={registerUser} autocomplete="off" id="create-new-user-form">
|
||||||
<div class="my-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="email">Email</label>
|
<label class="immich-form-label" for="email">Email</label>
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="edit-album-modal" title="Edit album" width="wide" {onClose}>
|
<FullScreenModal title="Edit album" width="wide" {onClose}>
|
||||||
<form on:submit|preventDefault={handleUpdateAlbumInfo} autocomplete="off" id="edit-album-form">
|
<form on:submit|preventDefault={handleUpdateAlbumInfo} autocomplete="off" id="edit-album-form">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="hidden sm:flex">
|
<div class="hidden sm:flex">
|
||||||
|
@ -96,7 +96,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="edit-user-modal" title="Edit user" icon={mdiAccountEditOutline} {onClose}>
|
<FullScreenModal title="Edit user" icon={mdiAccountEditOutline} {onClose}>
|
||||||
<form on:submit|preventDefault={editUser} autocomplete="off" id="edit-user-form">
|
<form on:submit|preventDefault={editUser} autocomplete="off" id="edit-user-form">
|
||||||
<div class="my-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="email">Email</label>
|
<label class="immich-form-label" for="email">Email</label>
|
||||||
|
@ -28,12 +28,7 @@
|
|||||||
const handleSubmit = () => dispatch('submit', { excludePattern: exclusionPattern });
|
const handleSubmit = () => dispatch('submit', { excludePattern: exclusionPattern });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal
|
<FullScreenModal title="Add exclusion pattern" icon={mdiFolderRemove} onClose={handleCancel}>
|
||||||
id="add-exclusion-pattern-modal"
|
|
||||||
title="Add exclusion pattern"
|
|
||||||
icon={mdiFolderRemove}
|
|
||||||
onClose={handleCancel}
|
|
||||||
>
|
|
||||||
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off" id="add-exclusion-pattern-form">
|
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off" id="add-exclusion-pattern-form">
|
||||||
<p class="py-5 text-sm">
|
<p class="py-5 text-sm">
|
||||||
Exclusion patterns lets you ignore files and folders when scanning your library. This is useful if you have
|
Exclusion patterns lets you ignore files and folders when scanning your library. This is useful if you have
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
const handleSubmit = () => dispatch('submit', { importPath });
|
const handleSubmit = () => dispatch('submit', { importPath });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="library-import-path-modal" {title} icon={mdiFolderSync} onClose={handleCancel}>
|
<FullScreenModal {title} icon={mdiFolderSync} onClose={handleCancel}>
|
||||||
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off" id="library-import-path-form">
|
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off" id="library-import-path-form">
|
||||||
<p class="py-5 text-sm">
|
<p class="py-5 text-sm">
|
||||||
Specify a folder to import. This folder, including subfolders, will be scanned for images and videos.
|
Specify a folder to import. This folder, including subfolders, will be scanned for images and videos.
|
||||||
|
@ -27,12 +27,7 @@
|
|||||||
const handleSubmit = () => dispatch('submit', { ownerId });
|
const handleSubmit = () => dispatch('submit', { ownerId });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal
|
<FullScreenModal title="Select library owner" icon={mdiFolderSync} onClose={handleCancel}>
|
||||||
id="select-library-owner-modal"
|
|
||||||
title="Select library owner"
|
|
||||||
icon={mdiFolderSync}
|
|
||||||
onClose={handleCancel}
|
|
||||||
>
|
|
||||||
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off" id="select-library-owner-form">
|
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off" id="select-library-owner-form">
|
||||||
<p class="p-5 text-sm">NOTE: This cannot be changed later!</p>
|
<p class="p-5 text-sm">NOTE: This cannot be changed later!</p>
|
||||||
|
|
||||||
|
@ -21,21 +21,17 @@
|
|||||||
const handleClose = () => dispatch('close');
|
const handleClose = () => dispatch('close');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="map-settings-modal" title="Map settings" onClose={handleClose}>
|
<FullScreenModal title="Map settings" onClose={handleClose}>
|
||||||
<form
|
<form
|
||||||
on:submit|preventDefault={() => dispatch('save', settings)}
|
on:submit|preventDefault={() => dispatch('save', settings)}
|
||||||
class="flex flex-col gap-4 text-immich-primary dark:text-immich-dark-primary"
|
class="flex flex-col gap-4 text-immich-primary dark:text-immich-dark-primary"
|
||||||
id="map-settings-form"
|
id="map-settings-form"
|
||||||
>
|
>
|
||||||
<SettingSwitch id="allow-dark-mode" title="Allow dark mode" bind:checked={settings.allowDarkMode} />
|
<SettingSwitch title="Allow dark mode" bind:checked={settings.allowDarkMode} />
|
||||||
<SettingSwitch id="only-favorites" title="Only favorites" bind:checked={settings.onlyFavorites} />
|
<SettingSwitch title="Only favorites" bind:checked={settings.onlyFavorites} />
|
||||||
<SettingSwitch id="include-archived" title="Include archived" bind:checked={settings.includeArchived} />
|
<SettingSwitch title="Include archived" bind:checked={settings.includeArchived} />
|
||||||
<SettingSwitch
|
<SettingSwitch title="Include shared partner assets" bind:checked={settings.withPartners} />
|
||||||
id="include-shared-partner-assets"
|
<SettingSwitch title="Include shared albums" bind:checked={settings.withSharedAlbums} />
|
||||||
title="Include shared partner assets"
|
|
||||||
bind:checked={settings.withPartners}
|
|
||||||
/>
|
|
||||||
<SettingSwitch id="include-shared-albums" title="Include shared albums" bind:checked={settings.withSharedAlbums} />
|
|
||||||
{#if customDateRange}
|
{#if customDateRange}
|
||||||
<div in:fly={{ y: 10, duration: 200 }} class="flex flex-col gap-4">
|
<div in:fly={{ y: 10, duration: 200 }} class="flex flex-col gap-4">
|
||||||
<div class="flex items-center justify-between gap-8">
|
<div class="flex items-center justify-between gap-8">
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
id="permanently-delete-asset-modal"
|
|
||||||
title="Permanently delete asset{s(size)}"
|
title="Permanently delete asset{s(size)}"
|
||||||
confirmText="Delete"
|
confirmText="Delete"
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="album-selection-modal" title={getTitle()} {onClose}>
|
<FullScreenModal title={getTitle()} {onClose}>
|
||||||
<div class="mb-2 flex max-h-[400px] flex-col">
|
<div class="mb-2 flex max-h-[400px] flex-col">
|
||||||
{#if loading}
|
{#if loading}
|
||||||
{#each { length: 3 } as _}
|
{#each { length: 3 } as _}
|
||||||
|
@ -56,7 +56,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
id="edit-date-time-modal"
|
|
||||||
confirmColor="primary"
|
confirmColor="primary"
|
||||||
title="Edit date and time"
|
title="Edit date and time"
|
||||||
prompt="Please select a new date:"
|
prompt="Please select a new date:"
|
||||||
@ -75,13 +74,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col w-full mt-2">
|
<div class="flex flex-col w-full mt-2">
|
||||||
<Combobox
|
<Combobox bind:selectedOption label="Timezone" options={timezones} placeholder="Search timezone..." />
|
||||||
bind:selectedOption
|
|
||||||
id="settings-timezone"
|
|
||||||
label="Timezone"
|
|
||||||
options={timezones}
|
|
||||||
placeholder="Search timezone..."
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ConfirmDialog>
|
</ConfirmDialog>
|
||||||
|
@ -104,7 +104,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
id="change-location-modal"
|
|
||||||
confirmColor="primary"
|
confirmColor="primary"
|
||||||
title="Change location"
|
title="Change location"
|
||||||
width="wide"
|
width="wide"
|
||||||
|
@ -19,17 +19,18 @@
|
|||||||
import { clickOutside } from '$lib/actions/click-outside';
|
import { clickOutside } from '$lib/actions/click-outside';
|
||||||
import { focusOutside } from '$lib/actions/focus-outside';
|
import { focusOutside } from '$lib/actions/focus-outside';
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
|
import { uniqueIdStore } from '$lib/stores/unique-id.store';
|
||||||
|
|
||||||
/**
|
|
||||||
* Unique identifier for the combobox.
|
|
||||||
*/
|
|
||||||
export let id: string;
|
|
||||||
export let label: string;
|
export let label: string;
|
||||||
export let hideLabel = false;
|
export let hideLabel = false;
|
||||||
export let options: ComboBoxOption[] = [];
|
export let options: ComboBoxOption[] = [];
|
||||||
export let selectedOption: ComboBoxOption | undefined;
|
export let selectedOption: ComboBoxOption | undefined;
|
||||||
export let placeholder = '';
|
export let placeholder = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier for the combobox.
|
||||||
|
*/
|
||||||
|
let id: string = uniqueIdStore.generateId();
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not the dropdown autocomplete list should be visible.
|
* Indicates whether or not the dropdown autocomplete list should be visible.
|
||||||
*/
|
*/
|
||||||
|
@ -159,7 +159,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="create-shared-link-modal" title={getTitle()} icon={mdiLink} {onClose}>
|
<FullScreenModal title={getTitle()} icon={mdiLink} {onClose}>
|
||||||
<section>
|
<section>
|
||||||
{#if shareType === SharedLinkType.Album}
|
{#if shareType === SharedLinkType.Album}
|
||||||
{#if !editingLink}
|
{#if !editingLink}
|
||||||
@ -204,33 +204,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<SettingSwitch id="require-password" bind:checked={enablePassword} title={'Require password'} />
|
<SettingSwitch bind:checked={enablePassword} title={'Require password'} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<SettingSwitch id="show-metadata" bind:checked={showMetadata} title={'Show metadata'} />
|
<SettingSwitch bind:checked={showMetadata} title={'Show metadata'} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<SettingSwitch
|
<SettingSwitch bind:checked={allowDownload} title={'Allow public user to download'} />
|
||||||
id="allow-public-download"
|
|
||||||
bind:checked={allowDownload}
|
|
||||||
title={'Allow public user to download'}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<SettingSwitch id="allow-public-upload" bind:checked={allowUpload} title={'Allow public user to upload'} />
|
<SettingSwitch bind:checked={allowUpload} title={'Allow public user to upload'} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{#if editingLink}
|
{#if editingLink}
|
||||||
<p class="immich-form-label my-2">
|
<p class="immich-form-label my-2">
|
||||||
<SettingSwitch
|
<SettingSwitch bind:checked={shouldChangeExpirationTime} title={'Change expiration time'} />
|
||||||
id="change-expiration-time"
|
|
||||||
bind:checked={shouldChangeExpirationTime}
|
|
||||||
title={'Change expiration time'}
|
|
||||||
/>
|
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<p class="immich-form-label my-2">Expire after</p>
|
<p class="immich-form-label my-2">Expire after</p>
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
import Button from '../../elements/buttons/button.svelte';
|
import Button from '../../elements/buttons/button.svelte';
|
||||||
import type { Color } from '$lib/components/elements/buttons/button.svelte';
|
import type { Color } from '$lib/components/elements/buttons/button.svelte';
|
||||||
|
|
||||||
export let id: string = 'confirm-dialog';
|
|
||||||
export let title = 'Confirm';
|
export let title = 'Confirm';
|
||||||
export let prompt = 'Are you sure you want to do this?';
|
export let prompt = 'Are you sure you want to do this?';
|
||||||
export let confirmText = 'Confirm';
|
export let confirmText = 'Confirm';
|
||||||
@ -24,7 +23,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal {title} {id} onClose={onCancel} {width}>
|
<FullScreenModal {title} onClose={onCancel} {width}>
|
||||||
<div class="text-md py-5 text-center">
|
<div class="text-md py-5 text-center">
|
||||||
<slot name="prompt">
|
<slot name="prompt">
|
||||||
<p>{prompt}</p>
|
<p>{prompt}</p>
|
||||||
|
@ -3,13 +3,9 @@
|
|||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
|
import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
|
||||||
import ModalHeader from '$lib/components/shared-components/modal-header.svelte';
|
import ModalHeader from '$lib/components/shared-components/modal-header.svelte';
|
||||||
|
import { uniqueIdStore } from '$lib/stores/unique-id.store';
|
||||||
|
|
||||||
export let onClose: () => void;
|
export let onClose: () => void;
|
||||||
|
|
||||||
/**
|
|
||||||
* Unique identifier for the modal.
|
|
||||||
*/
|
|
||||||
export let id: string;
|
|
||||||
export let title: string;
|
export let title: string;
|
||||||
/**
|
/**
|
||||||
* If true, the logo will be displayed next to the modal title.
|
* If true, the logo will be displayed next to the modal title.
|
||||||
@ -28,6 +24,11 @@
|
|||||||
*/
|
*/
|
||||||
export let width: 'wide' | 'narrow' | 'auto' = 'narrow';
|
export let width: 'wide' | 'narrow' | 'auto' = 'narrow';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier for the modal.
|
||||||
|
*/
|
||||||
|
let id: string = uniqueIdStore.generateId();
|
||||||
|
|
||||||
$: titleId = `${id}-title`;
|
$: titleId = `${id}-title`;
|
||||||
$: isStickyBottom = !!$$slots['sticky-bottom'];
|
$: isStickyBottom = !!$$slots['sticky-bottom'];
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
const colors: UserAvatarColor[] = Object.values(UserAvatarColor);
|
const colors: UserAvatarColor[] = Object.values(UserAvatarColor);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="avatar-selector-modal" title="Select avatar color" width="auto" onClose={() => dispatch('close')}>
|
<FullScreenModal title="Select avatar color" width="auto" onClose={() => dispatch('close')}>
|
||||||
<div class="flex items-center justify-center mt-4">
|
<div class="flex items-center justify-center mt-4">
|
||||||
<div class="grid grid-cols-2 md:grid-cols-5 gap-4">
|
<div class="grid grid-cols-2 md:grid-cols-5 gap-4">
|
||||||
{#each colors as color}
|
{#each colors as color}
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="profile-image-cropper" title="Set profile picture" width="auto" {onClose}>
|
<FullScreenModal title="Set profile picture" width="auto" {onClose}>
|
||||||
<div class="flex place-items-center items-center justify-center">
|
<div class="flex place-items-center items-center justify-center">
|
||||||
<div
|
<div
|
||||||
class="relative flex aspect-square w-[250px] overflow-hidden rounded-full border-4 border-immich-primary bg-immich-dark-primary dark:border-immich-dark-primary dark:bg-immich-primary"
|
class="relative flex aspect-square w-[250px] overflow-hidden rounded-full border-4 border-immich-primary bg-immich-dark-primary dark:border-immich-dark-primary dark:bg-immich-primary"
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
<div class="grid grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-5 mt-1">
|
<div class="grid grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-5 mt-1">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Combobox
|
<Combobox
|
||||||
id="camera-make"
|
|
||||||
label="Make"
|
label="Make"
|
||||||
on:select={({ detail }) => (filters.make = detail?.value)}
|
on:select={({ detail }) => (filters.make = detail?.value)}
|
||||||
options={toComboBoxOptions(makes)}
|
options={toComboBoxOptions(makes)}
|
||||||
@ -52,7 +51,6 @@
|
|||||||
|
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Combobox
|
<Combobox
|
||||||
id="camera-model"
|
|
||||||
label="Model"
|
label="Model"
|
||||||
on:select={({ detail }) => (filters.model = detail?.value)}
|
on:select={({ detail }) => (filters.model = detail?.value)}
|
||||||
options={toComboBoxOptions(models)}
|
options={toComboBoxOptions(models)}
|
||||||
|
@ -63,7 +63,6 @@
|
|||||||
<div class="grid grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-5 mt-1">
|
<div class="grid grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-5 mt-1">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Combobox
|
<Combobox
|
||||||
id="location-country"
|
|
||||||
label="Country"
|
label="Country"
|
||||||
on:select={({ detail }) => (filters.country = detail?.value)}
|
on:select={({ detail }) => (filters.country = detail?.value)}
|
||||||
options={toComboBoxOptions(countries)}
|
options={toComboBoxOptions(countries)}
|
||||||
@ -74,7 +73,6 @@
|
|||||||
|
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Combobox
|
<Combobox
|
||||||
id="location-state"
|
|
||||||
label="State"
|
label="State"
|
||||||
on:select={({ detail }) => (filters.state = detail?.value)}
|
on:select={({ detail }) => (filters.state = detail?.value)}
|
||||||
options={toComboBoxOptions(states)}
|
options={toComboBoxOptions(states)}
|
||||||
@ -85,7 +83,6 @@
|
|||||||
|
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Combobox
|
<Combobox
|
||||||
id="location-city"
|
|
||||||
label="City"
|
label="City"
|
||||||
on:select={({ detail }) => (filters.city = detail?.value)}
|
on:select={({ detail }) => (filters.city = detail?.value)}
|
||||||
options={toComboBoxOptions(cities)}
|
options={toComboBoxOptions(cities)}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
|
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
|
||||||
|
|
||||||
export let id: string;
|
|
||||||
export let title: string;
|
export let title: string;
|
||||||
export let comboboxPlaceholder: string;
|
export let comboboxPlaceholder: string;
|
||||||
export let subtitle = '';
|
export let subtitle = '';
|
||||||
@ -33,7 +32,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<Combobox
|
<Combobox
|
||||||
{id}
|
|
||||||
label={title}
|
label={title}
|
||||||
hideLabel={true}
|
hideLabel={true}
|
||||||
{selectedOption}
|
{selectedOption}
|
||||||
|
@ -3,14 +3,16 @@
|
|||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Slider from '$lib/components/elements/slider.svelte';
|
import Slider from '$lib/components/elements/slider.svelte';
|
||||||
|
import { uniqueIdStore } from '$lib/stores/unique-id.store';
|
||||||
|
|
||||||
export let id: string;
|
|
||||||
export let title: string;
|
export let title: string;
|
||||||
export let subtitle = '';
|
export let subtitle = '';
|
||||||
export let checked = false;
|
export let checked = false;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let isEdited = false;
|
export let isEdited = false;
|
||||||
|
|
||||||
|
let id: string = uniqueIdStore.generateId();
|
||||||
|
|
||||||
$: sliderId = `${id}-slider`;
|
$: sliderId = `${id}-slider`;
|
||||||
$: subtitleId = subtitle ? `${id}-subtitle` : undefined;
|
$: subtitleId = subtitle ? `${id}-subtitle` : undefined;
|
||||||
|
|
||||||
|
@ -37,12 +37,7 @@
|
|||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal
|
<FullScreenModal title="Keyboard shortcuts" width="auto" onClose={() => dispatch('close')}>
|
||||||
id="keyboard-shortcuts-modal"
|
|
||||||
title="Keyboard shortcuts"
|
|
||||||
width="auto"
|
|
||||||
onClose={() => dispatch('close')}
|
|
||||||
>
|
|
||||||
<div class="grid grid-cols-1 gap-4 px-4 pb-4 md:grid-cols-2">
|
<div class="grid grid-cols-1 gap-4 px-4 pb-4 md:grid-cols-2">
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<h2>General</h2>
|
<h2>General</h2>
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if showModal}
|
{#if showModal}
|
||||||
<FullScreenModal id="new-version-modal" title="🎉 NEW VERSION AVAILABLE" onClose={() => (showModal = false)}>
|
<FullScreenModal title="🎉 NEW VERSION AVAILABLE" onClose={() => (showModal = false)}>
|
||||||
<div>
|
<div>
|
||||||
Hi friend, there is a new version of the application please take your time to visit the
|
Hi friend, there is a new version of the application please take your time to visit the
|
||||||
<span class="font-medium underline"
|
<span class="font-medium underline"
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="slideshow-settings-modal" title="Slideshow settings" {onClose}>
|
<FullScreenModal title="Slideshow settings" {onClose}>
|
||||||
<div class="flex flex-col gap-4 text-immich-primary dark:text-immich-dark-primary">
|
<div class="flex flex-col gap-4 text-immich-primary dark:text-immich-dark-primary">
|
||||||
<SettingDropdown
|
<SettingDropdown
|
||||||
title="Direction"
|
title="Direction"
|
||||||
@ -63,7 +63,7 @@
|
|||||||
$slideshowLook = handleToggle(option, lookOptions) || $slideshowLook;
|
$slideshowLook = handleToggle(option, lookOptions) || $slideshowLook;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SettingSwitch id="show-progress-bar" title="Show Progress Bar" bind:checked={$showProgressBar} />
|
<SettingSwitch title="Show Progress Bar" bind:checked={$showProgressBar} />
|
||||||
<SettingInputField
|
<SettingInputField
|
||||||
inputType={SettingInputFieldType.NUMBER}
|
inputType={SettingInputFieldType.NUMBER}
|
||||||
label="Duration"
|
label="Duration"
|
||||||
|
@ -72,7 +72,6 @@
|
|||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="theme-selection"
|
|
||||||
title="Theme selection"
|
title="Theme selection"
|
||||||
subtitle="Automatically set the theme to light or dark based on your browser's system preference"
|
subtitle="Automatically set the theme to light or dark based on your browser's system preference"
|
||||||
bind:checked={$colorTheme.system}
|
bind:checked={$colorTheme.system}
|
||||||
@ -82,7 +81,6 @@
|
|||||||
|
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="default-locale"
|
|
||||||
title="Default Locale"
|
title="Default Locale"
|
||||||
subtitle="Format dates and numbers based on your browser locale"
|
subtitle="Format dates and numbers based on your browser locale"
|
||||||
checked={$locale == undefined}
|
checked={$locale == undefined}
|
||||||
@ -94,7 +92,6 @@
|
|||||||
{#if $locale !== undefined}
|
{#if $locale !== undefined}
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingCombobox
|
<SettingCombobox
|
||||||
id="custom-locale"
|
|
||||||
comboboxPlaceholder="Searching locales..."
|
comboboxPlaceholder="Searching locales..."
|
||||||
{selectedOption}
|
{selectedOption}
|
||||||
options={getAllLanguages()}
|
options={getAllLanguages()}
|
||||||
@ -107,7 +104,6 @@
|
|||||||
|
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="always-load-original-file"
|
|
||||||
title="Display original photos"
|
title="Display original photos"
|
||||||
subtitle="Prefer to display the original photo when viewing an asset rather than thumbnails when the original asset is web-compatible. This may result in slower photo display speeds."
|
subtitle="Prefer to display the original photo when viewing an asset rather than thumbnails when the original asset is web-compatible. This may result in slower photo display speeds."
|
||||||
bind:checked={$alwaysLoadOriginalFile}
|
bind:checked={$alwaysLoadOriginalFile}
|
||||||
@ -116,7 +112,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="play-video-thumbnail-on-hover"
|
|
||||||
title="Play video thumbnail on hover"
|
title="Play video thumbnail on hover"
|
||||||
subtitle="Play video thumbnail when mouse is hovering over item. Even when disabled, playback can be started by hovering over the play icon."
|
subtitle="Play video thumbnail when mouse is hovering over item. Even when disabled, playback can be started by hovering over the play icon."
|
||||||
bind:checked={$playVideoThumbnailOnHover}
|
bind:checked={$playVideoThumbnailOnHover}
|
||||||
@ -125,7 +120,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="loop-video"
|
|
||||||
title="Loop videos"
|
title="Loop videos"
|
||||||
subtitle="Enable to automatically loop a video in the detail viewer."
|
subtitle="Enable to automatically loop a video in the detail viewer."
|
||||||
bind:checked={$loopVideo}
|
bind:checked={$loopVideo}
|
||||||
@ -135,7 +129,6 @@
|
|||||||
|
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="show-delete-warning"
|
|
||||||
title="Permanent deletion warning"
|
title="Permanent deletion warning"
|
||||||
subtitle="Show a warning when permanently deleting assets"
|
subtitle="Show a warning when permanently deleting assets"
|
||||||
bind:checked={$showDeleteModal}
|
bind:checked={$showDeleteModal}
|
||||||
@ -144,7 +137,6 @@
|
|||||||
|
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="people-sidebar-link"
|
|
||||||
title="People"
|
title="People"
|
||||||
subtitle="Display a link to People in the sidebar"
|
subtitle="Display a link to People in the sidebar"
|
||||||
bind:checked={$sidebarSettings.people}
|
bind:checked={$sidebarSettings.people}
|
||||||
@ -152,7 +144,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="sharing-sidebar-link"
|
|
||||||
title="Sharing"
|
title="Sharing"
|
||||||
subtitle="Display a link to Sharing in the sidebar"
|
subtitle="Display a link to Sharing in the sidebar"
|
||||||
bind:checked={$sidebarSettings.sharing}
|
bind:checked={$sidebarSettings.sharing}
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="time-based-memories"
|
|
||||||
title="Time-based memories"
|
title="Time-based memories"
|
||||||
subtitle="Photos from previous years"
|
subtitle="Photos from previous years"
|
||||||
bind:checked={memoriesEnabled}
|
bind:checked={memoriesEnabled}
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="partner-selection-modal" title="Add partner" showLogo {onClose}>
|
<FullScreenModal title="Add partner" showLogo {onClose}>
|
||||||
<div class="immich-scrollbar max-h-[300px] overflow-y-auto">
|
<div class="immich-scrollbar max-h-[300px] overflow-y-auto">
|
||||||
{#if availableUsers.length > 0}
|
{#if availableUsers.length > 0}
|
||||||
{#each availableUsers as user}
|
{#each availableUsers as user}
|
||||||
|
@ -167,7 +167,6 @@
|
|||||||
<hr class="my-4 border border-gray-200 dark:border-gray-700" />
|
<hr class="my-4 border border-gray-200 dark:border-gray-700" />
|
||||||
<p class="text-xs font-medium my-4">PHOTOS FROM {partner.user.name.toUpperCase()}</p>
|
<p class="text-xs font-medium my-4">PHOTOS FROM {partner.user.name.toUpperCase()}</p>
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
id="show-in-timeline"
|
|
||||||
title="Show in timeline"
|
title="Show in timeline"
|
||||||
subtitle="Show photos and videos from this user in your timeline"
|
subtitle="Show photos and videos from this user in your timeline"
|
||||||
bind:checked={partner.inTimeline}
|
bind:checked={partner.inTimeline}
|
||||||
|
14
web/src/lib/stores/unique-id.store.spec.ts
Normal file
14
web/src/lib/stores/unique-id.store.spec.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { uniqueIdStore } from '$lib/stores/unique-id.store';
|
||||||
|
|
||||||
|
describe('uniqueIdStore', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
uniqueIdStore.update(() => -1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate unique ids', () => {
|
||||||
|
const { generateId } = uniqueIdStore;
|
||||||
|
const ids = [generateId(), generateId(), generateId()];
|
||||||
|
|
||||||
|
expect(ids).toEqual(['id-0', 'id-1', 'id-2']);
|
||||||
|
});
|
||||||
|
});
|
16
web/src/lib/stores/unique-id.store.ts
Normal file
16
web/src/lib/stores/unique-id.store.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { get, writable } from 'svelte/store';
|
||||||
|
|
||||||
|
function createIdStore() {
|
||||||
|
const { subscribe, update } = writable(-1);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
update,
|
||||||
|
generateId: () => {
|
||||||
|
update((value) => value + 1);
|
||||||
|
return `id-${get(uniqueIdStore)}`;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const uniqueIdStore = createIdStore();
|
@ -453,7 +453,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if showChangeNameModal}
|
{#if showChangeNameModal}
|
||||||
<FullScreenModal id="change-name-modal" title="Change name" onClose={() => (showChangeNameModal = false)}>
|
<FullScreenModal title="Change name" onClose={() => (showChangeNameModal = false)}>
|
||||||
<form on:submit|preventDefault={submitNameChange} autocomplete="off" id="change-name-form">
|
<form on:submit|preventDefault={submitNameChange} autocomplete="off" id="change-name-form">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="name">Name</label>
|
<label class="immich-form-label" for="name">Name</label>
|
||||||
|
@ -154,7 +154,6 @@
|
|||||||
|
|
||||||
{#if shouldShowPasswordResetSuccess}
|
{#if shouldShowPasswordResetSuccess}
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
id="password-reset-success-modal"
|
|
||||||
title="Password reset success"
|
title="Password reset success"
|
||||||
confirmText="Done"
|
confirmText="Done"
|
||||||
onConfirm={() => (shouldShowPasswordResetSuccess = false)}
|
onConfirm={() => (shouldShowPasswordResetSuccess = false)}
|
||||||
|
Loading…
Reference in New Issue
Block a user