mirror of
https://github.com/immich-app/immich.git
synced 2025-06-03 05:34:32 -04:00
first pass at replacing all CircleIconButtons
This commit is contained in:
parent
0b18f5c12a
commit
1f6ad41d3f
@ -2,44 +2,23 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { mdiCast, mdiCastConnected } from '@mdi/js';
|
import { mdiCast, mdiCastConnected } from '@mdi/js';
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
|
||||||
import { CastDestinationType, castManager } from '$lib/managers/cast-manager.svelte';
|
import { CastDestinationType, castManager } from '$lib/managers/cast-manager.svelte';
|
||||||
import { GCastDestination } from '$lib/utils/cast/gcast-destination.svelte';
|
import { GCastDestination } from '$lib/utils/cast/gcast-destination.svelte';
|
||||||
import { IconButton } from '@immich/ui';
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
|
||||||
whiteHover?: boolean;
|
|
||||||
navBar?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { whiteHover, navBar }: Props = $props();
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await castManager.initialize();
|
await castManager.initialize();
|
||||||
});
|
});
|
||||||
|
|
||||||
const getButtonColor = () => {
|
|
||||||
return castManager.isCasting ? 'primary' : whiteHover ? undefined : 'opaque';
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if castManager.availableDestinations.length > 0 && castManager.availableDestinations[0].type === CastDestinationType.GCAST}
|
{#if castManager.availableDestinations.length > 0 && castManager.availableDestinations[0].type === CastDestinationType.GCAST}
|
||||||
{#if navBar}
|
<IconButton
|
||||||
<IconButton
|
shape="round"
|
||||||
shape="round"
|
variant="ghost"
|
||||||
variant="ghost"
|
size="medium"
|
||||||
size="medium"
|
color={castManager.isCasting ? 'primary' : 'secondary'}
|
||||||
color={castManager.isCasting ? 'primary' : 'secondary'}
|
icon={castManager.isCasting ? mdiCastConnected : mdiCast}
|
||||||
icon={castManager.isCasting ? mdiCastConnected : mdiCast}
|
onclick={() => void GCastDestination.showCastDialog()}
|
||||||
onclick={() => void GCastDestination.showCastDialog()}
|
aria-label={$t('cast')}
|
||||||
aria-label={$t('cast')}
|
/>
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<CircleIconButton
|
|
||||||
color={getButtonColor()}
|
|
||||||
icon={castManager.isCasting ? mdiCastConnected : mdiCast}
|
|
||||||
onclick={GCastDestination.showCastDialog}
|
|
||||||
title={$t('cast')}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import JobTileButton from './job-tile-button.svelte';
|
import JobTileButton from './job-tile-button.svelte';
|
||||||
import JobTileStatus from './job-tile-status.svelte';
|
import JobTileStatus from './job-tile-status.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
@ -75,12 +76,12 @@
|
|||||||
<span class="text-sm">
|
<span class="text-sm">
|
||||||
{$t('admin.jobs_failed', { values: { jobCount: jobCounts.failed.toLocaleString($locale) } })}
|
{$t('admin.jobs_failed', { values: { jobCount: jobCounts.failed.toLocaleString($locale) } })}
|
||||||
</span>
|
</span>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiClose}
|
icon={mdiClose}
|
||||||
title={$t('clear_message')}
|
aria-label={$t('clear_message')}
|
||||||
size="12"
|
size="tiny"
|
||||||
padding="1"
|
shape="round"
|
||||||
onclick={() => onCommand({ command: JobCommand.ClearFailed, force: false })}
|
onclick={() => onCommand({ command: JobCommand.ClearFailed, force: false })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
import { SettingInputFieldType } from '$lib/constants';
|
import { SettingInputFieldType } from '$lib/constants';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
import type { SystemConfigDto } from '@immich/sdk';
|
import type { SystemConfigDto } from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiMinusCircle } from '@mdi/js';
|
import { mdiMinusCircle } from '@mdi/js';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -48,12 +48,11 @@
|
|||||||
{#each config.machineLearning.urls as _, i (i)}
|
{#each config.machineLearning.urls as _, i (i)}
|
||||||
{#snippet removeButton()}
|
{#snippet removeButton()}
|
||||||
{#if config.machineLearning.urls.length > 1}
|
{#if config.machineLearning.urls.length > 1}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
size="24"
|
size="large"
|
||||||
class="ms-2"
|
shape="round"
|
||||||
padding="2"
|
color="danger"
|
||||||
color="red"
|
aria-label=""
|
||||||
title=""
|
|
||||||
onclick={() => config.machineLearning.urls.splice(i, 1)}
|
onclick={() => config.machineLearning.urls.splice(i, 1)}
|
||||||
icon={mdiMinusCircle}
|
icon={mdiMinusCircle}
|
||||||
/>
|
/>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import { getContextMenuPositionFromEvent, type ContextMenuPosition } from '$lib/utils/context-menu';
|
import { getContextMenuPositionFromEvent, type ContextMenuPosition } from '$lib/utils/context-menu';
|
||||||
import { getShortDateRange } from '$lib/utils/date-time';
|
import { getShortDateRange } from '$lib/utils/date-time';
|
||||||
import type { AlbumResponseDto } from '@immich/sdk';
|
import type { AlbumResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiDotsVertical } from '@mdi/js';
|
import { mdiDotsVertical } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -42,12 +43,13 @@
|
|||||||
class="absolute end-6 top-6 opacity-0 group-hover:opacity-100 focus-within:opacity-100"
|
class="absolute end-6 top-6 opacity-0 group-hover:opacity-100 focus-within:opacity-100"
|
||||||
data-testid="context-button-parent"
|
data-testid="context-button-parent"
|
||||||
>
|
>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="opaque"
|
color="secondary"
|
||||||
title={$t('show_album_options')}
|
aria-label={$t('show_album_options')}
|
||||||
icon={mdiDotsVertical}
|
icon={mdiDotsVertical}
|
||||||
size="20"
|
shape="round"
|
||||||
padding="2"
|
variant="ghost"
|
||||||
|
size="medium"
|
||||||
class="icon-white-drop-shadow"
|
class="icon-white-drop-shadow"
|
||||||
onclick={showAlbumContextMenu}
|
onclick={showAlbumContextMenu}
|
||||||
/>
|
/>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
import { delay } from '$lib/utils/asset-utils';
|
import { delay } from '$lib/utils/asset-utils';
|
||||||
import { navigate } from '$lib/utils/navigation';
|
import { navigate } from '$lib/utils/navigation';
|
||||||
import { getAlbumInfo, type AlbumResponseDto, type MapMarkerResponseDto } from '@immich/sdk';
|
import { getAlbumInfo, type AlbumResponseDto, type MapMarkerResponseDto } from '@immich/sdk';
|
||||||
import { LoadingSpinner, Modal, ModalBody } from '@immich/ui';
|
import { IconButton, LoadingSpinner, Modal, ModalBody } from '@immich/ui';
|
||||||
import { mdiMapOutline } from '@mdi/js';
|
import { mdiMapOutline } from '@mdi/js';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -103,7 +103,14 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CircleIconButton title={$t('map')} onclick={openMap} icon={mdiMapOutline} />
|
<IconButton
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
icon={mdiMapOutline}
|
||||||
|
onclick={openMap}
|
||||||
|
aria-label={$t('map')}
|
||||||
|
/>
|
||||||
|
|
||||||
{#if albumMapViewManager.isInMapView}
|
{#if albumMapViewManager.isInMapView}
|
||||||
<Modal title={$t('map')} size="medium" onClose={closeMap}>
|
<Modal title={$t('map')} size="medium" onClose={closeMap}>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import SharedLinkCopy from '$lib/components/sharedlinks-page/actions/shared-link-copy.svelte';
|
import SharedLinkCopy from '$lib/components/sharedlinks-page/actions/shared-link-copy.svelte';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import type { AlbumResponseDto, SharedLinkResponseDto } from '@immich/sdk';
|
import type { AlbumResponseDto, SharedLinkResponseDto } from '@immich/sdk';
|
||||||
import { Text } from '@immich/ui';
|
import { IconButton, Text } from '@immich/ui';
|
||||||
import { mdiQrcode } from '@mdi/js';
|
import { mdiQrcode } from '@mdi/js';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -40,7 +40,14 @@
|
|||||||
<Text size="tiny" color="muted">{getShareProperties()}</Text>
|
<Text size="tiny" color="muted">{getShareProperties()}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<CircleIconButton title={$t('view_qr_code')} icon={mdiQrcode} onclick={onViewQrCode} />
|
<IconButton
|
||||||
|
aria-label={$t('view_qr_code')}
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
icon={mdiQrcode}
|
||||||
|
onclick={onViewQrCode}
|
||||||
|
/>
|
||||||
<SharedLinkCopy link={sharedLink} />
|
<SharedLinkCopy link={sharedLink} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
import { mdiFileImagePlusOutline, mdiFolderDownloadOutline } from '@mdi/js';
|
import { mdiFileImagePlusOutline, mdiFolderDownloadOutline } from '@mdi/js';
|
||||||
import { onDestroy } from 'svelte';
|
import { onDestroy } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import DownloadAction from '../photos-page/actions/download-action.svelte';
|
import DownloadAction from '../photos-page/actions/download-action.svelte';
|
||||||
import AssetGrid from '../photos-page/asset-grid.svelte';
|
import AssetGrid from '../photos-page/asset-grid.svelte';
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
@ -22,6 +21,7 @@
|
|||||||
import ThemeButton from '../shared-components/theme-button.svelte';
|
import ThemeButton from '../shared-components/theme-button.svelte';
|
||||||
import AlbumSummary from './album-summary.svelte';
|
import AlbumSummary from './album-summary.svelte';
|
||||||
import CastButton from '$lib/cast/cast-button.svelte';
|
import CastButton from '$lib/cast/cast-button.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sharedLink: SharedLinkResponseDto;
|
sharedLink: SharedLinkResponseDto;
|
||||||
@ -104,19 +104,25 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
{#snippet trailing()}
|
{#snippet trailing()}
|
||||||
<CastButton whiteHover />
|
<CastButton />
|
||||||
|
|
||||||
{#if sharedLink.allowUpload}
|
{#if sharedLink.allowUpload}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('add_photos')}
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('add_photos')}
|
||||||
onclick={() => openFileUploadDialog({ albumId: album.id })}
|
onclick={() => openFileUploadDialog({ albumId: album.id })}
|
||||||
icon={mdiFileImagePlusOutline}
|
icon={mdiFileImagePlusOutline}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if album.assetCount > 0 && sharedLink.allowDownload}
|
{#if album.assetCount > 0 && sharedLink.allowDownload}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('download')}
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('download')}
|
||||||
onclick={() => downloadAlbum(album)}
|
onclick={() => downloadAlbum(album)}
|
||||||
icon={mdiFolderDownloadOutline}
|
icon={mdiFolderDownloadOutline}
|
||||||
/>
|
/>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { shortcut } from '$lib/actions/shortcut';
|
import { shortcut } from '$lib/actions/shortcut';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiArrowLeft } from '@mdi/js';
|
import { mdiArrowLeft } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -12,4 +13,11 @@
|
|||||||
|
|
||||||
<svelte:document use:shortcut={{ shortcut: { key: 'Escape' }, onShortcut: onClose }} />
|
<svelte:document use:shortcut={{ shortcut: { key: 'Escape' }, onShortcut: onClose }} />
|
||||||
|
|
||||||
<CircleIconButton color="opaque" icon={mdiArrowLeft} title={$t('go_back')} onclick={onClose} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
icon={mdiArrowLeft}
|
||||||
|
aria-label={$t('go_back')}
|
||||||
|
onclick={onClose}
|
||||||
|
/>
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import { mdiDeleteForeverOutline, mdiDeleteOutline } from '@mdi/js';
|
import { mdiDeleteForeverOutline, mdiDeleteOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { OnAction, PreAction } from './action';
|
import type { OnAction, PreAction } from './action';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
asset: AssetResponseDto;
|
asset: AssetResponseDto;
|
||||||
@ -79,10 +80,12 @@
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="opaque"
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
icon={asset.isTrashed ? mdiDeleteForeverOutline : mdiDeleteOutline}
|
icon={asset.isTrashed ? mdiDeleteForeverOutline : mdiDeleteOutline}
|
||||||
title={asset.isTrashed ? $t('permanently_delete') : $t('delete')}
|
aria-label={asset.isTrashed ? $t('permanently_delete') : $t('delete')}
|
||||||
onclick={() => trashOrDelete(asset.isTrashed)}
|
onclick={() => trashOrDelete(asset.isTrashed)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import type { TimelineAsset } from '$lib/stores/assets-store.svelte';
|
import type { TimelineAsset } from '$lib/stores/assets-store.svelte';
|
||||||
import { downloadFile } from '$lib/utils/asset-utils';
|
import { downloadFile } from '$lib/utils/asset-utils';
|
||||||
import { getAssetInfo } from '@immich/sdk';
|
import { getAssetInfo } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiFolderDownloadOutline } from '@mdi/js';
|
import { mdiFolderDownloadOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -21,7 +22,13 @@
|
|||||||
<svelte:document use:shortcut={{ shortcut: { key: 'd', shift: true }, onShortcut: onDownloadFile }} />
|
<svelte:document use:shortcut={{ shortcut: { key: 'd', shift: true }, onShortcut: onDownloadFile }} />
|
||||||
|
|
||||||
{#if !menuItem}
|
{#if !menuItem}
|
||||||
<CircleIconButton color="opaque" icon={mdiFolderDownloadOutline} title={$t('download')} onclick={onDownloadFile} />
|
<IconButton
|
||||||
|
color="primary"
|
||||||
|
shape="round"
|
||||||
|
icon={mdiFolderDownloadOutline}
|
||||||
|
aria-label={$t('download')}
|
||||||
|
onclick={onDownloadFile}
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<MenuOption icon={mdiFolderDownloadOutline} text={$t('download')} onClick={onDownloadFile} />
|
<MenuOption icon={mdiFolderDownloadOutline} text={$t('download')} onClick={onDownloadFile} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
import { mdiHeart, mdiHeartOutline } from '@mdi/js';
|
import { mdiHeart, mdiHeartOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { OnAction } from './action';
|
import type { OnAction } from './action';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
asset: AssetResponseDto;
|
asset: AssetResponseDto;
|
||||||
@ -47,9 +48,11 @@
|
|||||||
|
|
||||||
<svelte:document use:shortcut={{ shortcut: { key: 'f' }, onShortcut: toggleFavorite }} />
|
<svelte:document use:shortcut={{ shortcut: { key: 'f' }, onShortcut: toggleFavorite }} />
|
||||||
|
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="opaque"
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
icon={asset.isFavorite ? mdiHeart : mdiHeartOutline}
|
icon={asset.isFavorite ? mdiHeart : mdiHeartOutline}
|
||||||
title={asset.isFavorite ? $t('unfavorite') : $t('to_favorite')}
|
aria-label={asset.isFavorite ? $t('unfavorite') : $t('to_favorite')}
|
||||||
onclick={toggleFavorite}
|
onclick={toggleFavorite}
|
||||||
/>
|
/>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts"></script>
|
<script lang="ts">
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiMotionPauseOutline, mdiPlaySpeed } from '@mdi/js';
|
import { mdiMotionPauseOutline, mdiPlaySpeed } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -10,9 +11,10 @@
|
|||||||
let { isPlaying, onClick }: Props = $props();
|
let { isPlaying, onClick }: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="opaque"
|
shape="round"
|
||||||
|
color="primary"
|
||||||
icon={isPlaying ? mdiMotionPauseOutline : mdiPlaySpeed}
|
icon={isPlaying ? mdiMotionPauseOutline : mdiPlaySpeed}
|
||||||
title={isPlaying ? $t('stop_motion_photo') : $t('play_motion_photo')}
|
aria-label={isPlaying ? $t('stop_motion_photo') : $t('play_motion_photo')}
|
||||||
onclick={() => onClick(!isPlaying)}
|
onclick={() => onClick(!isPlaying)}
|
||||||
/>
|
/>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
||||||
import { makeSharedLinkUrl } from '$lib/utils';
|
import { makeSharedLinkUrl } from '$lib/utils';
|
||||||
import type { AssetResponseDto } from '@immich/sdk';
|
import type { AssetResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiShareVariantOutline } from '@mdi/js';
|
import { mdiShareVariantOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -22,4 +23,11 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CircleIconButton color="opaque" icon={mdiShareVariantOutline} onclick={handleClick} title={$t('share')} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
icon={mdiShareVariantOutline}
|
||||||
|
onclick={handleClick}
|
||||||
|
aria-label={$t('share')}
|
||||||
|
/>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { shortcut } from '$lib/actions/shortcut';
|
import { shortcut } from '$lib/actions/shortcut';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiInformationOutline } from '@mdi/js';
|
import { mdiInformationOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -12,4 +13,11 @@
|
|||||||
|
|
||||||
<svelte:document use:shortcut={{ shortcut: { key: 'i' }, onShortcut: onShowDetail }} />
|
<svelte:document use:shortcut={{ shortcut: { key: 'i' }, onShortcut: onShowDetail }} />
|
||||||
|
|
||||||
<CircleIconButton color="opaque" icon={mdiInformationOutline} onclick={onShowDetail} title={$t('info')} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
icon={mdiInformationOutline}
|
||||||
|
onclick={onShowDetail}
|
||||||
|
aria-label={$t('info')}
|
||||||
|
/>
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { isTenMinutesApart } from '$lib/utils/timesince';
|
import { isTenMinutesApart } from '$lib/utils/timesince';
|
||||||
import { ReactionType, type ActivityResponseDto, type AssetTypeEnum, type UserResponseDto } from '@immich/sdk';
|
import { ReactionType, type ActivityResponseDto, type AssetTypeEnum, type UserResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiClose, mdiDeleteOutline, mdiDotsVertical, mdiHeart, mdiSend } from '@mdi/js';
|
import { mdiClose, mdiDeleteOutline, mdiDotsVertical, mdiHeart, mdiSend } from '@mdi/js';
|
||||||
import * as luxon from 'luxon';
|
import * as luxon from 'luxon';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
import UserAvatar from '../shared-components/user-avatar.svelte';
|
import UserAvatar from '../shared-components/user-avatar.svelte';
|
||||||
@ -125,7 +125,14 @@
|
|||||||
bind:clientHeight={activityHeight}
|
bind:clientHeight={activityHeight}
|
||||||
>
|
>
|
||||||
<div class="flex place-items-center gap-2">
|
<div class="flex place-items-center gap-2">
|
||||||
<CircleIconButton onclick={onClose} icon={mdiClose} title={$t('close')} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
onclick={onClose}
|
||||||
|
icon={mdiClose}
|
||||||
|
aria-label={$t('close')}
|
||||||
|
/>
|
||||||
|
|
||||||
<p class="text-lg text-immich-fg dark:text-immich-dark-fg">{$t('activity')}</p>
|
<p class="text-lg text-immich-fg dark:text-immich-dark-fg">{$t('activity')}</p>
|
||||||
</div>
|
</div>
|
||||||
@ -159,7 +166,7 @@
|
|||||||
title={$t('comment_options')}
|
title={$t('comment_options')}
|
||||||
align="top-right"
|
align="top-right"
|
||||||
direction="left"
|
direction="left"
|
||||||
size="16"
|
size="small"
|
||||||
>
|
>
|
||||||
<MenuOption
|
<MenuOption
|
||||||
activeColor="bg-red-200"
|
activeColor="bg-red-200"
|
||||||
@ -212,7 +219,7 @@
|
|||||||
title={$t('reaction_options')}
|
title={$t('reaction_options')}
|
||||||
align="top-right"
|
align="top-right"
|
||||||
direction="left"
|
direction="left"
|
||||||
size="16"
|
size="small"
|
||||||
>
|
>
|
||||||
<MenuOption
|
<MenuOption
|
||||||
activeColor="bg-red-200"
|
activeColor="bg-red-200"
|
||||||
@ -269,9 +276,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else if message}
|
{:else if message}
|
||||||
<div class="flex items-end w-fit ms-0">
|
<div class="flex items-end w-fit ms-0">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('send_message')}
|
shape="round"
|
||||||
size="15"
|
aria-label={$t('send_message')}
|
||||||
|
size="small"
|
||||||
|
variant="ghost"
|
||||||
icon={mdiSend}
|
icon={mdiSend}
|
||||||
class="dark:text-immich-dark-gray"
|
class="dark:text-immich-dark-gray"
|
||||||
onclick={() => handleSendComment()}
|
onclick={() => handleSendComment()}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
type PersonResponseDto,
|
type PersonResponseDto,
|
||||||
type StackResponseDto,
|
type StackResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiAlertOutline,
|
mdiAlertOutline,
|
||||||
mdiCogRefreshOutline,
|
mdiCogRefreshOutline,
|
||||||
@ -122,22 +123,37 @@
|
|||||||
<ShareAction {asset} />
|
<ShareAction {asset} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if asset.isOffline}
|
{#if asset.isOffline}
|
||||||
<CircleIconButton color="alert" icon={mdiAlertOutline} onclick={onShowDetail} title={$t('asset_offline')} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="danger"
|
||||||
|
icon={mdiAlertOutline}
|
||||||
|
onclick={onShowDetail}
|
||||||
|
aria-label={$t('asset_offline')}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if asset.livePhotoVideoId}
|
{#if asset.livePhotoVideoId}
|
||||||
{@render motionPhoto?.()}
|
{@render motionPhoto?.()}
|
||||||
{/if}
|
{/if}
|
||||||
{#if asset.type === AssetTypeEnum.Image}
|
{#if asset.type === AssetTypeEnum.Image}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="opaque"
|
class="hidden sm:flex"
|
||||||
hideMobile={true}
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
icon={$photoZoomState && $photoZoomState.currentZoom > 1 ? mdiMagnifyMinusOutline : mdiMagnifyPlusOutline}
|
icon={$photoZoomState && $photoZoomState.currentZoom > 1 ? mdiMagnifyMinusOutline : mdiMagnifyPlusOutline}
|
||||||
title={$t('zoom_image')}
|
aria-label={$t('zoom_image')}
|
||||||
onclick={onZoomImage}
|
onclick={onZoomImage}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if canCopyImageToClipboard() && asset.type === AssetTypeEnum.Image}
|
{#if canCopyImageToClipboard() && asset.type === AssetTypeEnum.Image}
|
||||||
<CircleIconButton color="opaque" icon={mdiContentCopy} title={$t('copy_image')} onclick={() => onCopyImage?.()} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
icon={mdiContentCopy}
|
||||||
|
aria-label={$t('copy_image')}
|
||||||
|
onclick={() => onCopyImage?.()}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if !isOwner && showDownloadButton}
|
{#if !isOwner && showDownloadButton}
|
||||||
@ -151,20 +167,11 @@
|
|||||||
{#if isOwner}
|
{#if isOwner}
|
||||||
<FavoriteAction {asset} {onAction} />
|
<FavoriteAction {asset} {onAction} />
|
||||||
{/if}
|
{/if}
|
||||||
<!-- {#if showEditorButton}
|
|
||||||
<CircleIconButton
|
|
||||||
color="opaque"
|
|
||||||
hideMobile={true}
|
|
||||||
icon={mdiImageEditOutline}
|
|
||||||
onclick={showEditorHandler}
|
|
||||||
title={$t('editor')}
|
|
||||||
/>
|
|
||||||
{/if} -->
|
|
||||||
|
|
||||||
{#if isOwner}
|
{#if isOwner}
|
||||||
<DeleteAction {asset} {onAction} {preAction} />
|
<DeleteAction {asset} {onAction} {preAction} />
|
||||||
|
|
||||||
<ButtonContextMenu direction="left" align="top-right" color="opaque" title={$t('more')} icon={mdiDotsVertical}>
|
<ButtonContextMenu direction="left" align="top-right" color="secondary" title={$t('more')} icon={mdiDotsVertical}>
|
||||||
{#if showSlideshow && !isLocked}
|
{#if showSlideshow && !isLocked}
|
||||||
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
|
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
type AssetResponseDto,
|
type AssetResponseDto,
|
||||||
type ExifResponseDto,
|
type ExifResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiCalendar,
|
mdiCalendar,
|
||||||
mdiCameraIris,
|
mdiCameraIris,
|
||||||
@ -42,7 +43,6 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import PersonSidePanel from '../faces-page/person-side-panel.svelte';
|
import PersonSidePanel from '../faces-page/person-side-panel.svelte';
|
||||||
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
||||||
import UserAvatar from '../shared-components/user-avatar.svelte';
|
import UserAvatar from '../shared-components/user-avatar.svelte';
|
||||||
@ -158,7 +158,14 @@
|
|||||||
|
|
||||||
<section class="relative p-2">
|
<section class="relative p-2">
|
||||||
<div class="flex place-items-center gap-2">
|
<div class="flex place-items-center gap-2">
|
||||||
<CircleIconButton icon={mdiClose} title={$t('close')} onclick={onClose} />
|
<IconButton
|
||||||
|
icon={mdiClose}
|
||||||
|
aria-label={$t('close')}
|
||||||
|
onclick={onClose}
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
/>
|
||||||
<p class="text-lg text-immich-fg dark:text-immich-dark-fg">{$t('info')}</p>
|
<p class="text-lg text-immich-fg dark:text-immich-dark-fg">{$t('info')}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -193,30 +200,34 @@
|
|||||||
<h2>{$t('people').toUpperCase()}</h2>
|
<h2>{$t('people').toUpperCase()}</h2>
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2 items-center">
|
||||||
{#if people.some((person) => person.isHidden)}
|
{#if people.some((person) => person.isHidden)}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('show_hidden_people')}
|
aria-label={$t('show_hidden_people')}
|
||||||
icon={showingHiddenPeople ? mdiEyeOff : mdiEye}
|
icon={showingHiddenPeople ? mdiEyeOff : mdiEye}
|
||||||
padding="1"
|
size="medium"
|
||||||
buttonSize="32"
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
onclick={() => (showingHiddenPeople = !showingHiddenPeople)}
|
onclick={() => (showingHiddenPeople = !showingHiddenPeople)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('tag_people')}
|
aria-label={$t('tag_people')}
|
||||||
icon={mdiPlus}
|
icon={mdiPlus}
|
||||||
padding="1"
|
size="medium"
|
||||||
size="20"
|
shape="round"
|
||||||
buttonSize="32"
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
onclick={() => (isFaceEditMode.value = !isFaceEditMode.value)}
|
onclick={() => (isFaceEditMode.value = !isFaceEditMode.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if people.length > 0 || unassignedFaces.length > 0}
|
{#if people.length > 0 || unassignedFaces.length > 0}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('edit_people')}
|
aria-label={$t('edit_people')}
|
||||||
icon={mdiPencil}
|
icon={mdiPencil}
|
||||||
padding="1"
|
size="medium"
|
||||||
size="20"
|
shape="round"
|
||||||
buttonSize="32"
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
onclick={() => (showEditFaces = true)}
|
onclick={() => (showEditFaces = true)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
@ -369,11 +380,13 @@
|
|||||||
<p class="break-all flex place-items-center gap-2 whitespace-pre-wrap">
|
<p class="break-all flex place-items-center gap-2 whitespace-pre-wrap">
|
||||||
{asset.originalFileName}
|
{asset.originalFileName}
|
||||||
{#if isOwner}
|
{#if isOwner}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
icon={mdiInformationOutline}
|
icon={mdiInformationOutline}
|
||||||
title={$t('show_file_location')}
|
aria-label={$t('show_file_location')}
|
||||||
size="16"
|
size="small"
|
||||||
padding="2"
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
onclick={toggleAssetPath}
|
onclick={toggleAssetPath}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fly, slide } from 'svelte/transition';
|
import { fly, slide } from 'svelte/transition';
|
||||||
import { getByteUnitString } from '../../utils/byte-units';
|
import { getByteUnitString } from '../../utils/byte-units';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
const abort = (downloadKey: string, download: DownloadProgress) => {
|
const abort = (downloadKey: string, download: DownloadProgress) => {
|
||||||
download.abort?.abort();
|
download.abort?.abort();
|
||||||
@ -42,10 +42,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="absolute end-2">
|
<div class="absolute end-2">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('close')}
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('close')}
|
||||||
onclick={() => abort(downloadKey, download)}
|
onclick={() => abort(downloadKey, download)}
|
||||||
size="20"
|
size="large"
|
||||||
icon={mdiClose}
|
icon={mdiClose}
|
||||||
class="dark:text-immich-dark-gray"
|
class="dark:text-immich-dark-gray"
|
||||||
/>
|
/>
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
rotateDegrees,
|
rotateDegrees,
|
||||||
type CropAspectRatio,
|
type CropAspectRatio,
|
||||||
} from '$lib/stores/asset-editor.store';
|
} from '$lib/stores/asset-editor.store';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiBackupRestore, mdiCropFree, mdiRotateLeft, mdiRotateRight, mdiSquareOutline } from '@mdi/js';
|
import { mdiBackupRestore, mdiCropFree, mdiRotateLeft, mdiRotateRight, mdiSquareOutline } from '@mdi/js';
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -147,7 +148,25 @@
|
|||||||
<h2>{$t('editor_crop_tool_h2_rotation').toUpperCase()}</h2>
|
<h2>{$t('editor_crop_tool_h2_rotation').toUpperCase()}</h2>
|
||||||
</div>
|
</div>
|
||||||
<ul class="flex-wrap flex-row flex gap-x-6 gap-y-4 justify-center">
|
<ul class="flex-wrap flex-row flex gap-x-6 gap-y-4 justify-center">
|
||||||
<li><CircleIconButton title={$t('anti_clockwise')} onclick={() => rotate(false)} icon={mdiRotateLeft} /></li>
|
<li>
|
||||||
<li><CircleIconButton title={$t('clockwise')} onclick={() => rotate(true)} icon={mdiRotateRight} /></li>
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('anti_clockwise')}
|
||||||
|
onclick={() => rotate(false)}
|
||||||
|
icon={mdiRotateLeft}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('clockwise')}
|
||||||
|
onclick={() => rotate(true)}
|
||||||
|
icon={mdiRotateRight}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
import { editTypes, showCancelConfirmDialog } from '$lib/stores/asset-editor.store';
|
import { editTypes, showCancelConfirmDialog } from '$lib/stores/asset-editor.store';
|
||||||
import { websocketEvents } from '$lib/stores/websocket';
|
import { websocketEvents } from '$lib/stores/websocket';
|
||||||
import { type AssetResponseDto } from '@immich/sdk';
|
import { type AssetResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiClose } from '@mdi/js';
|
import { mdiClose } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import CircleIconButton from '../../elements/buttons/circle-icon-button.svelte';
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
return websocketEvents.on('on_asset_update', (assetUpdate) => {
|
return websocketEvents.on('on_asset_update', (assetUpdate) => {
|
||||||
@ -44,17 +44,25 @@
|
|||||||
|
|
||||||
<section class="relative p-2 dark:bg-immich-dark-bg dark:text-immich-dark-fg">
|
<section class="relative p-2 dark:bg-immich-dark-bg dark:text-immich-dark-fg">
|
||||||
<div class="flex place-items-center gap-2">
|
<div class="flex place-items-center gap-2">
|
||||||
<CircleIconButton icon={mdiClose} title={$t('close')} onclick={onClose} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
icon={mdiClose}
|
||||||
|
aria-label={$t('close')}
|
||||||
|
onclick={onClose}
|
||||||
|
/>
|
||||||
<p class="text-lg text-immich-fg dark:text-immich-dark-fg capitalize">{$t('editor')}</p>
|
<p class="text-lg text-immich-fg dark:text-immich-dark-fg capitalize">{$t('editor')}</p>
|
||||||
</div>
|
</div>
|
||||||
<section class="px-4 py-4">
|
<section class="px-4 py-4">
|
||||||
<ul class="flex w-full justify-around">
|
<ul class="flex w-full justify-around">
|
||||||
{#each editTypes as etype (etype.name)}
|
{#each editTypes as etype (etype.name)}
|
||||||
<li>
|
<li>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color={etype.name === selectedType ? 'primary' : 'opaque'}
|
shape="round"
|
||||||
|
color={etype.name === selectedType ? 'primary' : 'secondary'}
|
||||||
icon={etype.icon}
|
icon={etype.icon}
|
||||||
title={etype.name}
|
aria-label={etype.name}
|
||||||
onclick={() => selectType(etype.name)}
|
onclick={() => selectType(etype.name)}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||||
import { castManager, CastState } from '$lib/managers/cast-manager.svelte';
|
import { castManager, CastState } from '$lib/managers/cast-manager.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiCastConnected, mdiPause, mdiPlay } from '@mdi/js';
|
import { mdiCastConnected, mdiPause, mdiPlay } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -83,11 +84,13 @@
|
|||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="opaque"
|
color="primary"
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
icon={castManager.castState == CastState.PLAYING ? mdiPause : mdiPlay}
|
icon={castManager.castState == CastState.PLAYING ? mdiPause : mdiPlay}
|
||||||
onclick={() => handlePlayPauseButton()}
|
onclick={() => handlePlayPauseButton()}
|
||||||
title={castManager.castState == CastState.PLAYING ? 'Pause' : 'Play'}
|
aria-label={castManager.castState == CastState.PLAYING ? 'Pause' : 'Play'}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
|
||||||
import { render, screen } from '@testing-library/svelte';
|
|
||||||
|
|
||||||
describe('CircleIconButton component', () => {
|
|
||||||
it('should render as a button', () => {
|
|
||||||
render(CircleIconButton, { icon: '', title: 'test' });
|
|
||||||
const button = screen.getByRole('button');
|
|
||||||
expect(button).toBeInTheDocument();
|
|
||||||
expect(button).toHaveAttribute('type', 'button');
|
|
||||||
expect(button).not.toHaveAttribute('href');
|
|
||||||
expect(button).toHaveAttribute('title', 'test');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render as a link if href prop is set', () => {
|
|
||||||
render(CircleIconButton, { props: { href: '/test', icon: '', title: 'test' } });
|
|
||||||
const link = screen.getByRole('link');
|
|
||||||
expect(link).toBeInTheDocument();
|
|
||||||
expect(link).toHaveAttribute('href', '/test');
|
|
||||||
expect(link).not.toHaveAttribute('type');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render icon inside button', () => {
|
|
||||||
render(CircleIconButton, { icon: '', title: 'test' });
|
|
||||||
const button = screen.getByRole('button');
|
|
||||||
const icon = button.querySelector('svg');
|
|
||||||
expect(icon).toBeInTheDocument();
|
|
||||||
expect(icon).toHaveAttribute('aria-label', 'test');
|
|
||||||
});
|
|
||||||
});
|
|
@ -3,6 +3,7 @@
|
|||||||
import { mdiClose, mdiMagnify } from '@mdi/js';
|
import { mdiClose, mdiMagnify } from '@mdi/js';
|
||||||
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
name: string;
|
name: string;
|
||||||
@ -42,11 +43,13 @@
|
|||||||
? 'rounded-2xl'
|
? 'rounded-2xl'
|
||||||
: 'rounded-t-lg'} bg-gray-200 p-2 dark:bg-immich-dark-gray gap-2 place-items-center h-full"
|
: 'rounded-t-lg'} bg-gray-200 p-2 dark:bg-immich-dark-gray gap-2 place-items-center h-full"
|
||||||
>
|
>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
icon={mdiMagnify}
|
icon={mdiMagnify}
|
||||||
title={$t('search')}
|
aria-label={$t('search')}
|
||||||
size="16"
|
size="small"
|
||||||
padding="2"
|
|
||||||
onclick={() => onSearch({ force: true })}
|
onclick={() => onSearch({ force: true })}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
@ -64,6 +67,14 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if name}
|
{#if name}
|
||||||
<CircleIconButton icon={mdiClose} title={$t('clear_value')} size="16" padding="2" onclick={resetSearch} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
icon={mdiClose}
|
||||||
|
aria-label={$t('clear_value')}
|
||||||
|
size="small"
|
||||||
|
onclick={resetSearch}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
import { zoomImageToBase64 } from '$lib/utils/people-utils';
|
import { zoomImageToBase64 } from '$lib/utils/people-utils';
|
||||||
import { getPersonNameWithHiddenValue } from '$lib/utils/person';
|
import { getPersonNameWithHiddenValue } from '$lib/utils/person';
|
||||||
import { AssetTypeEnum, getAllPeople, type AssetFaceResponseDto, type PersonResponseDto } from '@immich/sdk';
|
import { AssetTypeEnum, getAllPeople, type AssetFaceResponseDto, type PersonResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiArrowLeftThin, mdiClose, mdiMagnify, mdiPlus } from '@mdi/js';
|
import { mdiArrowLeftThin, mdiClose, mdiMagnify, mdiPlus } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -78,19 +79,36 @@
|
|||||||
<div class="flex place-items-center justify-between gap-2">
|
<div class="flex place-items-center justify-between gap-2">
|
||||||
{#if !searchFaces}
|
{#if !searchFaces}
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} onclick={onClose} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
icon={mdiArrowLeftThin}
|
||||||
|
aria-label={$t('back')}
|
||||||
|
onclick={onClose}
|
||||||
|
/>
|
||||||
<p class="flex text-lg text-immich-fg dark:text-immich-dark-fg">{$t('select_face')}</p>
|
<p class="flex text-lg text-immich-fg dark:text-immich-dark-fg">{$t('select_face')}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end gap-2">
|
<div class="flex justify-end gap-2">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
icon={mdiMagnify}
|
icon={mdiMagnify}
|
||||||
title={$t('search_for_existing_person')}
|
aria-label={$t('search_for_existing_person')}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
searchFaces = true;
|
searchFaces = true;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{#if !isShowLoadingNewPerson}
|
{#if !isShowLoadingNewPerson}
|
||||||
<CircleIconButton icon={mdiPlus} title={$t('create_new_person')} onclick={handleCreatePerson} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
icon={mdiPlus}
|
||||||
|
aria-label={$t('create_new_person')}
|
||||||
|
onclick={handleCreatePerson}
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex place-content-center place-items-center">
|
<div class="flex place-content-center place-items-center">
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
@ -98,7 +116,14 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} onclick={onClose} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
icon={mdiArrowLeftThin}
|
||||||
|
aria-label={$t('back')}
|
||||||
|
onclick={onClose}
|
||||||
|
/>
|
||||||
<div class="w-full flex">
|
<div class="w-full flex">
|
||||||
<SearchPeople
|
<SearchPeople
|
||||||
type="input"
|
type="input"
|
||||||
@ -112,7 +137,14 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<CircleIconButton icon={mdiClose} title={$t('cancel_search')} onclick={() => (searchFaces = false)} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
icon={mdiClose}
|
||||||
|
aria-label={$t('cancel_search')}
|
||||||
|
onclick={() => (searchFaces = false)}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="px-4 py-4 text-sm">
|
<div class="px-4 py-4 text-sm">
|
||||||
|
@ -11,10 +11,9 @@
|
|||||||
import { getPeopleThumbnailUrl } from '$lib/utils';
|
import { getPeopleThumbnailUrl } from '$lib/utils';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { updatePeople, type PersonResponseDto } from '@immich/sdk';
|
import { updatePeople, type PersonResponseDto } from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiClose, mdiEye, mdiEyeOff, mdiEyeSettings, mdiRestart } from '@mdi/js';
|
import { mdiClose, mdiEye, mdiEyeOff, mdiEyeSettings, mdiRestart } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
people: PersonResponseDto[];
|
people: PersonResponseDto[];
|
||||||
@ -114,7 +113,14 @@
|
|||||||
class="fixed top-0 flex h-16 w-full items-center justify-between border-b bg-white p-1 dark:border-immich-dark-gray dark:bg-black dark:text-immich-dark-fg md:p-8"
|
class="fixed top-0 flex h-16 w-full items-center justify-between border-b bg-white p-1 dark:border-immich-dark-gray dark:bg-black dark:text-immich-dark-fg md:p-8"
|
||||||
>
|
>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<CircleIconButton title={$t('close')} icon={mdiClose} onclick={onClose} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('close')}
|
||||||
|
icon={mdiClose}
|
||||||
|
onclick={onClose}
|
||||||
|
/>
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2 items-center">
|
||||||
<p id={titleId} class="ms-2">{$t('show_and_hide_people')}</p>
|
<p id={titleId} class="ms-2">{$t('show_and_hide_people')}</p>
|
||||||
<p class="text-sm text-gray-400 dark:text-gray-600">({totalPeopleCount.toLocaleString($locale)})</p>
|
<p class="text-sm text-gray-400 dark:text-gray-600">({totalPeopleCount.toLocaleString($locale)})</p>
|
||||||
@ -122,8 +128,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-end">
|
<div class="flex items-center justify-end">
|
||||||
<div class="flex items-center md:me-4">
|
<div class="flex items-center md:me-4">
|
||||||
<CircleIconButton title={$t('reset_people_visibility')} icon={mdiRestart} onclick={handleResetVisibility} />
|
<IconButton
|
||||||
<CircleIconButton title={toggleButton.label} icon={toggleButton.icon} onclick={handleToggleVisibility} />
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('reset_people_visibility')}
|
||||||
|
icon={mdiRestart}
|
||||||
|
onclick={handleResetVisibility}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={toggleButton.label}
|
||||||
|
icon={toggleButton.icon}
|
||||||
|
onclick={handleToggleVisibility}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button loading={showLoadingSpinner} onclick={handleSaveVisibility} size="small">{$t('done')}</Button>
|
<Button loading={showLoadingSpinner} onclick={handleSaveVisibility} size="small">{$t('done')}</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,14 +6,13 @@
|
|||||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { getAllPeople, getPerson, mergePerson, type PersonResponseDto } from '@immich/sdk';
|
import { getAllPeople, getPerson, mergePerson, type PersonResponseDto } from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
|
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { flip } from 'svelte/animate';
|
import { flip } from 'svelte/animate';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
import FaceThumbnail from './face-thumbnail.svelte';
|
import FaceThumbnail from './face-thumbnail.svelte';
|
||||||
@ -133,10 +132,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if selectedPeople.length === 1}
|
{#if selectedPeople.length === 1}
|
||||||
<div class="absolute bottom-2">
|
<div class="absolute bottom-2">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('swap_merge_direction')}
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('swap_merge_direction')}
|
||||||
icon={mdiSwapHorizontal}
|
icon={mdiSwapHorizontal}
|
||||||
size="24"
|
size="large"
|
||||||
onclick={handleSwapPeople}
|
onclick={handleSwapPeople}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import FaceThumbnail from './face-thumbnail.svelte';
|
import FaceThumbnail from './face-thumbnail.svelte';
|
||||||
import { mdiSwapVertical } from '@mdi/js';
|
import { mdiSwapVertical } from '@mdi/js';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
screenHeight: number;
|
screenHeight: number;
|
||||||
@ -31,15 +32,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if handleSearch}
|
{#if handleSearch}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
icon={mdiSwapVertical}
|
icon={mdiSwapVertical}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
sortBySimilarirty = !sortBySimilarirty;
|
sortBySimilarirty = !sortBySimilarirty;
|
||||||
handleSearch(sortBySimilarirty);
|
handleSearch(sortBySimilarirty);
|
||||||
}}
|
}}
|
||||||
color="neutral"
|
aria-label={$t('sort_people_by_similarity')}
|
||||||
title={$t('sort_people_by_similarity')}
|
/>
|
||||||
></CircleIconButton>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
import AssignFaceSidePanel from './assign-face-side-panel.svelte';
|
import AssignFaceSidePanel from './assign-face-side-panel.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
assetId: string;
|
assetId: string;
|
||||||
@ -196,7 +197,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex place-items-center justify-between gap-2">
|
<div class="flex place-items-center justify-between gap-2">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} onclick={onClose} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
icon={mdiArrowLeftThin}
|
||||||
|
aria-label={$t('back')}
|
||||||
|
onclick={onClose}
|
||||||
|
/>
|
||||||
<p class="flex text-lg text-immich-fg dark:text-immich-dark-fg">{$t('edit_faces')}</p>
|
<p class="flex text-lg text-immich-fg dark:text-immich-dark-fg">{$t('edit_faces')}</p>
|
||||||
</div>
|
</div>
|
||||||
{#if !isShowLoadingDone}
|
{#if !isShowLoadingDone}
|
||||||
@ -303,22 +311,22 @@
|
|||||||
|
|
||||||
<div class="absolute -end-[5px] -top-[5px] h-[20px] w-[20px] rounded-full">
|
<div class="absolute -end-[5px] -top-[5px] h-[20px] w-[20px] rounded-full">
|
||||||
{#if selectedPersonToCreate[face.id] || selectedPersonToReassign[face.id]}
|
{#if selectedPersonToCreate[face.id] || selectedPersonToReassign[face.id]}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiRestart}
|
icon={mdiRestart}
|
||||||
title={$t('reset')}
|
aria-label={$t('reset')}
|
||||||
size="18"
|
size="medium"
|
||||||
padding="1"
|
|
||||||
class="absolute start-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
class="absolute start-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
||||||
onclick={() => handleReset(face.id)}
|
onclick={() => handleReset(face.id)}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiPencil}
|
icon={mdiPencil}
|
||||||
title={$t('select_new_face')}
|
aria-label={$t('select_new_face')}
|
||||||
size="18"
|
size="medium"
|
||||||
padding="1"
|
|
||||||
class="absolute start-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
class="absolute start-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
||||||
onclick={() => handleFacePicker(face)}
|
onclick={() => handleFacePicker(face)}
|
||||||
/>
|
/>
|
||||||
@ -335,12 +343,12 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if face.person != null}
|
{#if face.person != null}
|
||||||
<div class="absolute -end-[5px] top-[25px] h-[20px] w-[20px] rounded-full">
|
<div class="absolute -end-[5px] top-[25px] h-[20px] w-[20px] rounded-full">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="red"
|
shape="round"
|
||||||
|
color="danger"
|
||||||
icon={mdiTrashCan}
|
icon={mdiTrashCan}
|
||||||
title={$t('delete_face')}
|
aria-label={$t('delete_face')}
|
||||||
size="18"
|
size="medium"
|
||||||
padding="1"
|
|
||||||
class="absolute start-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
class="absolute start-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
||||||
onclick={() => deleteAssetFace(face)}
|
onclick={() => deleteAssetFace(face)}
|
||||||
/>
|
/>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import type { ValidateLibraryImportPathResponseDto } from '@immich/sdk';
|
import type { ValidateLibraryImportPathResponseDto } from '@immich/sdk';
|
||||||
import { validate, type LibraryResponseDto } from '@immich/sdk';
|
import { validate, type LibraryResponseDto } from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiAlertOutline, mdiCheckCircleOutline, mdiPencilOutline, mdiRefresh } from '@mdi/js';
|
import { mdiAlertOutline, mdiCheckCircleOutline, mdiPencilOutline, mdiRefresh } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -198,11 +198,12 @@
|
|||||||
|
|
||||||
<td class="w-4/5 text-ellipsis px-4 text-sm">{validatedPath.importPath}</td>
|
<td class="w-4/5 text-ellipsis px-4 text-sm">{validatedPath.importPath}</td>
|
||||||
<td class="w-1/5 text-ellipsis flex justify-center">
|
<td class="w-1/5 text-ellipsis flex justify-center">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiPencilOutline}
|
icon={mdiPencilOutline}
|
||||||
title={$t('edit_import_path')}
|
aria-label={$t('edit_import_path')}
|
||||||
size="16"
|
size="small"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
editImportPath = listIndex;
|
editImportPath = listIndex;
|
||||||
editedImportPath = validatedPath.importPath;
|
editedImportPath = validatedPath.importPath;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type LibraryResponseDto } from '@immich/sdk';
|
import { type LibraryResponseDto } from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiPencilOutline } from '@mdi/js';
|
import { mdiPencilOutline } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -130,11 +130,12 @@
|
|||||||
>
|
>
|
||||||
<td class="w-3/4 text-ellipsis px-4 text-sm">{exclusionPattern}</td>
|
<td class="w-3/4 text-ellipsis px-4 text-sm">{exclusionPattern}</td>
|
||||||
<td class="w-1/4 text-ellipsis flex justify-center">
|
<td class="w-1/4 text-ellipsis flex justify-center">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiPencilOutline}
|
icon={mdiPencilOutline}
|
||||||
title={$t('edit_exclusion_pattern')}
|
aria-label={$t('edit_exclusion_pattern')}
|
||||||
size="16"
|
size="small"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
editExclusionPattern = listIndex;
|
editExclusionPattern = listIndex;
|
||||||
editedExclusionPattern = exclusionPattern;
|
editedExclusionPattern = exclusionPattern;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
||||||
import { copyToClipboard } from '$lib/utils';
|
import { copyToClipboard } from '$lib/utils';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiCodeTags, mdiContentCopy, mdiMessage, mdiPartyPopper } from '@mdi/js';
|
import { mdiCodeTags, mdiContentCopy, mdiMessage, mdiPartyPopper } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -40,10 +41,11 @@
|
|||||||
🚨 {$t('error_title')}
|
🚨 {$t('error_title')}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiContentCopy}
|
icon={mdiContentCopy}
|
||||||
title={$t('copy_error')}
|
aria-label={$t('copy_error')}
|
||||||
onclick={() => handleCopy()}
|
onclick={() => handleCopy()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -320,7 +320,14 @@
|
|||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
clearSelect={() => cancelMultiselect(assetInteraction)}
|
||||||
>
|
>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('select_all')}
|
||||||
|
icon={mdiSelectAll}
|
||||||
|
onclick={handleSelectAll}
|
||||||
|
/>
|
||||||
|
|
||||||
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
@ -361,8 +368,11 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
<div class="flex place-content-center place-items-center gap-2 overflow-hidden">
|
<div class="flex place-content-center place-items-center gap-2 overflow-hidden">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={paused ? $t('play_memories') : $t('pause_memories')}
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={paused ? $t('play_memories') : $t('pause_memories')}
|
||||||
icon={paused ? mdiPlay : mdiPause}
|
icon={paused ? mdiPlay : mdiPause}
|
||||||
onclick={() => handlePromiseError(handleAction('PlayPauseButtonClick', paused ? 'play' : 'pause'))}
|
onclick={() => handlePromiseError(handleAction('PlayPauseButtonClick', paused ? 'play' : 'pause'))}
|
||||||
class="hover:text-black"
|
class="hover:text-black"
|
||||||
@ -380,8 +390,11 @@
|
|||||||
{(current.assetIndex + 1).toLocaleString($locale)}/{current.memory.assets.length.toLocaleString($locale)}
|
{(current.assetIndex + 1).toLocaleString($locale)}/{current.memory.assets.length.toLocaleString($locale)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$videoViewerMuted ? $t('unmute_memories') : $t('mute_memories')}
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$videoViewerMuted ? $t('unmute_memories') : $t('mute_memories')}
|
||||||
icon={$videoViewerMuted ? mdiVolumeOff : mdiVolumeHigh}
|
icon={$videoViewerMuted ? mdiVolumeOff : mdiVolumeHigh}
|
||||||
onclick={() => ($videoViewerMuted = !$videoViewerMuted)}
|
onclick={() => ($videoViewerMuted = !$videoViewerMuted)}
|
||||||
/>
|
/>
|
||||||
@ -399,7 +412,14 @@
|
|||||||
onclick={() => memoryWrapper?.scrollIntoView({ behavior: 'smooth' })}
|
onclick={() => memoryWrapper?.scrollIntoView({ behavior: 'smooth' })}
|
||||||
disabled={!galleryInView}
|
disabled={!galleryInView}
|
||||||
>
|
>
|
||||||
<CircleIconButton title={$t('hide_gallery')} icon={mdiChevronUp} color="light" onclick={() => {}} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('hide_gallery')}
|
||||||
|
icon={mdiChevronUp}
|
||||||
|
onclick={() => {}}
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -499,11 +519,10 @@
|
|||||||
/> -->
|
/> -->
|
||||||
<ButtonContextMenu
|
<ButtonContextMenu
|
||||||
icon={mdiDotsVertical}
|
icon={mdiDotsVertical}
|
||||||
padding="3"
|
|
||||||
title={$t('menu')}
|
title={$t('menu')}
|
||||||
onclick={() => handlePromiseError(handleAction('ContextMenuClick', 'pause'))}
|
onclick={() => handlePromiseError(handleAction('ContextMenuClick', 'pause'))}
|
||||||
direction="left"
|
direction="left"
|
||||||
size="20"
|
size="medium"
|
||||||
align="bottom-right"
|
align="bottom-right"
|
||||||
class="text-white dark:text-white"
|
class="text-white dark:text-white"
|
||||||
>
|
>
|
||||||
@ -532,10 +551,12 @@
|
|||||||
<!-- CONTROL BUTTONS -->
|
<!-- CONTROL BUTTONS -->
|
||||||
{#if current.previous}
|
{#if current.previous}
|
||||||
<div class="absolute top-1/2 start-0 ms-4">
|
<div class="absolute top-1/2 start-0 ms-4">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('previous_memory')}
|
shape="round"
|
||||||
|
aria-label={$t('previous_memory')}
|
||||||
icon={mdiChevronLeft}
|
icon={mdiChevronLeft}
|
||||||
color="dark"
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
onclick={handlePreviousAsset}
|
onclick={handlePreviousAsset}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -543,10 +564,12 @@
|
|||||||
|
|
||||||
{#if current.next}
|
{#if current.next}
|
||||||
<div class="absolute top-1/2 end-0 me-4">
|
<div class="absolute top-1/2 end-0 me-4">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('next_memory')}
|
shape="round"
|
||||||
|
aria-label={$t('next_memory')}
|
||||||
icon={mdiChevronRight}
|
icon={mdiChevronRight}
|
||||||
color="dark"
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
onclick={handleNextAsset}
|
onclick={handleNextAsset}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -614,10 +637,12 @@
|
|||||||
class:opacity-0={galleryInView}
|
class:opacity-0={galleryInView}
|
||||||
class:opacity-100={!galleryInView}
|
class:opacity-100={!galleryInView}
|
||||||
>
|
>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('show_gallery')}
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('show_gallery')}
|
||||||
icon={mdiChevronDown}
|
icon={mdiChevronDown}
|
||||||
color="light"
|
|
||||||
onclick={() => memoryGallery?.scrollIntoView({ behavior: 'smooth' })}
|
onclick={() => memoryGallery?.scrollIntoView({ behavior: 'smooth' })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onArchive?: OnArchive;
|
onArchive?: OnArchive;
|
||||||
@ -41,8 +42,15 @@
|
|||||||
|
|
||||||
{#if !menuItem}
|
{#if !menuItem}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('loading')}
|
||||||
|
icon={mdiTimerSand}
|
||||||
|
onclick={() => {}}
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={text} {icon} onclick={handleArchive} />
|
<IconButton shape="round" color="secondary" variant="ghost" aria-label={text} {icon} onclick={handleArchive} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import { makeSharedLinkUrl } from '$lib/utils';
|
import { makeSharedLinkUrl } from '$lib/utils';
|
||||||
import { mdiShareVariantOutline } from '@mdi/js';
|
import { mdiShareVariantOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
const { getAssets } = getAssetControlContext();
|
const { getAssets } = getAssetControlContext();
|
||||||
|
|
||||||
@ -20,4 +21,11 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CircleIconButton title={$t('share')} icon={mdiShareVariantOutline} onclick={handleClick} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('share')}
|
||||||
|
icon={mdiShareVariantOutline}
|
||||||
|
onclick={handleClick}
|
||||||
|
/>
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
import DeleteAssetDialog from '../delete-asset-dialog.svelte';
|
import DeleteAssetDialog from '../delete-asset-dialog.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onAssetDelete: OnDelete;
|
onAssetDelete: OnDelete;
|
||||||
@ -44,9 +45,23 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text={label} icon={mdiDeleteOutline} onClick={handleTrash} />
|
<MenuOption text={label} icon={mdiDeleteOutline} onClick={handleTrash} />
|
||||||
{:else if loading}
|
{:else if loading}
|
||||||
<CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('loading')}
|
||||||
|
icon={mdiTimerSand}
|
||||||
|
onclick={() => {}}
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={label} icon={mdiDeleteForeverOutline} onclick={handleTrash} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={label}
|
||||||
|
icon={mdiDeleteForeverOutline}
|
||||||
|
onclick={handleTrash}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isShowConfirmation}
|
{#if isShowConfirmation}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
filename?: string;
|
filename?: string;
|
||||||
@ -39,5 +40,12 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text={$t('download')} icon={menuItemIcon} onClick={handleDownloadFiles} />
|
<MenuOption text={$t('download')} icon={menuItemIcon} onClick={handleDownloadFiles} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={$t('download')} icon={mdiCloudDownloadOutline} onclick={handleDownloadFiles} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('download')}
|
||||||
|
icon={mdiCloudDownloadOutline}
|
||||||
|
onclick={handleDownloadFiles}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
import { mdiHeartMinusOutline, mdiHeartOutline, mdiTimerSand } from '@mdi/js';
|
import { mdiHeartMinusOutline, mdiHeartOutline, mdiTimerSand } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onFavorite?: OnFavorite;
|
onFavorite?: OnFavorite;
|
||||||
@ -67,8 +68,15 @@
|
|||||||
|
|
||||||
{#if !menuItem}
|
{#if !menuItem}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('loading')}
|
||||||
|
icon={mdiTimerSand}
|
||||||
|
onclick={() => {}}
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={text} {icon} onclick={handleFavorite} />
|
<IconButton shape="round" color="secondary" variant="ghost" aria-label={text} {icon} onclick={handleFavorite} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import { mdiLinkOff, mdiMotionPlayOutline, mdiTimerSand } from '@mdi/js';
|
import { mdiLinkOff, mdiMotionPlayOutline, mdiTimerSand } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onLink: OnLink;
|
onLink: OnLink;
|
||||||
@ -75,8 +76,15 @@
|
|||||||
|
|
||||||
{#if !menuItem}
|
{#if !menuItem}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('loading')}
|
||||||
|
icon={mdiTimerSand}
|
||||||
|
onclick={() => {}}
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={text} {icon} onclick={onClick} />
|
<IconButton shape="round" color="secondary" variant="ghost" aria-label={text} {icon} onclick={onClick} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||||
import { getAlbumInfo, removeAssetFromAlbum, type AlbumResponseDto } from '@immich/sdk';
|
import { getAlbumInfo, removeAssetFromAlbum, type AlbumResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiDeleteOutline, mdiImageRemoveOutline } from '@mdi/js';
|
import { mdiDeleteOutline, mdiImageRemoveOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
@ -60,5 +61,12 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text={$t('remove_from_album')} icon={mdiImageRemoveOutline} onClick={removeFromAlbum} />
|
<MenuOption text={$t('remove_from_album')} icon={mdiImageRemoveOutline} onClick={removeFromAlbum} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={$t('remove_from_album')} icon={mdiDeleteOutline} onclick={removeFromAlbum} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('remove_from_album')}
|
||||||
|
icon={mdiDeleteOutline}
|
||||||
|
onclick={removeFromAlbum}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sharedLink: SharedLinkResponseDto;
|
sharedLink: SharedLinkResponseDto;
|
||||||
@ -58,4 +59,11 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CircleIconButton title={$t('remove_from_shared_link')} onclick={handleRemove} icon={mdiDeleteOutline} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('remove_from_shared_link')}
|
||||||
|
onclick={handleRemove}
|
||||||
|
icon={mdiDeleteOutline}
|
||||||
|
/>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { type AssetStore, isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
import { type AssetStore, isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
||||||
import { cancelMultiselect, selectAllAssets } from '$lib/utils/asset-utils';
|
import { cancelMultiselect, selectAllAssets } from '$lib/utils/asset-utils';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiSelectAll, mdiSelectRemove } from '@mdi/js';
|
import { mdiSelectAll, mdiSelectRemove } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -34,8 +34,11 @@
|
|||||||
{$isSelectingAllAssets ? $t('unselect_all') : $t('select_all')}
|
{$isSelectingAllAssets ? $t('unselect_all') : $t('select_all')}
|
||||||
</Button>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$isSelectingAllAssets ? $t('unselect_all') : $t('select_all')}
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$isSelectingAllAssets ? $t('unselect_all') : $t('select_all')}
|
||||||
icon={$isSelectingAllAssets ? mdiSelectRemove : mdiSelectAll}
|
icon={$isSelectingAllAssets ? mdiSelectRemove : mdiSelectAll}
|
||||||
onclick={$isSelectingAllAssets ? handleCancel : handleSelectAll}
|
onclick={$isSelectingAllAssets ? handleCancel : handleSelectAll}
|
||||||
/>
|
/>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import { tagAssets } from '$lib/utils/asset-utils';
|
import { tagAssets } from '$lib/utils/asset-utils';
|
||||||
import { mdiTagMultipleOutline, mdiTimerSand } from '@mdi/js';
|
import { mdiTagMultipleOutline, mdiTimerSand } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
|
||||||
@ -39,9 +40,16 @@
|
|||||||
|
|
||||||
{#if !menuItem}
|
{#if !menuItem}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('loading')}
|
||||||
|
icon={mdiTimerSand}
|
||||||
|
onclick={() => {}}
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={text} {icon} onclick={handleOpen} />
|
<IconButton shape="round" color="secondary" variant="ghost" aria-label={text} {icon} onclick={handleOpen} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
import { mdiArrowLeft, mdiFileImagePlusOutline, mdiFolderDownloadOutline, mdiSelectAll } from '@mdi/js';
|
import { mdiArrowLeft, mdiFileImagePlusOutline, mdiFolderDownloadOutline, mdiSelectAll } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import AssetViewer from '../asset-viewer/asset-viewer.svelte';
|
import AssetViewer from '../asset-viewer/asset-viewer.svelte';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import DownloadAction from '../photos-page/actions/download-action.svelte';
|
import DownloadAction from '../photos-page/actions/download-action.svelte';
|
||||||
import RemoveFromSharedLink from '../photos-page/actions/remove-from-shared-link.svelte';
|
import RemoveFromSharedLink from '../photos-page/actions/remove-from-shared-link.svelte';
|
||||||
import AssetSelectControlBar from '../photos-page/asset-select-control-bar.svelte';
|
import AssetSelectControlBar from '../photos-page/asset-select-control-bar.svelte';
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte';
|
import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte';
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sharedLink: SharedLinkResponseDto;
|
sharedLink: SharedLinkResponseDto;
|
||||||
@ -95,7 +95,14 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
clearSelect={() => cancelMultiselect(assetInteraction)}
|
||||||
>
|
>
|
||||||
<CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('select_all')}
|
||||||
|
icon={mdiSelectAll}
|
||||||
|
onclick={handleSelectAll}
|
||||||
|
/>
|
||||||
{#if sharedLink?.allowDownload}
|
{#if sharedLink?.allowDownload}
|
||||||
<DownloadAction filename="immich-shared.zip" />
|
<DownloadAction filename="immich-shared.zip" />
|
||||||
{/if}
|
{/if}
|
||||||
@ -111,15 +118,25 @@
|
|||||||
|
|
||||||
{#snippet trailing()}
|
{#snippet trailing()}
|
||||||
{#if sharedLink?.allowUpload}
|
{#if sharedLink?.allowUpload}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('add_photos')}
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('add_photos')}
|
||||||
onclick={() => handleUploadAssets()}
|
onclick={() => handleUploadAssets()}
|
||||||
icon={mdiFileImagePlusOutline}
|
icon={mdiFileImagePlusOutline}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if sharedLink?.allowDownload}
|
{#if sharedLink?.allowDownload}
|
||||||
<CircleIconButton title={$t('download')} onclick={downloadAssets} icon={mdiFolderDownloadOutline} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('download')}
|
||||||
|
onclick={downloadAssets}
|
||||||
|
icon={mdiFolderDownloadOutline}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</ControlAppBar>
|
</ControlAppBar>
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { FormEventHandler } from 'svelte/elements';
|
import type { FormEventHandler } from 'svelte/elements';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
@ -329,7 +330,7 @@
|
|||||||
class:pointer-events-none={!selectedOption}
|
class:pointer-events-none={!selectedOption}
|
||||||
>
|
>
|
||||||
{#if selectedOption}
|
{#if selectedOption}
|
||||||
<CircleIconButton onclick={onClear} title={$t('clear_value')} icon={mdiClose} size="16" padding="2" />
|
<IconButton shape="round" color="secondary" variant="ghost" onclick={onClear} aria-label={$t('clear_value')} icon={mdiClose} size="small" />
|
||||||
{:else if !isOpen}
|
{:else if !isOpen}
|
||||||
<Icon path={mdiUnfoldMoreHorizontal} ariaHidden={true} />
|
<Icon path={mdiUnfoldMoreHorizontal} ariaHidden={true} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { contextMenuNavigation } from '$lib/actions/context-menu-navigation';
|
import { contextMenuNavigation } from '$lib/actions/context-menu-navigation';
|
||||||
import { shortcuts } from '$lib/actions/shortcut';
|
import { shortcuts } from '$lib/actions/shortcut';
|
||||||
import CircleIconButton, {
|
|
||||||
type Color,
|
|
||||||
type Padding,
|
|
||||||
} 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 { languageManager } from '$lib/managers/language-manager.svelte';
|
import { languageManager } from '$lib/managers/language-manager.svelte';
|
||||||
import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store';
|
import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store';
|
||||||
@ -14,6 +10,7 @@
|
|||||||
type Align,
|
type Align,
|
||||||
} from '$lib/utils/context-menu';
|
} from '$lib/utils/context-menu';
|
||||||
import { generateId } from '$lib/utils/generate-id';
|
import { generateId } from '$lib/utils/generate-id';
|
||||||
|
import { IconButton, type Color, type Size, type Variants } from '@immich/ui';
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
import type { HTMLAttributes } from 'svelte/elements';
|
import type { HTMLAttributes } from 'svelte/elements';
|
||||||
|
|
||||||
@ -30,8 +27,8 @@
|
|||||||
// TODO change to start vs end
|
// TODO change to start vs end
|
||||||
direction?: 'left' | 'right';
|
direction?: 'left' | 'right';
|
||||||
color?: Color;
|
color?: Color;
|
||||||
size?: string | undefined;
|
size?: Size | undefined;
|
||||||
padding?: Padding | undefined;
|
variant?: Variants | undefined;
|
||||||
/**
|
/**
|
||||||
* Additional classes to apply to the button.
|
* Additional classes to apply to the button.
|
||||||
*/
|
*/
|
||||||
@ -49,9 +46,9 @@
|
|||||||
title,
|
title,
|
||||||
align = 'top-left',
|
align = 'top-left',
|
||||||
direction = 'right',
|
direction = 'right',
|
||||||
color = 'transparent',
|
color = 'info',
|
||||||
size = undefined,
|
size = undefined,
|
||||||
padding = undefined,
|
variant = 'ghost',
|
||||||
buttonClass = undefined,
|
buttonClass = undefined,
|
||||||
hideContent = false,
|
hideContent = false,
|
||||||
children,
|
children,
|
||||||
@ -161,12 +158,13 @@
|
|||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<div bind:this={buttonContainer}>
|
<div bind:this={buttonContainer}>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
{color}
|
{color}
|
||||||
{icon}
|
{icon}
|
||||||
{padding}
|
|
||||||
{size}
|
{size}
|
||||||
{title}
|
shape="round"
|
||||||
|
{variant}
|
||||||
|
aria-label={title}
|
||||||
aria-controls={menuId}
|
aria-controls={menuId}
|
||||||
aria-expanded={isOpen}
|
aria-expanded={isOpen}
|
||||||
aria-haspopup={true}
|
aria-haspopup={true}
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
|
|
||||||
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiClose } from '@mdi/js';
|
import { mdiClose } from '@mdi/js';
|
||||||
import { onDestroy, onMount, type Snippet } from 'svelte';
|
import { onDestroy, onMount, type Snippet } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
showBackButton?: boolean;
|
showBackButton?: boolean;
|
||||||
@ -82,7 +82,16 @@
|
|||||||
>
|
>
|
||||||
<div class="flex place-items-center sm:gap-6 justify-self-start dark:text-immich-dark-fg">
|
<div class="flex place-items-center sm:gap-6 justify-self-start dark:text-immich-dark-fg">
|
||||||
{#if showBackButton}
|
{#if showBackButton}
|
||||||
<CircleIconButton title={$t('close')} onclick={handleClose} icon={backIcon} size="24" class={buttonClass} />
|
<IconButton
|
||||||
|
aria-label={$t('close')}
|
||||||
|
onclick={handleClose}
|
||||||
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
icon={backIcon}
|
||||||
|
size="large"
|
||||||
|
class={buttonClass}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{@render leading?.()}
|
{@render leading?.()}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiClose } from '@mdi/js';
|
import { mdiClose } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -36,5 +37,13 @@
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CircleIconButton onclick={onClose} icon={mdiClose} size="20" title={$t('close')} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
onclick={onClose}
|
||||||
|
icon={mdiClose}
|
||||||
|
size="medium"
|
||||||
|
aria-label={$t('close')}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||||
import AvatarEditModal from '$lib/modals/AvatarEditModal.svelte';
|
import AvatarEditModal from '$lib/modals/AvatarEditModal.svelte';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiCog, mdiLogout, mdiPencil, mdiWrench } from '@mdi/js';
|
import { mdiCog, mdiLogout, mdiPencil, mdiWrench } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
@ -33,13 +33,12 @@
|
|||||||
<div class="relative">
|
<div class="relative">
|
||||||
<UserAvatar user={$user} size="xl" />
|
<UserAvatar user={$user} size="xl" />
|
||||||
<div class="absolute bottom-0 end-0 rounded-full w-6 h-6">
|
<div class="absolute bottom-0 end-0 rounded-full w-6 h-6">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiPencil}
|
icon={mdiPencil}
|
||||||
title={$t('edit_avatar')}
|
aria-label={$t('edit_avatar')}
|
||||||
class="border"
|
size="tiny"
|
||||||
size="12"
|
shape="round"
|
||||||
padding="2"
|
|
||||||
onclick={async () => {
|
onclick={async () => {
|
||||||
onClose();
|
onClose();
|
||||||
await modalManager.show(AvatarEditModal, {});
|
await modalManager.show(AvatarEditModal, {});
|
||||||
|
@ -128,7 +128,7 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<ThemeButton padding="2" />
|
<ThemeButton />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -163,7 +163,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CastButton navBar />
|
<CastButton />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
use:clickOutside={{
|
use:clickOutside={{
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
type ComponentNotification,
|
type ComponentNotification,
|
||||||
type Notification,
|
type Notification,
|
||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiCloseCircleOutline, mdiInformationOutline, mdiWindowClose } from '@mdi/js';
|
import { mdiCloseCircleOutline, mdiInformationOutline, mdiWindowClose } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -87,12 +88,14 @@
|
|||||||
{:else if notification.type == NotificationType.Info}{$t('info')}{/if}
|
{:else if notification.type == NotificationType.Info}{$t('info')}{/if}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
icon={mdiWindowClose}
|
icon={mdiWindowClose}
|
||||||
title={$t('close')}
|
aria-label={$t('close')}
|
||||||
class="dark:text-immich-dark-gray"
|
class="dark:text-immich-dark-gray"
|
||||||
size="20"
|
size="medium"
|
||||||
padding="2"
|
|
||||||
onclick={discard}
|
onclick={discard}
|
||||||
aria-hidden={true}
|
aria-hidden={true}
|
||||||
tabindex={-1}
|
tabindex={-1}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
import { onDestroy, tick } from 'svelte';
|
import { onDestroy, tick } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import SearchHistoryBox from './search-history-box.svelte';
|
import SearchHistoryBox from './search-history-box.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
value?: string;
|
value?: string;
|
||||||
@ -271,7 +272,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="absolute inset-y-0 {showClearIcon ? 'end-14' : 'end-2'} flex items-center ps-6 transition-all">
|
<div class="absolute inset-y-0 {showClearIcon ? 'end-14' : 'end-2'} flex items-center ps-6 transition-all">
|
||||||
<CircleIconButton title={$t('show_search_options')} icon={mdiTune} onclick={onFilterClick} size="20" />
|
<IconButton
|
||||||
|
aria-label={$t('show_search_options')}
|
||||||
|
shape="round"
|
||||||
|
icon={mdiTune}
|
||||||
|
onclick={onFilterClick}
|
||||||
|
size="medium"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if isFocus}
|
{#if isFocus}
|
||||||
@ -290,11 +299,28 @@
|
|||||||
|
|
||||||
{#if showClearIcon}
|
{#if showClearIcon}
|
||||||
<div class="absolute inset-y-0 end-0 flex items-center pe-2">
|
<div class="absolute inset-y-0 end-0 flex items-center pe-2">
|
||||||
<CircleIconButton onclick={onClear} icon={mdiClose} title={$t('clear')} size="20" />
|
<IconButton
|
||||||
|
onclick={onClear}
|
||||||
|
icon={mdiClose}
|
||||||
|
aria-label={$t('clear')}
|
||||||
|
size="medium"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="absolute inset-y-0 start-0 flex items-center ps-2">
|
<div class="absolute inset-y-0 start-0 flex items-center ps-2">
|
||||||
<CircleIconButton type="submit" title={$t('search')} icon={mdiMagnify} size="20" onclick={() => {}} />
|
<IconButton
|
||||||
|
type="submit"
|
||||||
|
aria-label={$t('search')}
|
||||||
|
icon={mdiMagnify}
|
||||||
|
size="medium"
|
||||||
|
onclick={() => {}}
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { searchStore } from '$lib/stores/search.svelte';
|
import { searchStore } from '$lib/stores/search.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiClose, mdiMagnify } from '@mdi/js';
|
import { mdiClose, mdiMagnify } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
@ -132,11 +133,13 @@
|
|||||||
{savedSearchTerm}
|
{savedSearchTerm}
|
||||||
</div>
|
</div>
|
||||||
<div aria-hidden={true} class="absolute end-5 top-0 items-center justify-center py-3">
|
<div aria-hidden={true} class="absolute end-5 top-0 items-center justify-center py-3">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
icon={mdiClose}
|
icon={mdiClose}
|
||||||
title={$t('remove')}
|
aria-label={$t('remove')}
|
||||||
size="18"
|
size="medium"
|
||||||
padding="1"
|
|
||||||
tabindex={-1}
|
tabindex={-1}
|
||||||
onclick={() => handleClearSingle(savedSearchTerm)}
|
onclick={() => handleClearSingle(savedSearchTerm)}
|
||||||
/>
|
/>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { getButtonVisibility } from '$lib/utils/purchase-utils';
|
import { getButtonVisibility } from '$lib/utils/purchase-utils';
|
||||||
import { updateMyPreferences } from '@immich/sdk';
|
import { updateMyPreferences } from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiClose, mdiInformationOutline } from '@mdi/js';
|
import { mdiClose, mdiInformationOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
@ -129,13 +129,16 @@
|
|||||||
<div class="h-10 w-10">
|
<div class="h-10 w-10">
|
||||||
<ImmichLogo noText class="h-[32px]" />
|
<ImmichLogo noText class="h-[32px]" />
|
||||||
</div>
|
</div>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
icon={mdiClose}
|
icon={mdiClose}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
showMessage = false;
|
showMessage = false;
|
||||||
}}
|
}}
|
||||||
title={$t('close')}
|
aria-label={$t('close')}
|
||||||
size="18"
|
size="medium"
|
||||||
class="text-immich-dark-gray/85 dark:text-immich-gray"
|
class="text-immich-dark-gray/85 dark:text-immich-gray"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,27 +1,21 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths';
|
|
||||||
import CircleIconButton, { type Padding } from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
|
||||||
import { themeManager } from '$lib/managers/theme-manager.svelte';
|
import { themeManager } from '$lib/managers/theme-manager.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
|
import { mdiWeatherNight, mdiWhiteBalanceSunny } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
let icon = $derived(themeManager.isDark ? sunPath : moonPath);
|
let icon = $derived(themeManager.isDark ? mdiWhiteBalanceSunny : mdiWeatherNight);
|
||||||
let viewBox = $derived(themeManager.isDark ? sunViewBox : moonViewBox);
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
padding?: Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { padding = '3' }: Props = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !themeManager.theme.system}
|
{#if !themeManager.theme.system}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('toggle_theme')}
|
aria-label={$t('toggle_theme')}
|
||||||
{icon}
|
{icon}
|
||||||
{viewBox}
|
|
||||||
role="switch"
|
role="switch"
|
||||||
aria-checked={themeManager.isDark ? 'true' : 'false'}
|
aria-checked={themeManager.isDark ? 'true' : 'false'}
|
||||||
onclick={() => themeManager.toggleTheme()}
|
onclick={() => themeManager.toggleTheme()}
|
||||||
{padding}
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiArrowUpLeft, mdiChevronRight } from '@mdi/js';
|
import { mdiArrowUpLeft, mdiChevronRight } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -18,12 +19,14 @@
|
|||||||
<nav class="flex items-center py-2">
|
<nav class="flex items-center py-2">
|
||||||
{#if !isRoot}
|
{#if !isRoot}
|
||||||
<div>
|
<div>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
icon={mdiArrowUpLeft}
|
icon={mdiArrowUpLeft}
|
||||||
title={$t('to_parent')}
|
aria-label={$t('to_parent')}
|
||||||
href={getLink(pathSegments.slice(0, -1).join('/'))}
|
href={getLink(pathSegments.slice(0, -1).join('/'))}
|
||||||
class="me-2"
|
class="me-2"
|
||||||
padding="2"
|
|
||||||
onclick={() => {}}
|
onclick={() => {}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -34,12 +37,14 @@
|
|||||||
>
|
>
|
||||||
<ol class="flex gap-2 items-center">
|
<ol class="flex gap-2 items-center">
|
||||||
<li>
|
<li>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
{icon}
|
{icon}
|
||||||
href={getLink('')}
|
href={getLink('')}
|
||||||
{title}
|
aria-label={title}
|
||||||
size="1.25em"
|
size="medium"
|
||||||
padding="2"
|
|
||||||
aria-current={isRoot ? 'page' : undefined}
|
aria-current={isRoot ? 'page' : undefined}
|
||||||
onclick={() => {}}
|
onclick={() => {}}
|
||||||
/>
|
/>
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import { uploadAssetsStore } from '$lib/stores/upload';
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
||||||
import { uploadExecutionQueue } from '$lib/utils/file-uploader';
|
import { uploadExecutionQueue } from '$lib/utils/file-uploader';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiCancel, mdiCloudUploadOutline, mdiCog, mdiWindowMinimize } from '@mdi/js';
|
import { mdiCancel, mdiCloudUploadOutline, mdiCog, mdiWindowMinimize } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { quartInOut } from 'svelte/easing';
|
import { quartInOut } from 'svelte/easing';
|
||||||
import { fade, scale } from 'svelte/transition';
|
import { fade, scale } from 'svelte/transition';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import { notificationController, NotificationType } from './notification/notification';
|
import { notificationController, NotificationType } from './notification/notification';
|
||||||
import UploadAssetPreview from './upload-asset-preview.svelte';
|
import UploadAssetPreview from './upload-asset-preview.svelte';
|
||||||
|
|
||||||
@ -79,27 +79,33 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-end">
|
<div class="flex flex-col items-end">
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('toggle_settings')}
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
icon={mdiCog}
|
icon={mdiCog}
|
||||||
size="14"
|
size="small"
|
||||||
padding="1"
|
|
||||||
onclick={() => (showOptions = !showOptions)}
|
onclick={() => (showOptions = !showOptions)}
|
||||||
|
aria-label={$t('toggle_settings')}
|
||||||
/>
|
/>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('minimize')}
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('minimize')}
|
||||||
icon={mdiWindowMinimize}
|
icon={mdiWindowMinimize}
|
||||||
size="14"
|
size="small"
|
||||||
padding="1"
|
|
||||||
onclick={() => (showDetail = false)}
|
onclick={() => (showDetail = false)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{#if $isDismissible}
|
{#if $isDismissible}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('dismiss_all_errors')}
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('dismiss_all_errors')}
|
||||||
icon={mdiCancel}
|
icon={mdiCancel}
|
||||||
size="14"
|
size="small"
|
||||||
padding="1"
|
|
||||||
onclick={() => uploadAssetsStore.dismissErrors()}
|
onclick={() => uploadAssetsStore.dismissErrors()}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
import { copyToClipboard, makeSharedLinkUrl } from '$lib/utils';
|
import { copyToClipboard, makeSharedLinkUrl } from '$lib/utils';
|
||||||
import type { SharedLinkResponseDto } from '@immich/sdk';
|
import type { SharedLinkResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiContentCopy } from '@mdi/js';
|
import { mdiContentCopy } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -20,5 +21,12 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text={$t('copy_link')} icon={mdiContentCopy} onClick={handleCopy} />
|
<MenuOption text={$t('copy_link')} icon={mdiContentCopy} onClick={handleCopy} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={$t('copy_link')} icon={mdiContentCopy} onclick={handleCopy} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('copy_link')}
|
||||||
|
icon={mdiContentCopy}
|
||||||
|
onclick={handleCopy}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiDelete } from '@mdi/js';
|
import { mdiDelete } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -14,5 +15,12 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text={$t('delete_link')} icon={mdiDelete} onClick={onDelete} />
|
<MenuOption text={$t('delete_link')} icon={mdiDelete} onClick={onDelete} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={$t('delete_link')} icon={mdiDelete} onclick={onDelete} />
|
<IconButton
|
||||||
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('delete_link')}
|
||||||
|
icon={mdiDelete}
|
||||||
|
onclick={onDelete}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import type { SharedLinkResponseDto } from '@immich/sdk';
|
import type { SharedLinkResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiCircleEditOutline } from '@mdi/js';
|
import { mdiCircleEditOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -21,5 +22,12 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text={$t('edit_link')} icon={mdiCircleEditOutline} onClick={onEdit} />
|
<MenuOption text={$t('edit_link')} icon={mdiCircleEditOutline} onClick={onEdit} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={$t('edit_link')} icon={mdiCircleEditOutline} onclick={onEdit} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('edit_link')}
|
||||||
|
icon={mdiCircleEditOutline}
|
||||||
|
onclick={onEdit}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import type { SessionResponseDto } from '@immich/sdk';
|
import type { SessionResponseDto } from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiAndroid,
|
mdiAndroid,
|
||||||
mdiApple,
|
mdiApple,
|
||||||
@ -74,11 +75,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if !device.current && onDelete}
|
{#if !device.current && onDelete}
|
||||||
<div>
|
<div>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="primary"
|
color="danger"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
icon={mdiTrashCanOutline}
|
icon={mdiTrashCanOutline}
|
||||||
title={$t('log_out')}
|
aria-label={$t('log_out')}
|
||||||
size="16"
|
size="small"
|
||||||
onclick={onDelete}
|
onclick={onDelete}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,12 +12,11 @@
|
|||||||
type PartnerResponseDto,
|
type PartnerResponseDto,
|
||||||
type UserResponseDto,
|
type UserResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiCheck, mdiClose } from '@mdi/js';
|
import { mdiCheck, mdiClose } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
|
||||||
import Icon from '../elements/icon.svelte';
|
import Icon from '../elements/icon.svelte';
|
||||||
|
|
||||||
interface PartnerSharing {
|
interface PartnerSharing {
|
||||||
@ -144,11 +143,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if partner.sharedByMe}
|
{#if partner.sharedByMe}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
onclick={() => handleRemovePartner(partner.user)}
|
onclick={() => handleRemovePartner(partner.user)}
|
||||||
icon={mdiClose}
|
icon={mdiClose}
|
||||||
size="16"
|
size="small"
|
||||||
title={$t('stop_sharing_photos_with_user')}
|
aria-label={$t('stop_sharing_photos_with_user')}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
updateApiKey,
|
updateApiKey,
|
||||||
type ApiKeyResponseDto,
|
type ApiKeyResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
|
import { mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
@ -127,18 +127,20 @@
|
|||||||
>{new Date(key.createdAt).toLocaleDateString($locale, dateFormats.settings)}
|
>{new Date(key.createdAt).toLocaleDateString($locale, dateFormats.settings)}
|
||||||
</td>
|
</td>
|
||||||
<td class="flex flex-row flex-wrap justify-center gap-x-2 gap-y-1 w-1/3">
|
<td class="flex flex-row flex-wrap justify-center gap-x-2 gap-y-1 w-1/3">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiPencilOutline}
|
icon={mdiPencilOutline}
|
||||||
title={$t('edit_key')}
|
aria-label={$t('edit_key')}
|
||||||
size="16"
|
size="small"
|
||||||
onclick={() => handleUpdate(key)}
|
onclick={() => handleUpdate(key)}
|
||||||
/>
|
/>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={mdiTrashCanOutline}
|
icon={mdiTrashCanOutline}
|
||||||
title={$t('delete_key')}
|
aria-label={$t('delete_key')}
|
||||||
size="16"
|
size="small"
|
||||||
onclick={() => handleDelete(key)}
|
onclick={() => handleDelete(key)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
|
@ -7,12 +7,11 @@
|
|||||||
import { getPeopleThumbnailUrl } from '$lib/utils';
|
import { getPeopleThumbnailUrl } from '$lib/utils';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { mergePerson, type PersonResponseDto } from '@immich/sdk';
|
import { mergePerson, type PersonResponseDto } from '@immich/sdk';
|
||||||
import { Button, Modal, ModalBody, ModalFooter } from '@immich/ui';
|
import { Button, IconButton, Modal, ModalBody, ModalFooter } from '@immich/ui';
|
||||||
import { mdiArrowLeft, mdiMerge } from '@mdi/js';
|
import { mdiArrowLeft, mdiMerge } from '@mdi/js';
|
||||||
import { onMount, tick } from 'svelte';
|
import { onMount, tick } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import ImageThumbnail from '../components/assets/thumbnail/image-thumbnail.svelte';
|
import ImageThumbnail from '../components/assets/thumbnail/image-thumbnail.svelte';
|
||||||
import CircleIconButton from '../components/elements/buttons/circle-icon-button.svelte';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
personToMerge: PersonResponseDto;
|
personToMerge: PersonResponseDto;
|
||||||
@ -75,8 +74,11 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-0.5 flex md:mx-2">
|
<div class="mx-0.5 flex md:mx-2">
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('swap_merge_direction')}
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('swap_merge_direction')}
|
||||||
icon={mdiMerge}
|
icon={mdiMerge}
|
||||||
onclick={() => ([personToMerge, personToBeMergedInto] = [personToBeMergedInto, personToMerge])}
|
onclick={() => ([personToMerge, personToBeMergedInto] = [personToBeMergedInto, personToMerge])}
|
||||||
/>
|
/>
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
updateAlbumInfo,
|
updateAlbumInfo,
|
||||||
type AlbumUserAddDto,
|
type AlbumUserAddDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiArrowLeft,
|
mdiArrowLeft,
|
||||||
mdiCogOutline,
|
mdiCogOutline,
|
||||||
@ -492,10 +492,11 @@
|
|||||||
<div class="my-3 flex gap-x-1">
|
<div class="my-3 flex gap-x-1">
|
||||||
<!-- link -->
|
<!-- link -->
|
||||||
{#if album.hasSharedLink && isOwned}
|
{#if album.hasSharedLink && isOwned}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('create_link_to_share')}
|
aria-label={$t('create_link_to_share')}
|
||||||
color="gray"
|
color="secondary"
|
||||||
size="20"
|
size="medium"
|
||||||
|
shape="round"
|
||||||
icon={mdiLink}
|
icon={mdiLink}
|
||||||
onclick={handleShareLink}
|
onclick={handleShareLink}
|
||||||
/>
|
/>
|
||||||
@ -515,22 +516,24 @@
|
|||||||
|
|
||||||
<!-- display ellipsis if there are readonly users too -->
|
<!-- display ellipsis if there are readonly users too -->
|
||||||
{#if albumHasViewers}
|
{#if albumHasViewers}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('view_all_users')}
|
shape="round"
|
||||||
color="gray"
|
aria-label={$t('view_all_users')}
|
||||||
size="20"
|
color="secondary"
|
||||||
|
size="medium"
|
||||||
icon={mdiDotsVertical}
|
icon={mdiDotsVertical}
|
||||||
onclick={handleEditUsers}
|
onclick={handleEditUsers}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isOwned}
|
{#if isOwned}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
color="gray"
|
shape="round"
|
||||||
size="20"
|
color="secondary"
|
||||||
|
size="medium"
|
||||||
icon={mdiPlus}
|
icon={mdiPlus}
|
||||||
onclick={handleShare}
|
onclick={handleShare}
|
||||||
title={$t('add_more_users')}
|
aria-label={$t('add_more_users')}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
@ -627,11 +630,14 @@
|
|||||||
{#if viewMode === AlbumPageViewMode.VIEW}
|
{#if viewMode === AlbumPageViewMode.VIEW}
|
||||||
<ControlAppBar showBackButton backIcon={mdiArrowLeft} onClose={() => goto(backUrl)}>
|
<ControlAppBar showBackButton backIcon={mdiArrowLeft} onClose={() => goto(backUrl)}>
|
||||||
{#snippet trailing()}
|
{#snippet trailing()}
|
||||||
<CastButton whiteHover />
|
<CastButton />
|
||||||
|
|
||||||
{#if isEditor}
|
{#if isEditor}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
title={$t('add_photos')}
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('add_photos')}
|
||||||
onclick={async () => {
|
onclick={async () => {
|
||||||
assetStore.suspendTransitions = true;
|
assetStore.suspendTransitions = true;
|
||||||
viewMode = AlbumPageViewMode.SELECT_ASSETS;
|
viewMode = AlbumPageViewMode.SELECT_ASSETS;
|
||||||
@ -646,18 +652,44 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isOwned}
|
{#if isOwned}
|
||||||
<CircleIconButton title={$t('share')} onclick={handleShare} icon={mdiShareVariantOutline} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('share')}
|
||||||
|
onclick={handleShare}
|
||||||
|
icon={mdiShareVariantOutline}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<AlbumMap {album} />
|
<AlbumMap {album} />
|
||||||
|
|
||||||
{#if album.assetCount > 0}
|
{#if album.assetCount > 0}
|
||||||
<CircleIconButton title={$t('slideshow')} onclick={handleStartSlideshow} icon={mdiPresentationPlay} />
|
<IconButton
|
||||||
<CircleIconButton title={$t('download')} onclick={handleDownloadAlbum} icon={mdiFolderDownloadOutline} />
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('slideshow')}
|
||||||
|
onclick={handleStartSlideshow}
|
||||||
|
icon={mdiPresentationPlay}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
aria-label={$t('download')}
|
||||||
|
onclick={handleDownloadAlbum}
|
||||||
|
icon={mdiFolderDownloadOutline}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isOwned}
|
{#if isOwned}
|
||||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('album_options')} offset={{ x: 175, y: 25 }}>
|
<ButtonContextMenu
|
||||||
|
icon={mdiDotsVertical}
|
||||||
|
title={$t('album_options')}
|
||||||
|
color="secondary"
|
||||||
|
offset={{ x: 175, y: 25 }}
|
||||||
|
>
|
||||||
{#if album.assetCount > 0}
|
{#if album.assetCount > 0}
|
||||||
<MenuOption
|
<MenuOption
|
||||||
icon={mdiImageOutline}
|
icon={mdiImageOutline}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||||
import { buildTree, normalizeTreePath } from '$lib/utils/tree-utils';
|
import { buildTree, normalizeTreePath } from '$lib/utils/tree-utils';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
|
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -134,7 +135,14 @@
|
|||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
clearSelect={() => cancelMultiselect(assetInteraction)}
|
||||||
>
|
>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAllAssets} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('select_all')}
|
||||||
|
icon={mdiSelectAll}
|
||||||
|
onclick={handleSelectAllAssets}
|
||||||
|
/>
|
||||||
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
||||||
<AddToAlbum onAddToAlbum={() => cancelMultiselect(assetInteraction)} />
|
<AddToAlbum onAddToAlbum={() => cancelMultiselect(assetInteraction)} />
|
||||||
<AddToAlbum onAddToAlbum={() => cancelMultiselect(assetInteraction)} shared />
|
<AddToAlbum onAddToAlbum={() => cancelMultiselect(assetInteraction)} shared />
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
searchSmart,
|
searchSmart,
|
||||||
type SmartSearchDto,
|
type SmartSearchDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiArrowLeft, mdiDotsVertical, mdiImageOffOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
|
import { mdiArrowLeft, mdiDotsVertical, mdiImageOffOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@ -268,7 +269,14 @@
|
|||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
clearSelect={() => cancelMultiselect(assetInteraction)}
|
||||||
>
|
>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('select_all')}
|
||||||
|
icon={mdiSelectAll}
|
||||||
|
onclick={handleSelectAll}
|
||||||
|
/>
|
||||||
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
||||||
<AddToAlbum {onAddToAlbum} />
|
<AddToAlbum {onAddToAlbum} />
|
||||||
<AddToAlbum shared {onAddToAlbum} />
|
<AddToAlbum shared {onAddToAlbum} />
|
||||||
@ -400,7 +408,14 @@
|
|||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
clearSelect={() => cancelMultiselect(assetInteraction)}
|
||||||
>
|
>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} />
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
aria-label={$t('select_all')}
|
||||||
|
icon={mdiSelectAll}
|
||||||
|
onclick={handleSelectAll}
|
||||||
|
/>
|
||||||
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
||||||
<AddToAlbum {onAddToAlbum} />
|
<AddToAlbum {onAddToAlbum} />
|
||||||
<AddToAlbum shared {onAddToAlbum} />
|
<AddToAlbum shared {onAddToAlbum} />
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import UserSettingsList from '$lib/components/user-settings-page/user-settings-list.svelte';
|
import UserSettingsList from '$lib/components/user-settings-page/user-settings-list.svelte';
|
||||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||||
import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte';
|
import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte';
|
||||||
import { Container } from '@immich/ui';
|
import { Container, IconButton } from '@immich/ui';
|
||||||
import { mdiKeyboard } from '@mdi/js';
|
import { mdiKeyboard } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
@ -17,9 +17,12 @@
|
|||||||
|
|
||||||
<UserPageLayout title={data.meta.title}>
|
<UserPageLayout title={data.meta.title}>
|
||||||
{#snippet buttons()}
|
{#snippet buttons()}
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
icon={mdiKeyboard}
|
icon={mdiKeyboard}
|
||||||
title={$t('show_keyboard_shortcuts')}
|
aria-label={$t('show_keyboard_shortcuts')}
|
||||||
onclick={() => modalManager.show(ShortcutsModal, {})}
|
onclick={() => modalManager.show(ShortcutsModal, {})}
|
||||||
/>
|
/>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
@ -193,11 +193,13 @@
|
|||||||
<div class="text-sm dark:text-white">
|
<div class="text-sm dark:text-white">
|
||||||
<p>{$t('duplicates_description')}</p>
|
<p>{$t('duplicates_description')}</p>
|
||||||
</div>
|
</div>
|
||||||
<CircleIconButton
|
<IconButton
|
||||||
|
shape="round"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
icon={mdiInformationOutline}
|
icon={mdiInformationOutline}
|
||||||
title={$t('deduplication_info')}
|
aria-label={$t('deduplication_info')}
|
||||||
size="16"
|
size="small"
|
||||||
padding="2"
|
|
||||||
onclick={() => modalManager.show(DuplicatesInformationModal, {})}
|
onclick={() => modalManager.show(DuplicatesInformationModal, {})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -314,9 +314,10 @@
|
|||||||
align="top-right"
|
align="top-right"
|
||||||
direction="left"
|
direction="left"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="16"
|
size="medium"
|
||||||
icon={mdiDotsVertical}
|
icon={mdiDotsVertical}
|
||||||
title={$t('library_options')}
|
title={$t('library_options')}
|
||||||
|
variant="filled"
|
||||||
>
|
>
|
||||||
<MenuOption onClick={() => onScanClicked(library)} text={$t('scan_library')} />
|
<MenuOption onClick={() => onScanClicked(library)} text={$t('scan_library')} />
|
||||||
<hr />
|
<hr />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user