[go: nahoru, domu]

Skip to content

Commit

Permalink
chore(web): context menu improvements (immich-app#10475)
Browse files Browse the repository at this point in the history
- ability to add custom hover colors
- migrate activity menu to ButtonContextMenu component
- onClick callbacks rather than events for menu options
- remove slots
- configurable menu option colors
- improve menu option layout
  • Loading branch information
ben-basten committed Jun 20, 2024
1 parent 5cde52e commit 0fda675
Show file tree
Hide file tree
Showing 19 changed files with 101 additions and 124 deletions.
8 changes: 4 additions & 4 deletions web/src/lib/components/album-page/albums-list.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -424,13 +424,13 @@
<MenuOption
icon={mdiRenameOutline}
text={$t('edit_album')}
on:click={() => contextMenuTargetAlbum && handleEdit(contextMenuTargetAlbum)}
onClick={() => contextMenuTargetAlbum && handleEdit(contextMenuTargetAlbum)}
/>
<MenuOption icon={mdiShareVariantOutline} text={$t('share')} on:click={() => openShareModal()} />
<MenuOption icon={mdiShareVariantOutline} text={$t('share')} onClick={() => openShareModal()} />
{/if}
<MenuOption icon={mdiFolderDownloadOutline} text={$t('download')} on:click={() => handleDownloadAlbum()} />
<MenuOption icon={mdiFolderDownloadOutline} text={$t('download')} onClick={() => handleDownloadAlbum()} />
{#if showFullContextMenu}
<MenuOption icon={mdiDeleteOutline} text={$t('delete')} on:click={() => setAlbumToDelete()} />
<MenuOption icon={mdiDeleteOutline} text={$t('delete')} onClick={() => setAlbumToDelete()} />
{/if}
</RightClickContextMenu>

Expand Down
6 changes: 3 additions & 3 deletions web/src/lib/components/album-page/share-info-modal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,14 @@
{#if isOwned}
<ButtonContextMenu icon={mdiDotsVertical} size="20" title={$t('options')}>
{#if role === AlbumUserRole.Viewer}
<MenuOption on:click={() => handleSetReadonly(user, AlbumUserRole.Editor)} text={$t('allow_edits')} />
<MenuOption onClick={() => handleSetReadonly(user, AlbumUserRole.Editor)} text={$t('allow_edits')} />
{:else}
<MenuOption
on:click={() => handleSetReadonly(user, AlbumUserRole.Viewer)}
onClick={() => handleSetReadonly(user, AlbumUserRole.Viewer)}
text={$t('disallow_edits')}
/>
{/if}
<MenuOption on:click={() => handleMenuRemove(user)} text={$t('remove')} />
<MenuOption onClick={() => handleMenuRemove(user)} text={$t('remove')} />
</ButtonContextMenu>
{:else if user.id == currentUser?.id}
<button
Expand Down
67 changes: 27 additions & 40 deletions web/src/lib/components/asset-viewer/activity-viewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import { getAssetThumbnailUrl, handlePromiseError } from '$lib/utils';
import { getAssetType } from '$lib/utils/asset-utils';
import { autoGrowHeight } from '$lib/actions/autogrow';
import { clickOutside } from '$lib/actions/click-outside';
import { handleError } from '$lib/utils/handle-error';
import { isTenMinutesApart } from '$lib/utils/timesince';
import {
Expand All @@ -16,7 +15,7 @@
type AssetTypeEnum,
type UserResponseDto,
} from '@immich/sdk';
import { mdiClose, mdiDotsVertical, mdiHeart, mdiSend } from '@mdi/js';
import { mdiClose, mdiDotsVertical, mdiHeart, mdiSend, mdiDeleteOutline } from '@mdi/js';
import * as luxon from 'luxon';
import { createEventDispatcher, onMount } from 'svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
Expand All @@ -26,6 +25,8 @@
import { locale } from '$lib/stores/preferences.store';
import { shortcut } from '$lib/actions/shortcut';
import { t } from 'svelte-i18n';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
const units: Intl.RelativeTimeFormatUnit[] = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second'];
Expand Down Expand Up @@ -71,7 +72,6 @@
close: void;
}>();
$: showDeleteReaction = Array.from({ length: reactions.length }).fill(false);
$: {
if (innerHeight && activityHeight) {
divHeight = innerHeight - activityHeight;
Expand Down Expand Up @@ -109,7 +109,6 @@
try {
await deleteActivity({ id: reaction.id });
reactions.splice(index, 1);
showDeleteReaction.splice(index, 1);
reactions = reactions;
if (isLiked && reaction.type === 'like' && reaction.id == isLiked.id) {
dispatch('deleteLike');
Expand Down Expand Up @@ -147,10 +146,6 @@
}
isSendingMessage = false;
};
const showOptionsMenu = (index: number) => {
showDeleteReaction[index] = !showDeleteReaction[index];
};
</script>

<div class="overflow-y-hidden relative h-full" bind:offsetHeight={innerHeight}>
Expand Down Expand Up @@ -188,27 +183,23 @@
</a>
{/if}
{#if reaction.user.id === user.id || albumOwnerId === user.id}
<div class="flex items-start w-fit pt-[5px]">
<CircleIconButton
<div class="mr-4">
<ButtonContextMenu
icon={mdiDotsVertical}
title={$t('comment_options')}
align="top-right"
direction="left"
size="16"
on:click={() => (showDeleteReaction[index] ? '' : showOptionsMenu(index))}
/>
>
<MenuOption
activeColor="bg-red-200"
icon={mdiDeleteOutline}
text={$t('remove')}
onClick={() => handleDeleteReaction(reaction, index)}
/>
</ButtonContextMenu>
</div>
{/if}
<div>
{#if showDeleteReaction[index]}
<button
type="button"
class="absolute right-6 rounded-xl items-center bg-gray-300 dark:bg-slate-100 py-3 px-6 text-left text-sm font-medium text-immich-fg hover:bg-red-300 focus:outline-none focus:ring-2 focus:ring-inset dark:text-immich-dark-bg dark:hover:bg-red-100 transition-colors"
use:clickOutside={{ onOutclick: () => (showDeleteReaction[index] = false) }}
on:click={() => handleDeleteReaction(reaction, index)}
>
Remove
</button>
{/if}
</div>
</div>

{#if (index != reactions.length - 1 && !shouldGroup(reactions[index].createdAt, reactions[index + 1].createdAt)) || index === reactions.length - 1}
Expand Down Expand Up @@ -240,27 +231,23 @@
</a>
{/if}
{#if reaction.user.id === user.id || albumOwnerId === user.id}
<div class="flex items-start w-fit">
<CircleIconButton
<div class="mr-4">
<ButtonContextMenu
icon={mdiDotsVertical}
title={$t('reaction_options')}
align="top-right"
direction="left"
size="16"
on:click={() => (showDeleteReaction[index] ? '' : showOptionsMenu(index))}
/>
>
<MenuOption
activeColor="bg-red-200"
icon={mdiDeleteOutline}
text={$t('remove')}
onClick={() => handleDeleteReaction(reaction, index)}
/>
</ButtonContextMenu>
</div>
{/if}
<div>
{#if showDeleteReaction[index]}
<button
type="button"
class="absolute right-6 rounded-xl items-center bg-gray-300 dark:bg-slate-100 py-3 px-6 text-left text-sm font-medium text-immich-fg hover:bg-red-300 focus:outline-none focus:ring-2 focus:ring-inset dark:text-immich-dark-bg dark:hover:bg-red-100 transition-colors"
use:clickOutside={{ onOutclick: () => (showDeleteReaction[index] = false) }}
on:click={() => handleDeleteReaction(reaction, index)}
>
Remove
</button>
{/if}
</div>
</div>
{#if (index != reactions.length - 1 && isTenMinutesApart(reactions[index].createdAt, reactions[index + 1].createdAt)) || index === reactions.length - 1}
<div
Expand Down
26 changes: 13 additions & 13 deletions web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -177,65 +177,65 @@
/>
<ButtonContextMenu direction="left" align="top-right" color="opaque" title={$t('more')} icon={mdiDotsVertical}>
{#if showSlideshow}
<MenuOption icon={mdiPresentationPlay} on:click={() => onMenuClick('playSlideShow')} text={$t('slideshow')} />
<MenuOption icon={mdiPresentationPlay} onClick={() => onMenuClick('playSlideShow')} text={$t('slideshow')} />
{/if}
{#if showDownloadButton}
<MenuOption icon={mdiFolderDownloadOutline} on:click={() => onMenuClick('download')} text={$t('download')} />
<MenuOption icon={mdiFolderDownloadOutline} onClick={() => onMenuClick('download')} text={$t('download')} />
{/if}
{#if asset.isTrashed}
<MenuOption icon={mdiHistory} on:click={() => onMenuClick('restoreAsset')} text={$t('restore')} />
<MenuOption icon={mdiHistory} onClick={() => onMenuClick('restoreAsset')} text={$t('restore')} />
{:else}
<MenuOption icon={mdiImageAlbum} on:click={() => onMenuClick('addToAlbum')} text={$t('add_to_album')} />
<MenuOption icon={mdiImageAlbum} onClick={() => onMenuClick('addToAlbum')} text={$t('add_to_album')} />
<MenuOption
icon={mdiShareVariantOutline}
on:click={() => onMenuClick('addToSharedAlbum')}
onClick={() => onMenuClick('addToSharedAlbum')}
text={$t('add_to_shared_album')}
/>
{/if}

{#if isOwner}
{#if hasStackChildren}
<MenuOption icon={mdiImageMinusOutline} on:click={() => onMenuClick('unstack')} text={$t('unstack')} />
<MenuOption icon={mdiImageMinusOutline} onClick={() => onMenuClick('unstack')} text={$t('unstack')} />
{/if}
{#if album}
<MenuOption
text={$t('set_as_album_cover')}
icon={mdiImageOutline}
on:click={() => onMenuClick('setAsAlbumCover')}
onClick={() => onMenuClick('setAsAlbumCover')}
/>
{/if}
{#if asset.type === AssetTypeEnum.Image}
<MenuOption
icon={mdiAccountCircleOutline}
on:click={() => onMenuClick('asProfileImage')}
onClick={() => onMenuClick('asProfileImage')}
text={$t('set_as_profile_picture')}
/>
{/if}
<MenuOption
on:click={() => onMenuClick('toggleArchive')}
onClick={() => onMenuClick('toggleArchive')}
icon={asset.isArchived ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline}
text={asset.isArchived ? $t('unarchive') : $t('to_archive')}
/>
<MenuOption
icon={mdiUpload}
on:click={() => openFileUploadDialog({ multiple: false, assetId: asset.id })}
onClick={() => openFileUploadDialog({ multiple: false, assetId: asset.id })}
text={$t('replace_with_upload')}
/>
<hr />
<MenuOption
icon={mdiDatabaseRefreshOutline}
on:click={() => onJobClick(AssetJobName.RefreshMetadata)}
onClick={() => onJobClick(AssetJobName.RefreshMetadata)}
text={getAssetJobName(AssetJobName.RefreshMetadata)}
/>
<MenuOption
icon={mdiImageRefreshOutline}
on:click={() => onJobClick(AssetJobName.RegenerateThumbnail)}
onClick={() => onJobClick(AssetJobName.RegenerateThumbnail)}
text={getAssetJobName(AssetJobName.RegenerateThumbnail)}
/>
{#if asset.type === AssetTypeEnum.Video}
<MenuOption
icon={mdiCogRefreshOutline}
on:click={() => onJobClick(AssetJobName.TranscodeVideo)}
onClick={() => onJobClick(AssetJobName.TranscodeVideo)}
text={getAssetJobName(AssetJobName.TranscodeVideo)}
/>
{/if}
Expand Down
8 changes: 4 additions & 4 deletions web/src/lib/components/faces-page/people-card.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@
icon={mdiDotsVertical}
title={$t('show_person_options')}
>
<MenuOption on:click={() => onMenuClick('hide-person')} icon={mdiEyeOffOutline} text={$t('hide_person')} />
<MenuOption on:click={() => onMenuClick('change-name')} icon={mdiAccountEditOutline} text={$t('change_name')} />
<MenuOption onClick={() => onMenuClick('hide-person')} icon={mdiEyeOffOutline} text={$t('hide_person')} />
<MenuOption onClick={() => onMenuClick('change-name')} icon={mdiAccountEditOutline} text={$t('change_name')} />
<MenuOption
on:click={() => onMenuClick('set-birth-date')}
onClick={() => onMenuClick('set-birth-date')}
icon={mdiCalendarEditOutline}
text={$t('set_date_of_birth')}
/>
<MenuOption
on:click={() => onMenuClick('merge-people')}
onClick={() => onMenuClick('merge-people')}
icon={mdiAccountMultipleCheckOutline}
text={$t('merge_people')}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</script>

<MenuOption
on:click={() => (showAlbumPicker = true)}
onClick={() => (showAlbumPicker = true)}
text={shared ? $t('add_to_shared_album') : $t('add_to_album')}
icon={shared ? mdiShareVariantOutline : mdiImageAlbum}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</script>

{#if menuItem}
<MenuOption {text} {icon} on:click={handleArchive} />
<MenuOption {text} {icon} onClick={handleArchive} />
{/if}

{#if !menuItem}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@

{#each jobs as job}
{#if isAllVideos || job !== AssetJobName.TranscodeVideo}
<MenuOption text={getAssetJobName(job)} icon={getAssetJobIcon(job)} on:click={() => handleRunJob(job)} />
<MenuOption text={getAssetJobName(job)} icon={getAssetJobIcon(job)} onClick={() => handleRunJob(job)} />
{/if}
{/each}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</script>

{#if menuItem}
<MenuOption text={$t('change_date')} icon={mdiCalendarEditOutline} on:click={() => (isShowChangeDate = true)} />
<MenuOption text={$t('change_date')} icon={mdiCalendarEditOutline} onClick={() => (isShowChangeDate = true)} />
{/if}
{#if isShowChangeDate}
<ChangeDate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<MenuOption
text={$t('change_location')}
icon={mdiMapMarkerMultipleOutline}
on:click={() => (isShowChangeLocation = true)}
onClick={() => (isShowChangeLocation = true)}
/>
{/if}
{#if isShowChangeLocation}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</script>

{#if menuItem}
<MenuOption text={label} icon={mdiDeleteOutline} on:click={handleTrash} />
<MenuOption text={label} icon={mdiDeleteOutline} onClick={handleTrash} />
{:else if loading}
<CircleIconButton title={$t('loading')} icon={mdiTimerSand} />
{:else}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</script>

{#if menuItem}
<MenuOption text={$t('download')} icon={menuItemIcon} on:click={handleDownloadFiles} />
<MenuOption text={$t('download')} icon={menuItemIcon} onClick={handleDownloadFiles} />
{:else}
<CircleIconButton title={$t('download')} icon={mdiCloudDownloadOutline} on:click={handleDownloadFiles} />
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
</script>

{#if menuItem}
<MenuOption {text} {icon} on:click={handleFavorite} />
<MenuOption {text} {icon} onClick={handleFavorite} />
{/if}

{#if !menuItem}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
</script>

{#if menuItem}
<MenuOption text={$t('remove_from_album')} icon={mdiImageRemoveOutline} on:click={removeFromAlbum} />
<MenuOption text={$t('remove_from_album')} icon={mdiImageRemoveOutline} onClick={removeFromAlbum} />
{:else}
<CircleIconButton title={$t('remove_from_album')} icon={mdiDeleteOutline} on:click={removeFromAlbum} />
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</script>

{#if unstack}
<MenuOption text={$t('unstack')} icon={mdiImageMinusOutline} on:click={handleUnstack} />
<MenuOption text={$t('unstack')} icon={mdiImageMinusOutline} onClick={handleUnstack} />
{:else}
<MenuOption text={$t('stack')} icon={mdiImageMultipleOutline} on:click={handleStack} />
<MenuOption text={$t('stack')} icon={mdiImageMultipleOutline} onClick={handleStack} />
{/if}
Loading

0 comments on commit 0fda675

Please sign in to comment.