refactor(web): prefer modal manager (#22152)

This commit is contained in:
Jason Rasmussen 2025-09-17 17:23:42 -04:00 committed by GitHub
parent eee94207ce
commit 2d816e89ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -13,7 +13,7 @@
type SharedLinkResponseDto, type SharedLinkResponseDto,
type UserResponseDto, type UserResponseDto,
} from '@immich/sdk'; } from '@immich/sdk';
import { Button, Icon, Link, Modal, ModalBody, Stack, Text } from '@immich/ui'; import { Button, Icon, Link, Modal, ModalBody, modalManager, Stack, Text } from '@immich/ui';
import { mdiCheck, mdiEye, mdiLink, mdiPencil } from '@mdi/js'; import { mdiCheck, mdiEye, mdiLink, mdiPencil } from '@mdi/js';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
@ -29,9 +29,11 @@
let users: UserResponseDto[] = $state([]); let users: UserResponseDto[] = $state([]);
let selectedUsers: Record<string, { user: UserResponseDto; role: AlbumUserRole }> = $state({}); let selectedUsers: Record<string, { user: UserResponseDto; role: AlbumUserRole }> = $state({});
let sharedLinkUrl = $state(''); const handleViewQrCode = async (sharedLink: SharedLinkResponseDto) => {
const handleViewQrCode = (sharedLink: SharedLinkResponseDto) => { await modalManager.show(QrCodeModal, {
sharedLinkUrl = makeSharedLinkUrl(sharedLink); title: $t('view_link'),
value: makeSharedLinkUrl(sharedLink),
});
}; };
const roleOptions: Array<{ title: string; value: AlbumUserRole | 'none'; icon?: string }> = [ const roleOptions: Array<{ title: string; value: AlbumUserRole | 'none'; icon?: string }> = [
@ -71,25 +73,64 @@
}; };
</script> </script>
{#if sharedLinkUrl} <Modal size="small" title={$t('share')} {onClose}>
<QrCodeModal title={$t('view_link')} onClose={() => (sharedLinkUrl = '')} value={sharedLinkUrl} /> <ModalBody>
{:else} {#if Object.keys(selectedUsers).length > 0}
<Modal size="small" title={$t('share')} {onClose}> <div class="mb-2 py-2 sticky">
<ModalBody> <p class="text-xs font-medium">{$t('selected')}</p>
{#if Object.keys(selectedUsers).length > 0} <div class="my-2">
<div class="mb-2 py-2 sticky"> {#each Object.values(selectedUsers) as { user } (user.id)}
<p class="text-xs font-medium">{$t('selected')}</p> {#key user.id}
<div class="my-2"> <div class="flex place-items-center gap-4 p-4">
{#each Object.values(selectedUsers) as { user } (user.id)} <div
{#key user.id} class="flex h-10 w-10 items-center justify-center rounded-full border bg-green-600 text-3xl text-white"
<div class="flex place-items-center gap-4 p-4"> >
<div <Icon icon={mdiCheck} size="24" />
class="flex h-10 w-10 items-center justify-center rounded-full border bg-green-600 text-3xl text-white" </div>
>
<Icon icon={mdiCheck} size="24" />
</div>
<!-- <UserAvatar {user} size="md" /> --> <!-- <UserAvatar {user} size="md" /> -->
<div class="text-start grow">
<p class="text-immich-fg dark:text-immich-dark-fg">
{user.name}
</p>
<p class="text-xs">
{user.email}
</p>
</div>
<Dropdown
title={$t('role')}
options={roleOptions}
render={({ title, icon }) => ({ title, icon })}
onSelect={({ value }) => handleChangeRole(user, value)}
/>
</div>
{/key}
{/each}
</div>
</div>
{/if}
{#if users.length + Object.keys(selectedUsers).length === 0}
<p class="p-5 text-sm">
{$t('album_share_no_users')}
</p>
{/if}
<div class="immich-scrollbar max-h-[500px] overflow-y-auto">
{#if users.length > 0 && users.length !== Object.keys(selectedUsers).length}
<Text>{$t('users')}</Text>
<div class="my-2">
{#each users as user (user.id)}
{#if !Object.keys(selectedUsers).includes(user.id)}
<div class="flex place-items-center transition-all hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl">
<button
type="button"
onclick={() => handleToggle(user)}
class="flex w-full place-items-center gap-4 p-4"
>
<UserAvatar {user} size="md" />
<div class="text-start grow"> <div class="text-start grow">
<p class="text-immich-fg dark:text-immich-dark-fg"> <p class="text-immich-fg dark:text-immich-dark-fg">
{user.name} {user.name}
@ -98,96 +139,53 @@
{user.email} {user.email}
</p> </p>
</div> </div>
</button>
<Dropdown </div>
title={$t('role')} {/if}
options={roleOptions} {/each}
render={({ title, icon }) => ({ title, icon })}
onSelect={({ value }) => handleChangeRole(user, value)}
/>
</div>
{/key}
{/each}
</div>
</div> </div>
{/if} {/if}
</div>
{#if users.length + Object.keys(selectedUsers).length === 0} {#if users.length > 0}
<p class="p-5 text-sm"> <div class="py-3">
{$t('album_share_no_users')}
</p>
{/if}
<div class="immich-scrollbar max-h-[500px] overflow-y-auto">
{#if users.length > 0 && users.length !== Object.keys(selectedUsers).length}
<Text>{$t('users')}</Text>
<div class="my-2">
{#each users as user (user.id)}
{#if !Object.keys(selectedUsers).includes(user.id)}
<div class="flex place-items-center transition-all hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl">
<button
type="button"
onclick={() => handleToggle(user)}
class="flex w-full place-items-center gap-4 p-4"
>
<UserAvatar {user} size="md" />
<div class="text-start grow">
<p class="text-immich-fg dark:text-immich-dark-fg">
{user.name}
</p>
<p class="text-xs">
{user.email}
</p>
</div>
</button>
</div>
{/if}
{/each}
</div>
{/if}
</div>
{#if users.length > 0}
<div class="py-3">
<Button
size="small"
fullWidth
shape="round"
disabled={Object.keys(selectedUsers).length === 0}
onclick={() =>
onClose({
action: 'sharedUsers',
data: Object.values(selectedUsers).map(({ user, ...rest }) => ({ userId: user.id, ...rest })),
})}>{$t('add')}</Button
>
</div>
{/if}
<hr class="my-4" />
<Stack gap={6}>
{#if sharedLinks.length > 0}
<div class="flex justify-between items-center">
<Text>{$t('shared_links')}</Text>
<Link href={AppRoute.SHARED_LINKS} onclick={() => onClose()} class="text-sm">{$t('view_all')}</Link>
</div>
<Stack gap={4}>
{#each sharedLinks as sharedLink (sharedLink.id)}
<AlbumSharedLink {album} {sharedLink} onViewQrCode={() => handleViewQrCode(sharedLink)} />
{/each}
</Stack>
{/if}
<Button <Button
leadingIcon={mdiLink}
size="small" size="small"
shape="round"
fullWidth fullWidth
onclick={() => onClose({ action: 'sharedLink' })}>{$t('create_link')}</Button shape="round"
disabled={Object.keys(selectedUsers).length === 0}
onclick={() =>
onClose({
action: 'sharedUsers',
data: Object.values(selectedUsers).map(({ user, ...rest }) => ({ userId: user.id, ...rest })),
})}>{$t('add')}</Button
> >
</Stack> </div>
</ModalBody> {/if}
</Modal>
{/if} <hr class="my-4" />
<Stack gap={6}>
{#if sharedLinks.length > 0}
<div class="flex justify-between items-center">
<Text>{$t('shared_links')}</Text>
<Link href={AppRoute.SHARED_LINKS} onclick={() => onClose()} class="text-sm">{$t('view_all')}</Link>
</div>
<Stack gap={4}>
{#each sharedLinks as sharedLink (sharedLink.id)}
<AlbumSharedLink {album} {sharedLink} onViewQrCode={() => handleViewQrCode(sharedLink)} />
{/each}
</Stack>
{/if}
<Button
leadingIcon={mdiLink}
size="small"
shape="round"
fullWidth
onclick={() => onClose({ action: 'sharedLink' })}>{$t('create_link')}</Button
>
</Stack>
</ModalBody>
</Modal>