1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

feat(web): better context menu position (#4271)

* feat(web): better context menu position

* fix: album context menu

* fix: add middle variant

* fix: rest of context menus

* fix: linting error
This commit is contained in:
Jason Rasmussen 2023-09-29 13:41:58 -04:00 committed by GitHub
parent 3e73cfb71a
commit 68d6d89a3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 40 additions and 29 deletions

View File

@ -6,6 +6,7 @@
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import IconButton from '../elements/buttons/icon-button.svelte'; import IconButton from '../elements/buttons/icon-button.svelte';
import type { OnClick, OnShowContextMenu } from './album-card'; import type { OnClick, OnShowContextMenu } from './album-card';
import { getContextMenuPosition } from '../../utils/context-menu';
export let album: AlbumResponseDto; export let album: AlbumResponseDto;
export let isSharingView = false; export let isSharingView = false;
@ -41,12 +42,8 @@
} }
}; };
const showAlbumContextMenu = (e: MouseEvent) => { const showAlbumContextMenu = (e: MouseEvent) =>
dispatchShowContextMenu('showalbumcontextmenu', { dispatchShowContextMenu('showalbumcontextmenu', getContextMenuPosition(e));
x: e.clientX,
y: e.clientY,
});
};
onMount(async () => { onMount(async () => {
imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || noThumbnailUrl; imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || noThumbnailUrl;

View File

@ -10,6 +10,7 @@
import { notificationController, NotificationType } from '../shared-components/notification/notification'; import { notificationController, NotificationType } from '../shared-components/notification/notification';
import { handleError } from '../../utils/handle-error'; import { handleError } from '../../utils/handle-error';
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte'; import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
import { getContextMenuPosition } from '../../utils/context-menu';
export let album: AlbumResponseDto; export let album: AlbumResponseDto;
@ -34,16 +35,8 @@
} }
}); });
const showContextMenu = (user: UserResponseDto) => { const showContextMenu = (event: MouseEvent, user: UserResponseDto) => {
const iconButton = document.getElementById('icon-' + user.id); position = getContextMenuPosition(event);
if (iconButton) {
position = {
x: iconButton.getBoundingClientRect().left,
y: iconButton.getBoundingClientRect().bottom,
};
}
selectedMenuUser = user; selectedMenuUser = user;
selectedRemoveUser = null; selectedRemoveUser = null;
}; };
@ -105,7 +98,7 @@
{#if isOwned} {#if isOwned}
<div> <div>
<CircleIconButton <CircleIconButton
on:click={() => showContextMenu(user)} on:click={(event) => showContextMenu(event, user)}
logo={DotsVertical} logo={DotsVertical}
backgroundColor="transparent" backgroundColor="transparent"
hoverColor="#e2e7e9" hoverColor="#e2e7e9"

View File

@ -20,6 +20,7 @@
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte'; import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte'; import MenuOption from '../shared-components/context-menu/menu-option.svelte';
import { getContextMenuPosition } from '$lib/utils/context-menu';
export let asset: AssetResponseDto; export let asset: AssetResponseDto;
export let showCopyButton: boolean; export let showCopyButton: boolean;
@ -52,8 +53,8 @@
let contextMenuPosition = { x: 0, y: 0 }; let contextMenuPosition = { x: 0, y: 0 };
let isShowAssetOptions = false; let isShowAssetOptions = false;
const showOptionsMenu = ({ x, y }: MouseEvent) => { const showOptionsMenu = (event: MouseEvent) => {
contextMenuPosition = { x, y }; contextMenuPosition = getContextMenuPosition(event, 'top-right');
isShowAssetOptions = !isShowAssetOptions; isShowAssetOptions = !isShowAssetOptions;
}; };

View File

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { PersonResponseDto, api } from '@api'; import { PersonResponseDto, api } from '@api';
import { getContextMenuPosition } from '$lib/utils/context-menu';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte'; import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import IconButton from '../elements/buttons/icon-button.svelte'; import IconButton from '../elements/buttons/icon-button.svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
@ -21,8 +22,8 @@
let showVerticalDots = false; let showVerticalDots = false;
let showContextMenu = false; let showContextMenu = false;
let contextMenuPosition = { x: 0, y: 0 }; let contextMenuPosition = { x: 0, y: 0 };
const showMenu = ({ x, y }: MouseEvent) => { const showMenu = (event: MouseEvent) => {
contextMenuPosition = { x, y }; contextMenuPosition = getContextMenuPosition(event);
showContextMenu = !showContextMenu; showContextMenu = !showContextMenu;
}; };
const onMenuExit = () => { const onMenuExit = () => {

View File

@ -10,6 +10,7 @@
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte'; import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
import type Icon from 'svelte-material-icons/AbTesting.svelte'; import type Icon from 'svelte-material-icons/AbTesting.svelte';
import { getContextMenuPosition } from '$lib/utils/context-menu';
export let icon: typeof Icon; export let icon: typeof Icon;
export let title: string; export let title: string;
@ -17,9 +18,8 @@
let showContextMenu = false; let showContextMenu = false;
let contextMenuPosition = { x: 0, y: 0 }; let contextMenuPosition = { x: 0, y: 0 };
const handleShowMenu = ({ x }: MouseEvent) => { const handleShowMenu = (event: MouseEvent) => {
const navigationBarHeight = 75; contextMenuPosition = getContextMenuPosition(event, 'top-left');
contextMenuPosition = { x: x, y: navigationBarHeight };
showContextMenu = !showContextMenu; showContextMenu = !showContextMenu;
}; };

View File

@ -18,6 +18,7 @@
import Portal from '../shared-components/portal/portal.svelte'; import Portal from '../shared-components/portal/portal.svelte';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte'; import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte'; import MenuOption from '../shared-components/context-menu/menu-option.svelte';
import { getContextMenuPosition } from '$lib/utils/context-menu';
let libraries: LibraryResponseDto[] = []; let libraries: LibraryResponseDto[] = [];
@ -60,8 +61,8 @@
} }
}; };
const showMenu = ({ x, y }: MouseEvent, type: LibraryType) => { const showMenu = (event: MouseEvent, type: LibraryType) => {
contextMenuPosition = { x, y }; contextMenuPosition = getContextMenuPosition(event);
showContextMenu = !showContextMenu; showContextMenu = !showContextMenu;
libraryType = type; libraryType = type;
}; };

