Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web): rework context menus: add icons and reorder items #8090

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 45 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 @@ -5,27 +5,39 @@
import { getAssetJobName } from '$lib/utils';
import { clickOutside } from '$lib/utils/click-outside';
import { getContextMenuPosition } from '$lib/utils/context-menu';
import { AssetJobName, AssetTypeEnum, type AssetResponseDto } from '@immich/sdk';
import { AssetJobName, AssetTypeEnum, type AssetResponseDto, type AlbumResponseDto } from '@immich/sdk';
import {
mdiAccountCircleOutline,
mdiAlertOutline,
mdiArchiveArrowDownOutline,
mdiArchiveArrowUpOutline,
mdiArrowLeft,
mdiCogRefreshOutline,
mdiContentCopy,
mdiDatabaseRefreshOutline,
mdiDeleteOutline,
mdiDotsVertical,
mdiFolderDownloadOutline,
mdiHeart,
mdiHeartOutline,
mdiImageAlbum,
mdiImageMinusOutline,
mdiImageOutline,
mdiImageRefreshOutline,
mdiInformationOutline,
mdiMagnifyMinusOutline,
mdiMagnifyPlusOutline,
mdiMotionPauseOutline,
mdiPlaySpeed,
mdiPresentationPlay,
mdiShareVariantOutline,
} from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte';

