Compare commits

...

4 Commits

Author SHA1 Message Date
Mees Frensel
52555c2328 allow non-owners to open settings modal in readonly mode 2026-04-16 15:08:56 +02:00
Mees Frensel
65b58b57dd Merge branch 'main' into fix/album-sharing 2026-04-16 14:21:39 +02:00
Mees Frensel
150ac7154c Merge branch 'main' into fix/album-sharing 2026-03-06 10:15:44 +01:00
Mees Frensel
95c1acbf20 fix(web): shared album avatars opening modal 2026-03-05 17:34:31 +01:00
2 changed files with 61 additions and 53 deletions

View File

@@ -24,10 +24,11 @@
type Props = {
album: AlbumResponseDto;
readOnly?: boolean;
onClose: () => void;
};
let { album, onClose }: Props = $props();
let { album, readOnly = false, onClose }: Props = $props();
const handleRoleSelect = async (user: UserResponseDto, role: AlbumUserRole | 'none') => {
if (role === 'none') {
@@ -72,14 +73,14 @@
onAlbumUpdate={(newAlbum) => (album = newAlbum)}
/>
<Modal title={$t('options')} {onClose} size="small">
<Modal title={readOnly ? $t('album') : $t('options')} {onClose} size="small">
<ModalBody>
<Stack gap={6}>
<div>
<Text size="medium" fontWeight="semi-bold">{$t('settings')}</Text>
<div class="grid gap-y-3 ps-2 mt-2">
{#if album.order}
<Field label={$t('display_order')}>
<Field label={$t('display_order')} disabled={readOnly}>
<Select
value={album.order}
options={[
@@ -90,7 +91,7 @@
/>
</Field>
{/if}
<Field label={$t('comments_and_likes')} description={$t('let_others_respond')}>
<Field label={$t('comments_and_likes')} description={$t('let_others_respond')} {readOnly}>
<Switch
checked={album.isActivityEnabled}
onCheckedChange={(checked) => handleUpdateAlbum(album, { isActivityEnabled: checked })}
@@ -102,7 +103,9 @@
<div>
<HStack fullWidth class="justify-between mb-2">
<Text size="medium" fontWeight="semi-bold">{$t('people')}</Text>
<HeaderActionButton action={AddUsers} />
{#if !readOnly}
<HeaderActionButton action={AddUsers} />
{/if}
</HStack>
<div class="ps-2">
<div class="flex items-center gap-2 mb-2">
@@ -123,7 +126,7 @@
</div>
<Text size="small">{user.name}</Text>
</div>
<Field class="w-32">
<Field class="w-32" disabled={readOnly}>
<Select
value={role}
options={[
@@ -138,20 +141,22 @@
{/each}
</div>
</div>
<div class="mb-4">
<HStack class="justify-between mb-2">
<Text size="medium" fontWeight="semi-bold">{$t('shared_links')}</Text>
<HeaderActionButton action={CreateSharedLink} />
</HStack>
{#if !readOnly}
<div class="mb-4">
<HStack class="justify-between mb-2">
<Text size="medium" fontWeight="semi-bold">{$t('shared_links')}</Text>
<HeaderActionButton action={CreateSharedLink} />
</HStack>
<div class="ps-2">
<Stack gap={4}>
{#each sharedLinks as sharedLink (sharedLink.id)}
<AlbumSharedLink {album} {sharedLink} />
{/each}
</Stack>
<div class="ps-2">
<Stack gap={4}>
{#each sharedLinks as sharedLink (sharedLink.id)}
<AlbumSharedLink {album} {sharedLink} />
{/each}
</Stack>
</div>
</div>
</div>
{/if}
</Stack>
</ModalBody>
</Modal>

View File

@@ -37,7 +37,6 @@
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
import { Route } from '$lib/route';
import {
getAlbumActions,
@@ -66,6 +65,7 @@
mdiArrowLeft,
mdiCogOutline,
mdiDeleteOutline,
mdiDotsHorizontal,
mdiDotsVertical,
mdiDownload,
mdiImageOutline,
@@ -369,44 +369,47 @@
<!-- ALBUM SHARING -->
{#if album.albumUsers.length > 0 || (album.hasSharedLink && isOwned)}
<div class="my-3 flex gap-x-1">
<!-- link -->
{#if album.hasSharedLink && isOwned}
<IconButton
aria-label={$t('create_link_to_share')}
color="secondary"
size="medium"
shape="round"
icon={mdiLink}
onclick={() => modalManager.show(SharedLinkCreateModal, { albumId: album.id })}
/>
{/if}
<!-- owner & users with write access (collaborators) -->
{@const sortedAlbumUsers = [
album.owner,
...album.albumUsers.filter(({ role }) => role === AlbumUserRole.Editor).map(({ user }) => user),
]}
<!-- owner -->
<button type="button" onclick={() => modalManager.show(AlbumOptionsModal, { album })}>
<UserAvatar user={album.owner} size="md" />
<div class="my-3 flex gap-x-1">
<button
class="flex gap-x-1"
type="button"
onclick={() => modalManager.show(AlbumOptionsModal, { album, readOnly: !isOwned })}
>
{#each sortedAlbumUsers as user (user.id)}
<UserAvatar {user} size="md" />
{/each}
<!-- display ellipsis if there are readonly users too -->
{#if albumHasViewers}
<IconButton
shape="round"
aria-label={$t('view_all_users')}
color="secondary"
size="medium"
icon={mdiDotsHorizontal}
/>
{/if}
{#if album.hasSharedLink && isOwned}
<IconButton
aria-label={$t('shared_link_manage_links')}
color="secondary"
size="medium"
shape="round"
icon={mdiLink}
/>
{/if}
</button>
<!-- users with write access (collaborators) -->
{#each album.albumUsers.filter(({ role }) => role === AlbumUserRole.Editor) as { user } (user.id)}
<button type="button" onclick={() => modalManager.show(AlbumOptionsModal, { album })}>
<UserAvatar {user} size="md" />
</button>
{/each}
<!-- display ellipsis if there are readonly users too -->
{#if albumHasViewers}
<IconButton
shape="round"
aria-label={$t('view_all_users')}
color="secondary"
size="medium"
icon={mdiDotsVertical}
onclick={() => modalManager.show(AlbumOptionsModal, { album })}
/>
{#if isOwned}
<ActionButton action={Share} />
{/if}
<ActionButton action={Share} />
</div>
{/if}
<AlbumDescription