View File

@ -0,0 +1,18 @@
export type Align = 'middle' | 'top-left' | 'top-right';
export const getContextMenuPosition = (event: MouseEvent, align: Align = 'middle') => {
const { x, y, currentTarget, target } = event;
const box = ((currentTarget || target) as HTMLElement)?.getBoundingClientRect();
if (box) {
switch (align) {
case 'middle':
return { x: box.x + box.width / 2, y: box.y + box.height / 2 };
case 'top-left':
return { x: box.x, y: box.y };
case 'top-right':
return { x: box.x + box.width, y: box.y };
}
}
return { x, y };
};

View File

@ -45,6 +45,7 @@
import ShareVariantOutline from 'svelte-material-icons/ShareVariantOutline.svelte'; import ShareVariantOutline from 'svelte-material-icons/ShareVariantOutline.svelte';
import type { PageData } from './$types'; import type { PageData } from './$types';
import { clickOutside } from '$lib/utils/click-outside'; import { clickOutside } from '$lib/utils/click-outside';
import { getContextMenuPosition } from '$lib/utils/context-menu';
export let data: PageData; export let data: PageData;
@ -193,9 +194,8 @@
timelineInteractionStore.clearMultiselect(); timelineInteractionStore.clearMultiselect();
}; };
const handleOpenAlbumOptions = ({ x }: MouseEvent) => { const handleOpenAlbumOptions = (event: MouseEvent) => {
const navigationBarHeight = 75; contextMenuPosition = getContextMenuPosition(event, 'top-left');
contextMenuPosition = { x: x, y: navigationBarHeight };
viewMode = viewMode === ViewMode.VIEW ? ViewMode.ALBUM_OPTIONS : ViewMode.VIEW; viewMode = viewMode === ViewMode.VIEW ? ViewMode.ALBUM_OPTIONS : ViewMode.VIEW;
}; };