export let asset: AssetResponseDto;
export let album: AlbumResponseDto | null = null;
export let showCopyButton: boolean;
export let showZoomButton: boolean;
export let showMotionPlayButton: boolean;
Expand All @@ -42,6 +54,7 @@
| 'addToAlbum'
| 'addToSharedAlbum'
| 'asProfileImage'
| 'setAsAlbumCover'
| 'download'
| 'playSlideShow'
| 'runJob'
Expand All @@ -59,6 +72,7 @@
addToAlbum: void;
addToSharedAlbum: void;
asProfileImage: void;
setAsAlbumCover: void;
runJob: AssetJobName;
playSlideShow: void;
unstack: void;
Expand Down Expand Up @@ -173,37 +187,55 @@
{#if isShowAssetOptions}
<ContextMenu {...contextMenuPosition} direction="left">
{#if showSlideshow}
<MenuOption on:click={() => onMenuClick('playSlideShow')} text="Slideshow" />
<MenuOption icon={mdiPresentationPlay} on:click={() => onMenuClick('playSlideShow')} text="Slideshow" />
{/if}
{#if showDownloadButton}
<MenuOption on:click={() => onMenuClick('download')} text="Download" />
<MenuOption icon={mdiFolderDownloadOutline} on:click={() => onMenuClick('download')} text="Download" />
{/if}
<MenuOption on:click={() => onMenuClick('addToAlbum')} text="Add to Album" />
<MenuOption on:click={() => onMenuClick('addToSharedAlbum')} text="Add to Shared Album" />
<MenuOption icon={mdiImageAlbum} on:click={() => onMenuClick('addToAlbum')} text="Add to album" />
<MenuOption
icon={mdiShareVariantOutline}
on:click={() => onMenuClick('addToSharedAlbum')}
text="Add to shared album"
/>

{#if isOwner}
{#if hasStackChildren}
<MenuOption icon={mdiImageMinusOutline} on:click={() => onMenuClick('unstack')} text="Un-stack" />
{/if}
{#if album}
<MenuOption
text="Set as album cover"
icon={mdiImageOutline}
on:click={() => onMenuClick('setAsAlbumCover')}
/>
{/if}
{#if asset.type === AssetTypeEnum.Image}
<MenuOption
icon={mdiAccountCircleOutline}
on:click={() => onMenuClick('asProfileImage')}
text="Set as profile picture"
/>
{/if}
<MenuOption
on:click={() => dispatch('toggleArchive')}
icon={asset.isArchived ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline}
text={asset.isArchived ? 'Unarchive' : 'Archive'}
/>
{#if asset.type === AssetTypeEnum.Image}
<MenuOption on:click={() => onMenuClick('asProfileImage')} text="As profile picture" />
{/if}

{#if hasStackChildren}
<MenuOption on:click={() => onMenuClick('unstack')} text="Un-Stack" />
{/if}

<hr />
<MenuOption
icon={mdiDatabaseRefreshOutline}
on:click={() => onJobClick(AssetJobName.RefreshMetadata)}
text={getAssetJobName(AssetJobName.RefreshMetadata)}
/>
<MenuOption
icon={mdiImageRefreshOutline}
on:click={() => onJobClick(AssetJobName.RegenerateThumbnail)}
text={getAssetJobName(AssetJobName.RegenerateThumbnail)}
/>
{#if asset.type === AssetTypeEnum.Video}
<MenuOption
icon={mdiCogRefreshOutline}
on:click={() => onJobClick(AssetJobName.TranscodeVideo)}
text={getAssetJobName(AssetJobName.TranscodeVideo)}
/>
Expand Down
24 changes: 19 additions & 5 deletions web/src/lib/components/faces-page/people-card.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
import { getPeopleThumbnailUrl } from '$lib/utils';
import { getContextMenuPosition } from '$lib/utils/context-menu';
import { type PersonResponseDto } from '@immich/sdk';
import { mdiDotsVertical } from '@mdi/js';
import {
mdiAccountEditOutline,
mdiAccountMultipleCheckOutline,
mdiCalendarEditOutline,
mdiDotsVertical,
mdiEyeOffOutline,
} from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import IconButton from '../elements/buttons/icon-button.svelte';
Expand Down Expand Up @@ -83,10 +89,18 @@
{#if showContextMenu}
<Portal target="body">
<ContextMenu {...contextMenuPosition} on:outclick={() => onMenuExit()}>
<MenuOption on:click={() => onMenuClick('hide-person')} text="Hide Person" />
<MenuOption on:click={() => onMenuClick('change-name')} text="Change name" />
<MenuOption on:click={() => onMenuClick('set-birth-date')} text="Set date of birth" />
<MenuOption on:click={() => onMenuClick('merge-people')} text="Merge People" />
<MenuOption on:click={() => onMenuClick('hide-person')} icon={mdiEyeOffOutline} text="Hide person" />
<MenuOption on:click={() => onMenuClick('change-name')} icon={mdiAccountEditOutline} text="Change name" />
<MenuOption
on:click={() => onMenuClick('set-birth-date')}
icon={mdiCalendarEditOutline}
text="Set date of birth"
/>
<MenuOption
on:click={() => onMenuClick('merge-people')}
icon={mdiAccountMultipleCheckOutline}
text="Merge people"
/>
</ContextMenu>
</Portal>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import { createAlbum, type AlbumResponseDto } from '@immich/sdk';
import { getMenuContext } from '../asset-select-context-menu.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js';

export let shared = false;
let showAlbumPicker = false;
Expand Down Expand Up @@ -53,7 +54,11 @@
};
</script>

<MenuOption on:click={() => (showAlbumPicker = true)} text={shared ? 'Add to Shared Album' : 'Add to Album'} />
<MenuOption
on:click={() => (showAlbumPicker = true)}
text={shared ? 'Add to shared album' : 'Add to album'}
icon={shared ? mdiShareVariantOutline : mdiImageAlbum}
/>

{#if showAlbumPicker}
<AlbumSelectionModal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
</script>

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

{#if !menuItem}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { getAssetJobMessage, getAssetJobName } from '$lib/utils';
import { getAssetJobIcon, getAssetJobMessage, getAssetJobName } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { AssetJobName, AssetTypeEnum, runAssetJobs } from '@immich/sdk';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
Expand Down Expand Up @@ -33,6 +33,6 @@

{#each jobs as job}
{#if isAllVideos || job !== AssetJobName.TranscodeVideo}
<MenuOption text={getAssetJobName(job)} on:click={() => handleRunJob(job)} />
<MenuOption text={getAssetJobName(job)} icon={getAssetJobIcon(job)} on:click={() => handleRunJob(job)} />
{/if}
{/each}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { DateTime } from 'luxon';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiCalendarEditOutline } from '@mdi/js';
export let menuItem = false;
const { clearSelect, getOwnedAssets } = getAssetControlContext();

Expand All @@ -26,7 +27,7 @@
</script>

{#if menuItem}
<MenuOption text="Change date" on:click={() => (isShowChangeDate = true)} />
<MenuOption text="Change date" icon={mdiCalendarEditOutline} on:click={() => (isShowChangeDate = true)} />
{/if}
{#if isShowChangeDate}
<ChangeDate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { updateAssets } from '@immich/sdk';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiMapMarkerMultipleOutline } from '@mdi/js';

export let menuItem = false;
const { clearSelect, getOwnedAssets } = getAssetControlContext();
Expand All @@ -26,7 +27,11 @@
</script>

{#if menuItem}
<MenuOption text="Change location" on:click={() => (isShowChangeLocation = true)} />
<MenuOption
text="Change location"
icon={mdiMapMarkerMultipleOutline}
on:click={() => (isShowChangeLocation = true)}
/>
{/if}
{#if isShowChangeLocation}
<ChangeLocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
let isShowConfirmation = false;
let loading = false;

$: label = force ? 'Permanently delete' : 'Delete';

const handleTrash = async () => {
if (force) {
isShowConfirmation = true;
Expand All @@ -46,11 +48,11 @@
</script>

{#if menuItem}
<MenuOption text={force ? 'Permanently Delete' : 'Delete'} on:click={handleTrash} />
<MenuOption text={label} icon={mdiDeleteOutline} on:click={handleTrash} />
{:else if loading}
<CircleIconButton title="Loading" icon={mdiTimerSand} />
{:else}
<CircleIconButton title="Delete" icon={mdiDeleteOutline} on:click={handleTrash} />
<CircleIconButton title={label} icon={mdiDeleteOutline} on:click={handleTrash} />
{/if}

{#if isShowConfirmation}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { downloadArchive, downloadFile } from '$lib/utils/asset-utils';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiCloudDownloadOutline } from '@mdi/js';
import { mdiCloudDownloadOutline, mdiFileDownloadOutline, mdiFolderDownloadOutline } from '@mdi/js';

export let filename = 'immich.zip';
export let menuItem = false;
Expand All @@ -21,10 +21,12 @@
clearSelect();
await downloadArchive(filename, { assetIds: assets.map((asset) => asset.id) });
};

$: menuItemIcon = getAssets().size === 1 ? mdiFileDownloadOutline : mdiFolderDownloadOutline;
</script>

{#if menuItem}
<MenuOption text="Download" on:click={handleDownloadFiles} />
<MenuOption text="Download" icon={menuItemIcon} on:click={handleDownloadFiles} />
{:else}
<CircleIconButton title="Download" icon={mdiCloudDownloadOutline} on:click={handleDownloadFiles} />
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
export let menuItem = false;
export let removeFavorite: boolean;

$: text = removeFavorite ? 'Remove from Favorites' : 'Favorite';
$: text = removeFavorite ? 'Remove from favorites' : 'Favorite';
$: icon = removeFavorite ? mdiHeartMinusOutline : mdiHeartOutline;

let loading = false;
Expand Down Expand Up @@ -57,7 +57,7 @@
</script>

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

{#if !menuItem}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { getAlbumInfo, removeAssetFromAlbum, type AlbumResponseDto } from '@immich/sdk';
import { mdiDeleteOutline } from '@mdi/js';
import { mdiDeleteOutline, mdiImageRemoveOutline } from '@mdi/js';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';

Expand Down Expand Up @@ -50,7 +50,7 @@
</script>

{#if menuItem}
<MenuOption text="Remove from album" on:click={() => (isShowConfirmation = true)} />
<MenuOption text="Remove from album" icon={mdiImageRemoveOutline} on:click={() => (isShowConfirmation = true)} />
{:else}
<CircleIconButton title="Remove from album" icon={mdiDeleteOutline} on:click={() => (isShowConfirmation = true)} />
{/if}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { handleError } from '$lib/utils/handle-error';
import { updateAssets } from '@immich/sdk';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiImageMultipleOutline } from '@mdi/js';

export let onStack: OnStack | undefined;

Expand Down Expand Up @@ -55,4 +56,4 @@
};
</script>

<MenuOption text="Stack" on:click={handleStack} />
<MenuOption text="Stack" icon={mdiImageMultipleOutline} on:click={handleStack} />
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@
<CircleIconButton {title} {icon} on:click={handleShowMenu} />
{#if showContextMenu}
<ContextMenu {...contextMenuPosition}>
<div class="flex flex-col rounded-lg">
<slot />
</div>
<slot />
</ContextMenu>
{/if}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
<div
transition:slide={{ duration: 200, easing: quintOut }}
bind:this={menuElement}
class="absolute z-10 w-[200px] overflow-hidden rounded-lg shadow-lg"
class="absolute z-10 min-w-[200px] w-max max-w-[300px] overflow-hidden rounded-lg shadow-lg"
style="left: {left}px; top: {top}px;"
role="menu"
use:clickOutside
on:outclick
on:escape
>
<slot />
<div class="flex flex-col rounded-lg">
<slot />
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<script>
import Icon from '$lib/components/elements/icon.svelte';

export let text = '';
export let subtitle = '';
export let icon = '';
</script>

<button
Expand All @@ -9,7 +12,14 @@
role="menuitem"
>
{#if text}
{text}
{#if icon}
<p class="flex gap-2">
<Icon path={icon} size="18" />
{text}
</p>
{:else}
{text}
{/if}
martabal marked this conversation as resolved.
Show resolved Hide resolved
{:else}
<slot />
{/if}
Expand Down