mirror of
https://github.com/immich-app/immich.git
synced 2025-01-01 08:31:59 +00:00
feat(web,a11y): standardize the FullScreenModal UI (#8566)
* feat(web,a11y): standardize the FullScreenModal look * consistent header, padding, close button, and radius as BaseModal * vertically stacking ConfirmDialogue CTA buttons in narrow screens * adding aria-modal tags for screen reader * add viewport-specific height limits on modals, to enable scrolling * prevent focus from being hidden under sticky content in modals * standardize FullScreenModal widths using a Prop * wip: consistent padding with header * fix: alignment on "create user" and "edit user" modals * fix: horizontal modal content alignment * fix: create user CTA buttons * chore: remove unnecessary warning --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
parent
d43daaee81
commit
796c933fb8
43 changed files with 749 additions and 853 deletions
|
@ -42,7 +42,8 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Delete User"
|
id="delete-user-confirmation-modal"
|
||||||
|
title="Delete user"
|
||||||
confirmText={forceDelete ? 'Permanently Delete' : 'Delete'}
|
confirmText={forceDelete ? 'Permanently Delete' : 'Delete'}
|
||||||
onConfirm={handleDeleteUser}
|
onConfirm={handleDeleteUser}
|
||||||
onClose={() => dispatch('cancel')}
|
onClose={() => dispatch('cancel')}
|
|
@ -147,6 +147,7 @@
|
||||||
|
|
||||||
{#if confirmJob}
|
{#if confirmJob}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="reprocess-faces-modal"
|
||||||
prompt="Are you sure you want to reprocess all faces? This will also clear named people."
|
prompt="Are you sure you want to reprocess all faces? This will also clear named people."
|
||||||
{onConfirm}
|
{onConfirm}
|
||||||
onClose={() => (confirmJob = null)}
|
onClose={() => (confirmJob = null)}
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Restore User"
|
id="restore-user-modal"
|
||||||
|
title="Restore user"
|
||||||
confirmText="Continue"
|
confirmText="Continue"
|
||||||
confirmColor="green"
|
confirmColor="green"
|
||||||
onConfirm={handleRestoreUser}
|
onConfirm={handleRestoreUser}
|
|
@ -5,7 +5,7 @@
|
||||||
export let onConfirm: () => void;
|
export let onConfirm: () => void;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue title="Disable Login" onClose={onCancel} {onConfirm}>
|
<ConfirmDialogue id="disable-login-modal" title="Disable login" onClose={onCancel} {onConfirm}>
|
||||||
<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>
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { updateAlbumInfo, type AlbumResponseDto, type UserResponseDto, AssetOrder } from '@immich/sdk';
|
import { updateAlbumInfo, type AlbumResponseDto, type UserResponseDto, AssetOrder } from '@immich/sdk';
|
||||||
import { mdiArrowDownThin, mdiArrowUpThin, mdiClose, mdiPlus } from '@mdi/js';
|
import { mdiArrowDownThin, mdiArrowUpThin, mdiPlus } from '@mdi/js';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
||||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||||
|
@ -52,20 +50,8 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={() => dispatch('close')}>
|
<FullScreenModal id="album-options-modal" title="Options" onClose={() => dispatch('close')}>
|
||||||
<div class="flex h-full w-full place-content-center place-items-center overflow-hidden p-2 md:p-0">
|
<div class="items-center justify-center">
|
||||||
<div
|
|
||||||
class="w-[550px] rounded-3xl border bg-immich-bg shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<div class="px-2 pt-2">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<h1 class="px-4 w-full self-center font-medium text-immich-primary dark:text-immich-dark-primary">Options</h1>
|
|
||||||
<div>
|
|
||||||
<CircleIconButton icon={mdiClose} title="Close" on:click={() => dispatch('close')} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" items-center justify-center p-4">
|
|
||||||
<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>
|
||||||
<div class="grid p-2 gap-y-2">
|
<div class="grid p-2 gap-y-2">
|
||||||
|
@ -113,7 +99,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -432,7 +432,7 @@
|
||||||
{#if allowEdit}
|
{#if allowEdit}
|
||||||
<!-- Edit Modal -->
|
<!-- Edit Modal -->
|
||||||
{#if albumToEdit}
|
{#if albumToEdit}
|
||||||
<FullScreenModal onClose={() => (albumToEdit = null)}>
|
<FullScreenModal id="edit-album-modal" title="Edit album" width="wide" onClose={() => (albumToEdit = null)}>
|
||||||
<EditAlbumForm album={albumToEdit} onEditSuccess={successEditAlbumInfo} onCancel={() => (albumToEdit = null)} />
|
<EditAlbumForm album={albumToEdit} onEditSuccess={successEditAlbumInfo} onCancel={() => (albumToEdit = null)} />
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -458,7 +458,8 @@
|
||||||
<!-- Delete Modal -->
|
<!-- Delete Modal -->
|
||||||
{#if albumToDelete}
|
{#if albumToDelete}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Delete Album"
|
id="delete-album-dialogue-modal"
|
||||||
|
title="Delete album"
|
||||||
confirmText="Delete"
|
confirmText="Delete"
|
||||||
onConfirm={deleteSelectedAlbum}
|
onConfirm={deleteSelectedAlbum}
|
||||||
onClose={() => (albumToDelete = null)}
|
onClose={() => (albumToDelete = null)}
|
||||||
|
|
|
@ -121,7 +121,8 @@
|
||||||
|
|
||||||
{#if selectedRemoveUser && selectedRemoveUser?.id === currentUser?.id}
|
{#if selectedRemoveUser && selectedRemoveUser?.id === currentUser?.id}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Leave Album?"
|
id="leave-album-modal"
|
||||||
|
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"
|
||||||
onConfirm={handleRemoveUser}
|
onConfirm={handleRemoveUser}
|
||||||
|
@ -131,7 +132,8 @@
|
||||||
|
|
||||||
{#if selectedRemoveUser && selectedRemoveUser?.id !== currentUser?.id}
|
{#if selectedRemoveUser && selectedRemoveUser?.id !== currentUser?.id}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Remove User?"
|
id="remove-user-modal"
|
||||||
|
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"
|
||||||
onConfirm={handleRemoveUser}
|
onConfirm={handleRemoveUser}
|
||||||
|
|
|
@ -161,6 +161,7 @@
|
||||||
|
|
||||||
{#if isShowConfirmation}
|
{#if isShowConfirmation}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="merge-people-modal"
|
||||||
title="Merge people"
|
title="Merge people"
|
||||||
confirmText="Merge"
|
confirmText="Merge"
|
||||||
onConfirm={handleMerge}
|
onConfirm={handleMerge}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
import { getPeopleThumbnailUrl } from '$lib/utils';
|
import { getPeopleThumbnailUrl } from '$lib/utils';
|
||||||
import { type PersonResponseDto } from '@immich/sdk';
|
import { type PersonResponseDto } from '@immich/sdk';
|
||||||
import { mdiArrowLeft, mdiClose, mdiMerge } from '@mdi/js';
|
import { mdiArrowLeft, mdiMerge } from '@mdi/js';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
|
@ -30,21 +30,8 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={() => dispatch('close')}>
|
<FullScreenModal id="merge-people-modal" title="Merge people - {title}" onClose={() => dispatch('close')}>
|
||||||
<div class="flex h-full w-full place-content-center place-items-center overflow-hidden">
|
<div class="flex items-center justify-center py-4 md:h-36 md:py-4">
|
||||||
<div
|
|
||||||
class="w-[250px] max-w-[125vw] rounded-3xl border bg-immich-bg shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg md:w-[375px]"
|
|
||||||
>
|
|
||||||
<div class="relative flex items-center justify-between">
|
|
||||||
<h1 class="truncate px-4 py-4 font-medium text-immich-primary dark:text-immich-dark-primary">
|
|
||||||
Merge People - {title}
|
|
||||||
</h1>
|
|
||||||
<div class="p-2">
|
|
||||||
<CircleIconButton title="Close" icon={mdiClose} on:click={() => dispatch('close')} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-center px-2 py-4 md:h-36 md:px-4 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">
|
||||||
<ImageThumbnail
|
<ImageThumbnail
|
||||||
|
@ -109,16 +96,14 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex px-4 md:px-8 md:pt-4">
|
<div class="flex px-4 md:pt-4">
|
||||||
<h1 class="text-xl text-gray-500 dark:text-gray-300">Are these the same person?</h1>
|
<h1 class="text-xl text-gray-500 dark:text-gray-300">Are these the same person?</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex px-4 pt-2 md:px-8">
|
<div class="flex px-4 pt-2">
|
||||||
<p class="text-sm text-gray-500 dark:text-gray-300">They will be merged together</p>
|
<p class="text-sm text-gray-500 dark:text-gray-300">They will be merged together</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-8 flex w-full gap-4 px-4 pb-4">
|
<div class="mt-8 flex w-full gap-4 pb-4">
|
||||||
<Button fullwidth color="gray" on:click={() => dispatch('reject')}>No</Button>
|
<Button fullwidth color="gray" on:click={() => dispatch('reject')}>No</Button>
|
||||||
<Button fullwidth on:click={() => dispatch('confirm', [personMerge1, personMerge2])}>Yes</Button>
|
<Button fullwidth on:click={() => dispatch('confirm', [personMerge1, personMerge2])}>Yes</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||||
import { mdiCake } from '@mdi/js';
|
import { mdiCake } from '@mdi/js';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import DateInput from '../elements/date-input.svelte';
|
import DateInput from '../elements/date-input.svelte';
|
||||||
|
|
||||||
export let birthDate: string;
|
export let birthDate: string;
|
||||||
|
@ -21,23 +20,15 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={handleCancel}>
|
<FullScreenModal id="set-birthday-modal" title="Set date of birth" icon={mdiCake} onClose={handleCancel}>
|
||||||
<div
|
<div class="text-immich-primary dark:text-immich-dark-primary">
|
||||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
|
||||||
>
|
|
||||||
<Icon path={mdiCake} size="4em" />
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Set date of birth</h1>
|
|
||||||
|
|
||||||
<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.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<DateInput
|
<DateInput
|
||||||
class="immich-form-input"
|
class="immich-form-input"
|
||||||
id="birthDate"
|
id="birthDate"
|
||||||
|
@ -47,10 +38,9 @@
|
||||||
max={todayFormatted}
|
max={todayFormatted}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
<Button color="gray" fullwidth on:click={() => handleCancel()}>Cancel</Button>
|
<Button color="gray" fullwidth on:click={() => handleCancel()}>Cancel</Button>
|
||||||
<Button type="submit" fullwidth>Set</Button>
|
<Button type="submit" fullwidth>Set</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import type { ApiKeyResponseDto } from '@immich/sdk';
|
import type { ApiKeyResponseDto } from '@immich/sdk';
|
||||||
import { mdiKeyVariant } from '@mdi/js';
|
import { mdiKeyVariant } from '@mdi/js';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
@ -8,7 +7,7 @@
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
|
|
||||||
export let apiKey: Partial<ApiKeyResponseDto>;
|
export let apiKey: Partial<ApiKeyResponseDto>;
|
||||||
export let title = 'API Key';
|
export let title: string;
|
||||||
export let cancelText = 'Cancel';
|
export let cancelText = 'Cancel';
|
||||||
export let submitText = 'Save';
|
export let submitText = 'Save';
|
||||||
|
|
||||||
|
@ -29,29 +28,16 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={handleCancel}>
|
<FullScreenModal id="api-key-modal" {title} icon={mdiKeyVariant} onClose={handleCancel}>
|
||||||
<div
|
|
||||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
|
||||||
>
|
|
||||||
<Icon path={mdiKeyVariant} size="4em" />
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">
|
|
||||||
{title}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||||
<div class="m-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>
|
||||||
<input class="immich-form-input" id="name" name="name" type="text" bind:value={apiKey.name} />
|
<input class="immich-form-input" id="name" name="name" type="text" bind:value={apiKey.name} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
<Button color="gray" fullwidth on:click={handleCancel}>{cancelText}</Button>
|
<Button color="gray" fullwidth on:click={handleCancel}>{cancelText}</Button>
|
||||||
<Button type="submit" fullwidth>{submitText}</Button>
|
<Button type="submit" fullwidth>{submitText}</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import { copyToClipboard } from '$lib/utils';
|
import { copyToClipboard } from '$lib/utils';
|
||||||
import { mdiKeyVariant } from '@mdi/js';
|
import { mdiKeyVariant } from '@mdi/js';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
|
@ -20,31 +19,22 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal>
|
<FullScreenModal id="api-key-secret-modal" title="API key" icon={mdiKeyVariant} onClose={() => handleDone()}>
|
||||||
<div
|
<div class="text-immich-primary dark:text-immich-dark-primary">
|
||||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
|
||||||
>
|
|
||||||
<Icon path={mdiKeyVariant} size="4em" />
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">API Key</h1>
|
|
||||||
|
|
||||||
<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.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<!-- <label class="immich-form-label" for="secret">API Key</label> -->
|
<!-- <label class="immich-form-label" for="secret">API Key</label> -->
|
||||||
<textarea class="immich-form-input" id="secret" name="secret" readonly={true} value={secret} />
|
<textarea class="immich-form-input" id="secret" name="secret" readonly={true} value={secret} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
{#if canCopyImagesToClipboard}
|
{#if canCopyImagesToClipboard}
|
||||||
<Button on:click={() => copyToClipboard(secret)} fullwidth>Copy to Clipboard</Button>
|
<Button on:click={() => copyToClipboard(secret)} fullwidth>Copy to Clipboard</Button>
|
||||||
{/if}
|
{/if}
|
||||||
<Button on:click={() => handleDone()} fullwidth>Done</Button>
|
<Button on:click={() => handleDone()} fullwidth>Done</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
import { createUser } from '@immich/sdk';
|
import { createUser } from '@immich/sdk';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import ImmichLogo from '../shared-components/immich-logo.svelte';
|
|
||||||
import PasswordField from '../shared-components/password-field.svelte';
|
import PasswordField from '../shared-components/password-field.svelte';
|
||||||
import Slider from '../elements/slider.svelte';
|
import Slider from '../elements/slider.svelte';
|
||||||
|
|
||||||
|
@ -69,43 +68,35 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<form on:submit|preventDefault={registerUser} autocomplete="off">
|
||||||
class="max-h-screen w-[500px] max-w-[95vw] overflow-y-auto immich-scrollbar rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
<div class="my-4 flex flex-col gap-2">
|
||||||
>
|
|
||||||
<div class="flex flex-col place-content-center place-items-center gap-4 px-4">
|
|
||||||
<ImmichLogo noText class="text-center" height="75" width="75" />
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Create new user</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={registerUser} autocomplete="off">
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
|
||||||
<label class="immich-form-label" for="email">Email</label>
|
<label class="immich-form-label" for="email">Email</label>
|
||||||
<input class="immich-form-input" id="email" bind:value={email} type="email" required />
|
<input class="immich-form-input" id="email" bind:value={email} type="email" required />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="password">Password</label>
|
<label class="immich-form-label" for="password">Password</label>
|
||||||
<PasswordField id="password" bind:password autocomplete="new-password" />
|
<PasswordField id="password" bind:password autocomplete="new-password" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="confirmPassword">Confirm Password</label>
|
<label class="immich-form-label" for="confirmPassword">Confirm Password</label>
|
||||||
<PasswordField id="confirmPassword" bind:password={confirmPassword} autocomplete="new-password" />
|
<PasswordField id="confirmPassword" bind:password={confirmPassword} autocomplete="new-password" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex place-items-center justify-between gap-2">
|
<div class="my-4 flex place-items-center justify-between gap-2">
|
||||||
<label class="text-sm dark:text-immich-dark-fg" for="require-password-change">
|
<label class="text-sm dark:text-immich-dark-fg" for="require-password-change">
|
||||||
Require user to change password on first login
|
Require user to change password on first login
|
||||||
</label>
|
</label>
|
||||||
<Slider id="require-password-change" bind:checked={shouldChangePassword} />
|
<Slider id="require-password-change" bind:checked={shouldChangePassword} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="name">Name</label>
|
<label class="immich-form-label" for="name">Name</label>
|
||||||
<input class="immich-form-input" id="name" bind:value={name} type="text" required />
|
<input class="immich-form-input" id="name" bind:value={name} type="text" required />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="flex items-center gap-2 immich-form-label" for="quotaSize">
|
<label class="flex items-center gap-2 immich-form-label" for="quotaSize">
|
||||||
Quota Size (GiB)
|
Quota Size (GiB)
|
||||||
{#if quotaSizeWarning}
|
{#if quotaSizeWarning}
|
||||||
|
@ -116,15 +107,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if error}
|
{#if error}
|
||||||
<p class="ml-4 text-sm text-red-400">{error}</p>
|
<p class="text-sm text-red-400">{error}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if success}
|
{#if success}
|
||||||
<p class="ml-4 text-sm text-immich-primary">{success}</p>
|
<p class="text-sm text-immich-primary">{success}</p>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex w-full gap-4 p-4">
|
<div class="flex w-full gap-4 pt-4">
|
||||||
<Button color="gray" fullwidth on:click={() => dispatch('cancel')}>Cancel</Button>
|
<Button color="gray" fullwidth on:click={() => dispatch('cancel')}>Cancel</Button>
|
||||||
<Button type="submit" disabled={isCreatingUser} fullwidth>Create</Button>
|
<Button type="submit" disabled={isCreatingUser} fullwidth>Create</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
|
|
|
@ -34,16 +34,7 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<form on:submit|preventDefault={handleUpdateAlbumInfo} autocomplete="off">
|
||||||
class="max-h-screen w-[700px] max-w-[95vw] overflow-y-auto rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 mb-4 text-immich-primary dark:text-immich-dark-primary"
|
|
||||||
>
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Edit Album</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={handleUpdateAlbumInfo} autocomplete="off">
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="hidden sm:flex">
|
<div class="hidden sm:flex">
|
||||||
<AlbumCover {album} css="h-[200px] w-[200px] m-4 shadow-lg" />
|
<AlbumCover {album} css="h-[200px] w-[200px] m-4 shadow-lg" />
|
||||||
|
@ -63,10 +54,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div class="mt-8 flex w-full sm:w-2/3 gap-4 px-4">
|
<div class="mt-8 flex w-full sm:w-2/3 gap-4">
|
||||||
<Button color="gray" fullwidth on:click={() => onCancel?.()}>Cancel</Button>
|
<Button color="gray" fullwidth on:click={() => onCancel?.()}>Cancel</Button>
|
||||||
<Button type="submit" fullwidth disabled={isSubmitting}>OK</Button>
|
<Button type="submit" fullwidth disabled={isSubmitting}>OK</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import { serverInfo } from '$lib/stores/server-info.store';
|
import { serverInfo } from '$lib/stores/server-info.store';
|
||||||
import { convertFromBytes, convertToBytes } from '$lib/utils/byte-converter';
|
import { convertFromBytes, convertToBytes } from '$lib/utils/byte-converter';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { updateUser, type UserResponseDto } from '@immich/sdk';
|
import { updateUser, type UserResponseDto } from '@immich/sdk';
|
||||||
import { mdiAccountEditOutline, mdiClose } from '@mdi/js';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
|
|
||||||
|
|
||||||
export let user: UserResponseDto;
|
export let user: UserResponseDto;
|
||||||
export let canResetPassword = true;
|
export let canResetPassword = true;
|
||||||
|
@ -91,33 +87,18 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FocusTrap>
|
<form on:submit|preventDefault={editUser} autocomplete="off">
|
||||||
<div
|
<div class="my-4 flex flex-col gap-2">
|
||||||
class="relative max-h-screen w-[500px] max-w-[95vw] overflow-y-auto rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<div class="absolute top-0 right-0 px-2 py-2 h-fit">
|
|
||||||
<CircleIconButton title="Close" icon={mdiClose} on:click={() => dispatch('close')} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
|
||||||
>
|
|
||||||
<Icon path={mdiAccountEditOutline} size="4em" />
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Edit user</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={editUser} autocomplete="off">
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
|
||||||
<label class="immich-form-label" for="email">Email</label>
|
<label class="immich-form-label" for="email">Email</label>
|
||||||
<input class="immich-form-input" id="email" name="email" type="email" bind:value={user.email} />
|
<input class="immich-form-input" id="email" name="email" type="email" bind:value={user.email} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="name">Name</label>
|
<label class="immich-form-label" for="name">Name</label>
|
||||||
<input class="immich-form-input" id="name" name="name" type="text" required bind:value={user.name} />
|
<input class="immich-form-input" id="name" name="name" type="text" required bind:value={user.name} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="flex items-center gap-2 immich-form-label" for="quotaSize"
|
<label class="flex items-center gap-2 immich-form-label" for="quotaSize"
|
||||||
>Quota Size (GiB) {#if quotaSizeWarning}
|
>Quota Size (GiB) {#if quotaSizeWarning}
|
||||||
<p class="text-red-400 text-sm">You set a quota higher than the disk size</p>
|
<p class="text-red-400 text-sm">You set a quota higher than the disk size</p>
|
||||||
|
@ -127,7 +108,7 @@
|
||||||
<p>Note: Enter 0 for unlimited quota</p>
|
<p>Note: Enter 0 for unlimited quota</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="storage-label">Storage Label</label>
|
<label class="immich-form-label" for="storage-label">Storage Label</label>
|
||||||
<input
|
<input
|
||||||
class="immich-form-input"
|
class="immich-form-input"
|
||||||
|
@ -139,9 +120,7 @@
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Note: To apply the Storage Label to previously uploaded assets, run the
|
Note: To apply the Storage Label to previously uploaded assets, run the
|
||||||
<a href={AppRoute.ADMIN_JOBS} class="text-immich-primary dark:text-immich-dark-primary">
|
<a href={AppRoute.ADMIN_JOBS} class="text-immich-primary dark:text-immich-dark-primary"> Storage Migration Job</a>
|
||||||
Storage Migration Job</a
|
|
||||||
>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -152,7 +131,7 @@
|
||||||
{#if success}
|
{#if success}
|
||||||
<p class="ml-4 text-sm text-immich-primary">{success}</p>
|
<p class="ml-4 text-sm text-immich-primary">{success}</p>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
{#if canResetPassword}
|
{#if canResetPassword}
|
||||||
<Button color="light-red" fullwidth on:click={() => (isShowResetPasswordConfirmation = true)}
|
<Button color="light-red" fullwidth on:click={() => (isShowResetPasswordConfirmation = true)}
|
||||||
>Reset password</Button
|
>Reset password</Button
|
||||||
|
@ -160,13 +139,12 @@
|
||||||
{/if}
|
{/if}
|
||||||
<Button type="submit" fullwidth>Confirm</Button>
|
<Button type="submit" fullwidth>Confirm</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</FocusTrap>
|
|
||||||
|
|
||||||
{#if isShowResetPasswordConfirmation}
|
{#if isShowResetPasswordConfirmation}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Reset Password"
|
id="reset-password-modal"
|
||||||
|
title="Reset password"
|
||||||
confirmText="Reset"
|
confirmText="Reset"
|
||||||
onConfirm={resetPassword}
|
onConfirm={resetPassword}
|
||||||
onClose={() => (isShowResetPasswordConfirmation = false)}
|
onClose={() => (isShowResetPasswordConfirmation = false)}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import { mdiFolderRemove } from '@mdi/js';
|
import { mdiFolderRemove } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
@ -29,26 +28,21 @@
|
||||||
const handleSubmit = () => dispatch('submit', { excludePattern: exclusionPattern });
|
const handleSubmit = () => dispatch('submit', { excludePattern: exclusionPattern });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={handleCancel}>
|
<FullScreenModal
|
||||||
<div
|
id="add-exclusion-pattern-modal"
|
||||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
title="Add exclusion pattern"
|
||||||
>
|
icon={mdiFolderRemove}
|
||||||
<div
|
onClose={handleCancel}
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
>
|
||||||
>
|
|
||||||
<Icon path={mdiFolderRemove} size="4em" />
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Add Exclusion pattern</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
||||||
<p class="p-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
|
||||||
folders that contain files you don't want to import, such as RAW files.
|
folders that contain files you don't want to import, such as RAW files.
|
||||||
<br /><br />
|
<br /><br />
|
||||||
Add exclusion patterns. Globbing using *, **, and ? is supported. To ignore all files in any directory named "Raw",
|
Add exclusion patterns. Globbing using *, **, and ? is supported. To ignore all files in any directory named "Raw",
|
||||||
use "**/Raw/**". To ignore all files ending in ".tif", use "**/*.tif". To ignore an absolute path, use "/path/to/ignore".
|
use "**/Raw/**". To ignore all files ending in ".tif", use "**/*.tif". To ignore an absolute path, use "/path/to/ignore".
|
||||||
</p>
|
</p>
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="exclusionPattern">Pattern</label>
|
<label class="immich-form-label" for="exclusionPattern">Pattern</label>
|
||||||
<input
|
<input
|
||||||
class="immich-form-input"
|
class="immich-form-input"
|
||||||
|
@ -58,7 +52,7 @@
|
||||||
bind:value={exclusionPattern}
|
bind:value={exclusionPattern}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
<Button color="gray" fullwidth on:click={() => handleCancel()}>Cancel</Button>
|
<Button color="gray" fullwidth on:click={() => handleCancel()}>Cancel</Button>
|
||||||
{#if isEditing}
|
{#if isEditing}
|
||||||
<Button color="red" fullwidth on:click={() => dispatch('delete')}>Delete</Button>
|
<Button color="red" fullwidth on:click={() => dispatch('delete')}>Delete</Button>
|
||||||
|
@ -66,11 +60,10 @@
|
||||||
|
|
||||||
<Button type="submit" disabled={!canSubmit} fullwidth>{submitText}</Button>
|
<Button type="submit" disabled={!canSubmit} fullwidth>{submitText}</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
{#if isDuplicate}
|
{#if isDuplicate}
|
||||||
<p class="text-red-500 text-sm">This exclusion pattern already exists.</p>
|
<p class="text-red-500 text-sm">This exclusion pattern already exists.</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||||
import { mdiFolderSync } from '@mdi/js';
|
import { mdiFolderSync } from '@mdi/js';
|
||||||
|
@ -31,32 +30,18 @@
|
||||||
const handleSubmit = () => dispatch('submit', { importPath });
|
const handleSubmit = () => dispatch('submit', { importPath });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={handleCancel}>
|
<FullScreenModal id="library-import-path-modal" {title} icon={mdiFolderSync} onClose={handleCancel}>
|
||||||
<div
|
|
||||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
|
||||||
>
|
|
||||||
<Icon path={mdiFolderSync} size="4em" />
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">
|
|
||||||
{title}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
||||||
<p class="p-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. Note that
|
Specify a folder to import. This folder, including subfolders, will be scanned for images and videos.
|
||||||
you are only allowed to import paths inside of your account's external path, configured in the administrative
|
|
||||||
settings.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="m-4 flex flex-col gap-2">
|
<div class="my-4 flex flex-col gap-2">
|
||||||
<label class="immich-form-label" for="path">Path</label>
|
<label class="immich-form-label" for="path">Path</label>
|
||||||
<input class="immich-form-input" id="path" name="path" type="text" bind:value={importPath} />
|
<input class="immich-form-input" id="path" name="path" type="text" bind:value={importPath} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
<Button color="gray" fullwidth on:click={() => handleCancel()}>{cancelText}</Button>
|
<Button color="gray" fullwidth on:click={() => handleCancel()}>{cancelText}</Button>
|
||||||
{#if isEditing}
|
{#if isEditing}
|
||||||
<Button color="red" fullwidth on:click={() => dispatch('delete')}>Delete</Button>
|
<Button color="red" fullwidth on:click={() => dispatch('delete')}>Delete</Button>
|
||||||
|
@ -65,11 +50,10 @@
|
||||||
<Button type="submit" disabled={!canSubmit} fullwidth>{submitText}</Button>
|
<Button type="submit" disabled={!canSubmit} fullwidth>{submitText}</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
{#if isDuplicate}
|
{#if isDuplicate}
|
||||||
<p class="text-red-500 text-sm">This import path already exists.</p>
|
<p class="text-red-500 text-sm">This import path already exists.</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -152,7 +152,7 @@
|
||||||
|
|
||||||
{#if addImportPath}
|
{#if addImportPath}
|
||||||
<LibraryImportPathForm
|
<LibraryImportPathForm
|
||||||
title="Add Import Path"
|
title="Add import path"
|
||||||
submitText="Add"
|
submitText="Add"
|
||||||
bind:importPath={importPathToAdd}
|
bind:importPath={importPathToAdd}
|
||||||
{importPaths}
|
{importPaths}
|
||||||
|
@ -166,7 +166,7 @@
|
||||||
|
|
||||||
{#if editImportPath != undefined}
|
{#if editImportPath != undefined}
|
||||||
<LibraryImportPathForm
|
<LibraryImportPathForm
|
||||||
title="Edit Import Path"
|
title="Edit import path"
|
||||||
submitText="Save"
|
submitText="Save"
|
||||||
isEditing={true}
|
isEditing={true}
|
||||||
bind:importPath={editedImportPath}
|
bind:importPath={editedImportPath}
|
||||||
|
|
|
@ -169,7 +169,7 @@
|
||||||
size="sm"
|
size="sm"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
addExclusionPattern = true;
|
addExclusionPattern = true;
|
||||||
}}>Add Exclusion Pattern</Button
|
}}>Add exclusion pattern</Button
|
||||||
></td
|
></td
|
||||||
></tr
|
></tr
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||||
import { mdiFolderSync } from '@mdi/js';
|
import { mdiFolderSync } from '@mdi/js';
|
||||||
|
@ -28,27 +27,21 @@
|
||||||
const handleSubmit = () => dispatch('submit', { ownerId });
|
const handleSubmit = () => dispatch('submit', { ownerId });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={handleCancel}>
|
<FullScreenModal
|
||||||
<div
|
id="select-library-owner-modal"
|
||||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
title="Select library owner"
|
||||||
>
|
icon={mdiFolderSync}
|
||||||
<div
|
onClose={handleCancel}
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
>
|
||||||
>
|
|
||||||
<Icon path={mdiFolderSync} size="4em" />
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Select library owner</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
||||||
<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>
|
||||||
|
|
||||||
<SettingSelect bind:value={ownerId} options={userOptions} name="user" />
|
<SettingSelect bind:value={ownerId} options={userOptions} name="user" />
|
||||||
|
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
<Button color="gray" fullwidth on:click={() => handleCancel()}>Cancel</Button>
|
<Button color="gray" fullwidth on:click={() => handleCancel()}>Cancel</Button>
|
||||||
|
|
||||||
<Button type="submit" fullwidth>Create</Button>
|
<Button type="submit" fullwidth>Create</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -21,12 +21,7 @@
|
||||||
const handleClose = () => dispatch('close');
|
const handleClose = () => dispatch('close');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={handleClose}>
|
<FullScreenModal id="map-settings-modal" title="Map settings" onClose={handleClose}>
|
||||||
<div
|
|
||||||
class="flex w-96 max-w-lg flex-col gap-8 rounded-3xl border bg-white p-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray"
|
|
||||||
>
|
|
||||||
<h1 class="self-center text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Map Settings</h1>
|
|
||||||
|
|
||||||
<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"
|
||||||
|
@ -114,5 +109,4 @@
|
||||||
<Button type="submit" size="sm" fullwidth>Save</Button>
|
<Button type="submit" size="sm" fullwidth>Save</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
|
|
||||||
{#if isShowConfirmation}
|
{#if isShowConfirmation}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="remove-from-album-modal"
|
||||||
title="Remove from {album.albumName}"
|
title="Remove from {album.albumName}"
|
||||||
confirmText="Remove"
|
confirmText="Remove"
|
||||||
onConfirm={removeFromAlbum}
|
onConfirm={removeFromAlbum}
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
|
|
||||||
{#if removing}
|
{#if removing}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Remove Assets?"
|
id="remove-assets-modal"
|
||||||
|
title="Remove assets?"
|
||||||
prompt="Are you sure you want to remove {getAssets().size} asset(s) from this shared link?"
|
prompt="Are you sure you want to remove {getAssets().size} asset(s) from this shared link?"
|
||||||
confirmText="Remove"
|
confirmText="Remove"
|
||||||
onConfirm={() => handleRemove()}
|
onConfirm={() => handleRemove()}
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Permanently Delete Asset{size > 1 ? 's' : ''}"
|
id="permanently-delete-asset-modal"
|
||||||
|
title="Permanently delete asset{size > 1 ? 's' : ''}"
|
||||||
confirmText="Delete"
|
confirmText="Delete"
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
onClose={() => dispatch('cancel')}
|
onClose={() => dispatch('cancel')}
|
||||||
|
|
|
@ -3,12 +3,9 @@
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
|
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
import { mdiClose } from '@mdi/js';
|
|
||||||
import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
|
import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
|
||||||
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
import ModalHeader from '$lib/components/shared-components/modal-header.svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
close: void;
|
close: void;
|
||||||
|
@ -28,6 +25,8 @@
|
||||||
*/
|
*/
|
||||||
export let icon: string | undefined = undefined;
|
export let icon: string | undefined = undefined;
|
||||||
|
|
||||||
|
$: titleId = `${id}-title`;
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (browser) {
|
if (browser) {
|
||||||
const scrollTop = document.documentElement.scrollTop;
|
const scrollTop = document.documentElement.scrollTop;
|
||||||
|
@ -51,7 +50,7 @@
|
||||||
<FocusTrap>
|
<FocusTrap>
|
||||||
<div
|
<div
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
aria-labelledby={`${id}-title`}
|
aria-labelledby={titleId}
|
||||||
style:z-index={zIndex}
|
style:z-index={zIndex}
|
||||||
transition:fade={{ duration: 100, easing: quintOut }}
|
transition:fade={{ duration: 100, easing: quintOut }}
|
||||||
class="fixed left-0 top-0 flex h-full w-full place-content-center place-items-center overflow-hidden bg-black/50"
|
class="fixed left-0 top-0 flex h-full w-full place-content-center place-items-center overflow-hidden bg-black/50"
|
||||||
|
@ -61,23 +60,11 @@
|
||||||
onOutclick: () => dispatch('close'),
|
onOutclick: () => dispatch('close'),
|
||||||
onEscape: () => dispatch('close'),
|
onEscape: () => dispatch('close'),
|
||||||
}}
|
}}
|
||||||
class="max-h-[800px] min-h-[200px] w-[450px] overflow-y-auto rounded-3xl bg-immich-bg shadow-md dark:bg-immich-dark-gray dark:text-immich-dark-fg immich-scrollbar"
|
class="min-h-[200px] w-[450px] overflow-y-auto rounded-3xl bg-immich-bg shadow-md dark:bg-immich-dark-gray dark:text-immich-dark-fg immich-scrollbar scroll-pb-20"
|
||||||
|
style="max-height: min(95vh, 800px);"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
>
|
>
|
||||||
<div class="flex place-items-center justify-between px-5 py-3">
|
<ModalHeader id={titleId} {title} {showLogo} {icon} on:close />
|
||||||
<div class="flex gap-2 place-items-center">
|
|
||||||
{#if showLogo}
|
|
||||||
<ImmichLogo noText={true} width={32} />
|
|
||||||
{:else if icon}
|
|
||||||
<Icon path={icon} size={32} ariaHidden={true} class="text-immich-primary dark:text-immich-dark-primary" />
|
|
||||||
{/if}
|
|
||||||
<h1 id={`${id}-title`}>
|
|
||||||
{title}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CircleIconButton on:click={() => dispatch('close')} icon={mdiClose} size={'20'} title="Close" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -63,16 +63,16 @@
|
||||||
|
|
||||||
<div role="presentation" on:keydown={handleKeydown}>
|
<div role="presentation" on:keydown={handleKeydown}>
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="edit-date-time-modal"
|
||||||
confirmColor="primary"
|
confirmColor="primary"
|
||||||
cancelColor="secondary"
|
cancelColor="secondary"
|
||||||
title="Edit date & time"
|
title="Edit date and time"
|
||||||
prompt="Please select a new date:"
|
prompt="Please select a new date:"
|
||||||
disabled={!date.isValid}
|
disabled={!date.isValid}
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
onClose={handleCancel}
|
onClose={handleCancel}
|
||||||
>
|
>
|
||||||
<div class="flex flex-col text-md px-4 text-center gap-2" slot="prompt">
|
<div class="flex flex-col text-md px-4 text-center gap-2" slot="prompt">
|
||||||
<div class="mt-2" />
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label for="datetime">Date and Time</label>
|
<label for="datetime">Date and Time</label>
|
||||||
<DateInput
|
<DateInput
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
import SearchBar from '../elements/search-bar.svelte';
|
import SearchBar from '../elements/search-bar.svelte';
|
||||||
import { listNavigation } from '$lib/utils/list-navigation';
|
import { listNavigation } from '$lib/utils/list-navigation';
|
||||||
|
|
||||||
export const title = 'Change Location';
|
|
||||||
export let asset: AssetResponseDto | undefined = undefined;
|
export let asset: AssetResponseDto | undefined = undefined;
|
||||||
|
|
||||||
interface Point {
|
interface Point {
|
||||||
|
@ -95,10 +94,11 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="change-location-modal"
|
||||||
confirmColor="primary"
|
confirmColor="primary"
|
||||||
cancelColor="secondary"
|
cancelColor="secondary"
|
||||||
title="Change Location"
|
title="Change location"
|
||||||
width={800}
|
width="wide"
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
onClose={handleCancel}
|
onClose={handleCancel}
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
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;
|
||||||
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';
|
||||||
|
@ -11,7 +12,7 @@
|
||||||
export let cancelColor: Color = 'primary';
|
export let cancelColor: Color = 'primary';
|
||||||
export let hideCancelButton = false;
|
export let hideCancelButton = false;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let width = 500;
|
export let width: 'wide' | 'narrow' = 'narrow';
|
||||||
export let onClose: () => void;
|
export let onClose: () => void;
|
||||||
export let onConfirm: () => void;
|
export let onConfirm: () => void;
|
||||||
|
|
||||||
|
@ -23,26 +24,14 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal {onClose}>
|
<FullScreenModal {title} {id} {onClose} {width}>
|
||||||
<div
|
<div class="text-md py-5 text-center">
|
||||||
class="max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
style="width: {width}px"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
|
||||||
>
|
|
||||||
<h1 class="pb-2 text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">
|
|
||||||
{title}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="text-md px-4 py-5 text-center">
|
|
||||||
<slot name="prompt">
|
<slot name="prompt">
|
||||||
<p>{prompt}</p>
|
<p>{prompt}</p>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 flex w-full gap-4 px-4">
|
<div class="mt-4 flex flex-col sm:flex-row w-full gap-4">
|
||||||
{#if !hideCancelButton}
|
{#if !hideCancelButton}
|
||||||
<Button color={cancelColor} fullwidth on:click={onClose}>
|
<Button color={cancelColor} fullwidth on:click={onClose}>
|
||||||
{cancelText}
|
{cancelText}
|
||||||
|
@ -52,6 +41,4 @@
|
||||||
{confirmText}
|
{confirmText}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -2,8 +2,44 @@
|
||||||
import { clickOutside } from '../../utils/click-outside';
|
import { clickOutside } from '../../utils/click-outside';
|
||||||
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';
|
||||||
|
|
||||||
export let onClose: (() => void) | undefined = undefined;
|
export let onClose: () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier for the modal.
|
||||||
|
*/
|
||||||
|
export let id: string;
|
||||||
|
export let title: string;
|
||||||
|
/**
|
||||||
|
* If true, the logo will be displayed next to the modal title.
|
||||||
|
*/
|
||||||
|
export let showLogo = false;
|
||||||
|
/**
|
||||||
|
* Optional icon to display next to the modal title, if `showLogo` is false.
|
||||||
|
*/
|
||||||
|
export let icon: string | undefined = undefined;
|
||||||
|
/**
|
||||||
|
* Sets the width of the modal.
|
||||||
|
*
|
||||||
|
* - `wide`: 750px
|
||||||
|
* - `narrow`: 450px
|
||||||
|
* - `auto`: fits the width of the modal content, up to a maximum of 550px
|
||||||
|
*/
|
||||||
|
export let width: 'wide' | 'narrow' | 'auto' = 'narrow';
|
||||||
|
|
||||||
|
$: titleId = `${id}-title`;
|
||||||
|
|
||||||
|
let modalWidth: string;
|
||||||
|
$: {
|
||||||
|
if (width === 'wide') {
|
||||||
|
modalWidth = 'w-[750px]';
|
||||||
|
} else if (width === 'narrow') {
|
||||||
|
modalWidth = 'w-[450px]';
|
||||||
|
} else {
|
||||||
|
modalWidth = 'sm:max-w-[550px]';
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FocusTrap>
|
<FocusTrap>
|
||||||
|
@ -12,8 +48,17 @@
|
||||||
out:fade={{ duration: 100 }}
|
out:fade={{ duration: 100 }}
|
||||||
class="fixed left-0 top-0 z-[9990] flex h-screen w-screen place-content-center place-items-center bg-black/40"
|
class="fixed left-0 top-0 z-[9990] flex h-screen w-screen place-content-center place-items-center bg-black/40"
|
||||||
>
|
>
|
||||||
<div class="z-[9999]" use:clickOutside={{ onOutclick: onClose, onEscape: onClose }} tabindex="-1">
|
<div
|
||||||
|
class="z-[9999] max-w-[95vw] max-h-[95vh] {modalWidth} overflow-y-auto rounded-3xl bg-immich-bg shadow-md dark:bg-immich-dark-gray dark:text-immich-dark-fg immich-scrollbar"
|
||||||
|
use:clickOutside={{ onOutclick: onClose, onEscape: onClose }}
|
||||||
|
tabindex="-1"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-labelledby={titleId}
|
||||||
|
>
|
||||||
|
<ModalHeader id={titleId} {title} {showLogo} {icon} on:close={() => onClose?.()} />
|
||||||
|
<div class="p-5 pt-0">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</FocusTrap>
|
</FocusTrap>
|
||||||
|
|
40
web/src/lib/components/shared-components/modal-header.svelte
Normal file
40
web/src/lib/components/shared-components/modal-header.svelte
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { mdiClose } from '@mdi/js';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher<{
|
||||||
|
close: void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier for the header text.
|
||||||
|
*/
|
||||||
|
export let id: string;
|
||||||
|
export let title: string;
|
||||||
|
/**
|
||||||
|
* If true, the logo will be displayed next to the modal title.
|
||||||
|
*/
|
||||||
|
export let showLogo = false;
|
||||||
|
/**
|
||||||
|
* Optional icon to display next to the modal title, if `showLogo` is false.
|
||||||
|
*/
|
||||||
|
export let icon: string | undefined = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex place-items-center justify-between px-5 py-3">
|
||||||
|
<div class="flex gap-2 place-items-center">
|
||||||
|
{#if showLogo}
|
||||||
|
<ImmichLogo noText={true} width={32} />
|
||||||
|
{:else if icon}
|
||||||
|
<Icon path={icon} size={32} ariaHidden={true} class="text-immich-primary dark:text-immich-dark-primary" />
|
||||||
|
{/if}
|
||||||
|
<h1 {id}>
|
||||||
|
{title}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CircleIconButton on:click={() => dispatch('close')} icon={mdiClose} size={'20'} title="Close" />
|
||||||
|
</div>
|
|
@ -1,7 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
|
||||||
import { UserAvatarColor, type UserResponseDto } from '@immich/sdk';
|
import { UserAvatarColor, type UserResponseDto } from '@immich/sdk';
|
||||||
import { mdiClose } from '@mdi/js';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import FullScreenModal from '../full-screen-modal.svelte';
|
import FullScreenModal from '../full-screen-modal.svelte';
|
||||||
import UserAvatar from '../user-avatar.svelte';
|
import UserAvatar from '../user-avatar.svelte';
|
||||||
|
@ -15,20 +13,8 @@
|
||||||
const colors: UserAvatarColor[] = Object.values(UserAvatarColor);
|
const colors: UserAvatarColor[] = Object.values(UserAvatarColor);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={() => dispatch('close')}>
|
<FullScreenModal id="avatar-selector-modal" title="Select avatar color" width="auto" onClose={() => dispatch('close')}>
|
||||||
<div class="flex h-full w-full place-content-center place-items-center overflow-hidden">
|
<div class="flex items-center justify-center mt-4">
|
||||||
<div
|
|
||||||
class=" rounded-3xl border bg-immich-bg shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg p-4"
|
|
||||||
>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<h1 class="px-4 w-full self-center font-medium text-immich-primary dark:text-immich-dark-primary text-sm">
|
|
||||||
SELECT AVATAR COLOR
|
|
||||||
</h1>
|
|
||||||
<div>
|
|
||||||
<CircleIconButton icon={mdiClose} title="Close" on:click={() => dispatch('close')} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-center p-4 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}
|
||||||
<button on:click={() => dispatch('choose', color)}>
|
<button on:click={() => dispatch('choose', color)}>
|
||||||
|
@ -37,6 +23,4 @@
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import FullScreenModal from './full-screen-modal.svelte';
|
import FullScreenModal from './full-screen-modal.svelte';
|
||||||
import { mdiClose, mdiInformationOutline } from '@mdi/js';
|
import { mdiInformationOutline } from '@mdi/js';
|
||||||
import Icon from '../elements/icon.svelte';
|
import Icon from '../elements/icon.svelte';
|
||||||
|
|
||||||
interface Shortcuts {
|
interface Shortcuts {
|
||||||
|
@ -38,29 +37,21 @@
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal onClose={() => dispatch('close')}>
|
<FullScreenModal
|
||||||
<div class="flex h-full w-full place-content-center place-items-center overflow-hidden">
|
id="keyboard-shortcuts-modal"
|
||||||
<div
|
title="Keyboard shortcuts"
|
||||||
class="rounded-3xl border bg-immich-bg shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
width="auto"
|
||||||
>
|
onClose={() => dispatch('close')}
|
||||||
<div class="relative px-4 pt-4">
|
>
|
||||||
<h1 class="px-4 py-4 font-medium text-immich-primary dark:text-immich-dark-primary">Keyboard Shortcuts</h1>
|
|
||||||
<div class="absolute inset-y-0 right-0 px-4 py-4">
|
|
||||||
<CircleIconButton title="Close" icon={mdiClose} on:click={() => dispatch('close')} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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="px-4 py-4">
|
<div class="p-4">
|
||||||
<h2>General</h2>
|
<h2>General</h2>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{#each shortcuts.general as shortcut}
|
{#each shortcuts.general as shortcut}
|
||||||
<div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm">
|
<div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm">
|
||||||
<div class="flex justify-self-end">
|
<div class="flex justify-self-end">
|
||||||
{#each shortcut.key as key}
|
{#each shortcut.key as key}
|
||||||
<p
|
<p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2">
|
||||||
class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2"
|
|
||||||
>
|
|
||||||
{key}
|
{key}
|
||||||
</p>
|
</p>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -71,16 +62,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="px-4 py-4">
|
<div class="p-4">
|
||||||
<h2>Actions</h2>
|
<h2>Actions</h2>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{#each shortcuts.actions as shortcut}
|
{#each shortcuts.actions as shortcut}
|
||||||
<div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm">
|
<div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm">
|
||||||
<div class="flex justify-self-end">
|
<div class="flex justify-self-end">
|
||||||
{#each shortcut.key as key}
|
{#each shortcut.key as key}
|
||||||
<p
|
<p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2">
|
||||||
class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2"
|
|
||||||
>
|
|
||||||
{key}
|
{key}
|
||||||
</p>
|
</p>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -96,6 +85,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -33,12 +33,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if showModal}
|
{#if showModal}
|
||||||
<FullScreenModal onClose={() => (showModal = false)}>
|
<FullScreenModal id="new-version-modal" title="🎉 NEW VERSION AVAILABLE" onClose={() => (showModal = false)}>
|
||||||
<div
|
|
||||||
class="max-w-lg rounded-3xl border bg-immich-bg px-8 py-10 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<p class="mb-4 text-2xl">🎉 NEW VERSION AVAILABLE 🎉</p>
|
|
||||||
|
|
||||||
<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"
|
||||||
|
@ -61,6 +56,5 @@
|
||||||
<div class="mt-8 text-right">
|
<div class="mt-8 text-right">
|
||||||
<Button fullwidth on:click={onAcknowledge}>Acknowledge</Button>
|
<Button fullwidth on:click={onAcknowledge}>Acknowledge</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -30,14 +30,7 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal {onClose}>
|
<FullScreenModal id="slideshow-settings-modal" title="Slideshow settings" {onClose}>
|
||||||
<div
|
|
||||||
class="flex w-full md:w-96 max-w-lg flex-col gap-8 rounded-3xl border bg-white p-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray"
|
|
||||||
>
|
|
||||||
<h1 class="self-center text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">
|
|
||||||
Slideshow Settings
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<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"
|
||||||
|
@ -53,8 +46,6 @@
|
||||||
min={1}
|
min={1}
|
||||||
bind:value={$slideshowDelay}
|
bind:value={$slideshowDelay}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button class="w-full" color="gray" on:click={onClose}>Done</Button>
|
<Button class="w-full" color="gray" on:click={onClose}>Done</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
|
|
||||||
{#if deleteDevice}
|
{#if deleteDevice}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="log-out-device-modal"
|
||||||
prompt="Are you sure you want to log out this device?"
|
prompt="Are you sure you want to log out this device?"
|
||||||
onConfirm={() => handleDelete()}
|
onConfirm={() => handleDelete()}
|
||||||
onClose={() => (deleteDevice = null)}
|
onClose={() => (deleteDevice = null)}
|
||||||
|
@ -57,6 +58,7 @@
|
||||||
|
|
||||||
{#if deleteAll}
|
{#if deleteAll}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="log-out-all-modal"
|
||||||
prompt="Are you sure you want to log out all devices?"
|
prompt="Are you sure you want to log out all devices?"
|
||||||
onConfirm={() => handleDeleteAll()}
|
onConfirm={() => handleDeleteAll()}
|
||||||
onClose={() => (deleteAll = false)}
|
onClose={() => (deleteAll = false)}
|
||||||
|
|
|
@ -189,6 +189,7 @@
|
||||||
|
|
||||||
{#if removePartnerDto}
|
{#if removePartnerDto}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="stop-sharing-photos-modal"
|
||||||
title="Stop sharing your photos?"
|
title="Stop sharing your photos?"
|
||||||
prompt="{removePartnerDto.name} will no longer be able to access your photos."
|
prompt="{removePartnerDto.name} will no longer be able to access your photos."
|
||||||
onClose={() => (removePartnerDto = null)}
|
onClose={() => (removePartnerDto = null)}
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
|
|
||||||
{#if newKey}
|
{#if newKey}
|
||||||
<APIKeyForm
|
<APIKeyForm
|
||||||
title="New API Key"
|
title="New API key"
|
||||||
submitText="Create"
|
submitText="Create"
|
||||||
apiKey={newKey}
|
apiKey={newKey}
|
||||||
on:submit={({ detail }) => handleCreate(detail)}
|
on:submit={({ detail }) => handleCreate(detail)}
|
||||||
|
@ -95,6 +95,7 @@
|
||||||
|
|
||||||
{#if editKey}
|
{#if editKey}
|
||||||
<APIKeyForm
|
<APIKeyForm
|
||||||
|
title="API key"
|
||||||
submitText="Save"
|
submitText="Save"
|
||||||
apiKey={editKey}
|
apiKey={editKey}
|
||||||
on:submit={({ detail }) => handleUpdate(detail)}
|
on:submit={({ detail }) => handleUpdate(detail)}
|
||||||
|
@ -104,7 +105,8 @@
|
||||||
|
|
||||||
{#if deleteKey}
|
{#if deleteKey}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
prompt="Are you sure you want to delete this API Key?"
|
id="confirm-api-key-delete-modal"
|
||||||
|
prompt="Are you sure you want to delete this API key?"
|
||||||
onConfirm={() => handleDelete()}
|
onConfirm={() => handleDelete()}
|
||||||
onClose={() => (deleteKey = null)}
|
onClose={() => (deleteKey = null)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -683,6 +683,7 @@
|
||||||
|
|
||||||
{#if viewMode === ViewMode.CONFIRM_DELETE}
|
{#if viewMode === ViewMode.CONFIRM_DELETE}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="delete-album-modal"
|
||||||
title="Delete album"
|
title="Delete album"
|
||||||
confirmText="Delete"
|
confirmText="Delete"
|
||||||
onConfirm={handleRemoveAlbum}
|
onConfirm={handleRemoveAlbum}
|
||||||
|
|
|
@ -463,24 +463,15 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if showChangeNameModal}
|
{#if showChangeNameModal}
|
||||||
<FullScreenModal onClose={() => (showChangeNameModal = false)}>
|
<FullScreenModal id="change-name-modal" title="Change name" onClose={() => (showChangeNameModal = false)}>
|
||||||
<div
|
|
||||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
|
||||||
>
|
|
||||||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Change name</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={submitNameChange} autocomplete="off">
|
<form on:submit|preventDefault={submitNameChange} autocomplete="off">
|
||||||
<div class="m-4 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>
|
||||||
<!-- svelte-ignore a11y-autofocus -->
|
<!-- svelte-ignore a11y-autofocus -->
|
||||||
<input class="immich-form-input" id="name" name="name" type="text" bind:value={personName} autofocus />
|
<input class="immich-form-input" id="name" name="name" type="text" bind:value={personName} autofocus />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-8 flex w-full gap-4 px-4">
|
<div class="mt-8 flex w-full gap-4">
|
||||||
<Button
|
<Button
|
||||||
color="gray"
|
color="gray"
|
||||||
fullwidth
|
fullwidth
|
||||||
|
@ -491,7 +482,6 @@
|
||||||
<Button type="submit" fullwidth>Ok</Button>
|
<Button type="submit" fullwidth>Ok</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,8 @@
|
||||||
|
|
||||||
{#if deleteLinkId}
|
{#if deleteLinkId}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Delete Shared Link"
|
id="delete-shared-link-modal"
|
||||||
|
title="Delete shared link"
|
||||||
prompt="Are you sure you want to delete this shared link?"
|
prompt="Are you sure you want to delete this shared link?"
|
||||||
confirmText="Delete"
|
confirmText="Delete"
|
||||||
onConfirm={() => handleDeleteLink()}
|
onConfirm={() => handleDeleteLink()}
|
||||||
|
|
|
@ -98,7 +98,8 @@
|
||||||
|
|
||||||
{#if isShowEmptyConfirmation}
|
{#if isShowEmptyConfirmation}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Empty Trash"
|
id="empty-trash-modal"
|
||||||
|
title="Empty trash"
|
||||||
confirmText="Empty"
|
confirmText="Empty"
|
||||||
onConfirm={handleEmptyTrash}
|
onConfirm={handleEmptyTrash}
|
||||||
onClose={() => (isShowEmptyConfirmation = false)}
|
onClose={() => (isShowEmptyConfirmation = false)}
|
||||||
|
|
|
@ -302,6 +302,7 @@
|
||||||
|
|
||||||
{#if confirmDeleteLibrary}
|
{#if confirmDeleteLibrary}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
id="warning-modal"
|
||||||
title="Warning!"
|
title="Warning!"
|
||||||
prompt="Are you sure you want to delete this library? This will delete all {deleteAssetCount} contained assets from Immich and cannot be undone. Files will remain on disk."
|
prompt="Are you sure you want to delete this library? This will delete all {deleteAssetCount} contained assets from Immich and cannot be undone. Files will remain on disk."
|
||||||
onConfirm={handleDelete}
|
onConfirm={handleDelete}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||||
import DeleteConfirmDialog from '$lib/components/admin-page/delete-confirm-dialoge.svelte';
|
import DeleteConfirmDialog from '$lib/components/admin-page/delete-confirm-dialogue.svelte';
|
||||||
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
|
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
|
||||||
import RestoreDialogue from '$lib/components/admin-page/restore-dialoge.svelte';
|
import RestoreDialogue from '$lib/components/admin-page/restore-dialogue.svelte';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import CreateUserForm from '$lib/components/forms/create-user-form.svelte';
|
import CreateUserForm from '$lib/components/forms/create-user-form.svelte';
|
||||||
|
@ -21,7 +21,14 @@
|
||||||
import { asByteUnitString } from '$lib/utils/byte-units';
|
import { asByteUnitString } from '$lib/utils/byte-units';
|
||||||
import { copyToClipboard } from '$lib/utils';
|
import { copyToClipboard } from '$lib/utils';
|
||||||
import { UserStatus, getAllUsers, type UserResponseDto } from '@immich/sdk';
|
import { UserStatus, getAllUsers, type UserResponseDto } from '@immich/sdk';
|
||||||
import { mdiClose, mdiContentCopy, mdiDeleteRestore, mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
|
import {
|
||||||
|
mdiAccountEditOutline,
|
||||||
|
mdiClose,
|
||||||
|
mdiContentCopy,
|
||||||
|
mdiDeleteRestore,
|
||||||
|
mdiPencilOutline,
|
||||||
|
mdiTrashCanOutline,
|
||||||
|
} from '@mdi/js';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
@ -116,13 +123,23 @@
|
||||||
<section id="setting-content" class="flex place-content-center sm:mx-4">
|
<section id="setting-content" class="flex place-content-center sm:mx-4">
|
||||||
<section class="w-full pb-28 lg:w-[850px]">
|
<section class="w-full pb-28 lg:w-[850px]">
|
||||||
{#if shouldShowCreateUserForm}
|
{#if shouldShowCreateUserForm}
|
||||||
<FullScreenModal onClose={() => (shouldShowCreateUserForm = false)}>
|
<FullScreenModal
|
||||||
|
id="create-new-user-modal"
|
||||||
|
title="Create new user"
|
||||||
|
showLogo
|
||||||
|
onClose={() => (shouldShowCreateUserForm = false)}
|
||||||
|
>
|
||||||
<CreateUserForm on:submit={onUserCreated} on:cancel={() => (shouldShowCreateUserForm = false)} />
|
<CreateUserForm on:submit={onUserCreated} on:cancel={() => (shouldShowCreateUserForm = false)} />
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if shouldShowEditUserForm}
|
{#if shouldShowEditUserForm}
|
||||||
<FullScreenModal onClose={() => (shouldShowEditUserForm = false)}>
|
<FullScreenModal
|
||||||
|
id="edit-user-modal"
|
||||||
|
title="Edit user"
|
||||||
|
icon={mdiAccountEditOutline}
|
||||||
|
onClose={() => (shouldShowEditUserForm = false)}
|
||||||
|
>
|
||||||
<EditUserForm
|
<EditUserForm
|
||||||
user={selectedUser}
|
user={selectedUser}
|
||||||
bind:newPassword
|
bind:newPassword
|
||||||
|
@ -153,9 +170,9 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if shouldShowPasswordResetSuccess}
|
{#if shouldShowPasswordResetSuccess}
|
||||||
<FullScreenModal onClose={() => (shouldShowPasswordResetSuccess = false)}>
|
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
title="Password Reset Success"
|
id="password-reset-success-modal"
|
||||||
|
title="Password reset success"
|
||||||
confirmText="Done"
|
confirmText="Done"
|
||||||
onConfirm={() => (shouldShowPasswordResetSuccess = false)}
|
onConfirm={() => (shouldShowPasswordResetSuccess = false)}
|
||||||
onClose={() => (shouldShowPasswordResetSuccess = false)}
|
onClose={() => (shouldShowPasswordResetSuccess = false)}
|
||||||
|
@ -180,13 +197,12 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Please provide the temporary password to the user and inform them they will need to change the
|
Please provide the temporary password to the user and inform them they will need to change the password
|
||||||
password at their next login.
|
at their next login.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ConfirmDialogue>
|
</ConfirmDialogue>
|
||||||
</FullScreenModal>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<table class="my-5 w-full text-left">
|
<table class="my-5 w-full text-left">
|
||||||
|
|
Loading…
Reference in a new issue