refactor(web): material icons (#4636)

This commit is contained in:
Jason Rasmussen 2023-10-25 09:48:25 -04:00 committed by GitHub
parent d5e19e45cd
commit 2ad389f64e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
89 changed files with 557 additions and 534 deletions

View file

@ -186,7 +186,7 @@ export default {
},
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: ['/node_modules/(?!svelte-material-icons).*/', '\\.pnp\\.[^\\/]+$'],
transformIgnorePatterns: ['\\.pnp\\.[^\\/]+$'],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,

26
web/package-lock.json generated
View file

@ -9,6 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@egjs/svelte-view360": "^4.0.0-beta.7",
"@mdi/js": "^7.3.67",
"@zoom-image/svelte": "^0.1.8",
"axios": "^0.27.2",
"buffer": "^6.0.3",
@ -23,7 +24,6 @@
"socket.io-client": "^4.6.1",
"svelte-loading-spinners": "^0.3.4",
"svelte-local-storage-store": "^0.5.0",
"svelte-material-icons": "^3.0.5",
"thumbhash": "^0.1.1"
},
"devDependencies": {
@ -3197,6 +3197,11 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@mdi/js": {
"version": "7.3.67",
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.3.67.tgz",
"integrity": "sha512-MnRjknFqpTC6FifhGHjZ0+QYq2bAkZFQqIj8JA2AdPZbBxUvr8QSgB2yPAJ8/ob/XkR41xlg5majDR3c1JP1hw=="
},
"node_modules/@namnode/store": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@namnode/store/-/store-0.1.0.tgz",
@ -11418,14 +11423,6 @@
"svelte": "^3.48.0 || ^4.0.0"
}
},
"node_modules/svelte-material-icons": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/svelte-material-icons/-/svelte-material-icons-3.0.5.tgz",
"integrity": "sha512-UbhAa+Btd5y6e6DMljVccP+cbJ8lvesltMippiCOvfIUtYe2TsQqM+P6osfrVsZHV47b1tY6AmqCuSpMKnwMOQ==",
"peerDependencies": {
"svelte": "^3.0.0 || ^4.0.0"
}
},
"node_modules/svelte-preprocess": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz",
@ -14495,6 +14492,11 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@mdi/js": {
"version": "7.3.67",
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.3.67.tgz",
"integrity": "sha512-MnRjknFqpTC6FifhGHjZ0+QYq2bAkZFQqIj8JA2AdPZbBxUvr8QSgB2yPAJ8/ob/XkR41xlg5majDR3c1JP1hw=="
},
"@namnode/store": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@namnode/store/-/store-0.1.0.tgz",
@ -20512,12 +20514,6 @@
"integrity": "sha512-SEDrpapeia6fUqta+r1NvSLlJYPkZ4pBcl15EYIOSPNzy6vhpoXu8cnzUDmZxsWl7fZGAHxrVH9UyZCbyO4W+g==",
"requires": {}
},
"svelte-material-icons": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/svelte-material-icons/-/svelte-material-icons-3.0.5.tgz",
"integrity": "sha512-UbhAa+Btd5y6e6DMljVccP+cbJ8lvesltMippiCOvfIUtYe2TsQqM+P6osfrVsZHV47b1tY6AmqCuSpMKnwMOQ==",
"requires": {}
},
"svelte-preprocess": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz",

View file

@ -62,6 +62,7 @@
"type": "module",
"dependencies": {
"@egjs/svelte-view360": "^4.0.0-beta.7",
"@mdi/js": "^7.3.67",
"@zoom-image/svelte": "^0.1.8",
"axios": "^0.27.2",
"buffer": "^6.0.3",
@ -76,7 +77,6 @@
"socket.io-client": "^4.6.1",
"svelte-loading-spinners": "^0.3.4",
"svelte-local-storage-store": "^0.5.0",
"svelte-material-icons": "^3.0.5",
"thumbhash": "^0.1.1"
}
}

View file

@ -1,25 +1,27 @@
<script lang="ts">
import type Icon from 'svelte-material-icons/AbTesting.svelte';
import SelectionSearch from 'svelte-material-icons/SelectionSearch.svelte';
import Play from 'svelte-material-icons/Play.svelte';
import Pause from 'svelte-material-icons/Pause.svelte';
import FastForward from 'svelte-material-icons/FastForward.svelte';
import AllInclusive from 'svelte-material-icons/AllInclusive.svelte';
import Close from 'svelte-material-icons/Close.svelte';
import AlertCircle from 'svelte-material-icons/AlertCircle.svelte';
import { locale } from '$lib/stores/preferences.store';
import { createEventDispatcher } from 'svelte';
import { JobCommand, JobCommandDto, JobCountsDto, QueueStatusDto } from '@api';
import Badge from '$lib/components/elements/badge.svelte';
import JobTileButton from './job-tile-button.svelte';
import JobTileStatus from './job-tile-status.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import {
mdiAlertCircle,
mdiAllInclusive,
mdiClose,
mdiFastForward,
mdiPause,
mdiPlay,
mdiSelectionSearch,
} from '@mdi/js';
export let title: string;
export let subtitle: string | undefined = undefined;
export let jobCounts: JobCountsDto;
export let queueStatus: QueueStatusDto;
export let allowForceCommand = true;
export let icon: typeof Icon;
export let icon: string;
export let disabled = false;
export let allText: string;
@ -47,7 +49,7 @@
<div class="flex flex-col gap-2 p-5 sm:p-7 md:p-9">
<div class="flex items-center gap-4 text-xl font-semibold text-immich-primary dark:text-immich-dark-primary">
<span class="flex items-center gap-2">
<svelte:component this={icon} size="1.25em" class="hidden shrink-0 sm:block" />
<Icon path={icon} size="1.25em" class="hidden shrink-0 sm:block" />
{title.toUpperCase()}
</span>
<div class="flex gap-2">
@ -102,12 +104,12 @@
color="light-gray"
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
>
<AlertCircle size="36" /> DISABLED
<Icon path={mdiAlertCircle} size="36" /> DISABLED
</JobTileButton>
{:else if !isIdle}
{#if waitingCount > 0}
<JobTileButton color="gray" on:click={() => dispatch('command', { command: JobCommand.Empty, force: false })}>
<Close size="24" /> CLEAR
<Icon path={mdiClose} size="24" /> CLEAR
</JobTileButton>
{/if}
{#if queueStatus.isPaused}
@ -117,26 +119,26 @@
on:click={() => dispatch('command', { command: JobCommand.Resume, force: false })}
>
<!-- size property is not reactive, so have to use width and height -->
<FastForward width={size} height={size} /> RESUME
<Icon path={mdiFastForward} {size} /> RESUME
</JobTileButton>
{:else}
<JobTileButton
color="light-gray"
on:click={() => dispatch('command', { command: JobCommand.Pause, force: false })}
>
<Pause size="24" /> PAUSE
<Icon path={mdiPause} size="24" /> PAUSE
</JobTileButton>
{/if}
{:else if allowForceCommand}
<JobTileButton color="gray" on:click={() => dispatch('command', { command: JobCommand.Start, force: true })}>
<AllInclusive size="24" />
<Icon path={mdiAllInclusive} size="24" />
{allText}
</JobTileButton>
<JobTileButton
color="light-gray"
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
>
<SelectionSearch size="24" />
<Icon path={mdiSelectionSearch} size="24" />
{missingText}
</JobTileButton>
{:else}
@ -144,7 +146,7 @@
color="light-gray"
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
>
<Play size="48" /> START
<Icon path={mdiPlay} size="48" /> START
</JobTileButton>
{/if}
</div>

View file

@ -7,16 +7,17 @@
import { handleError } from '$lib/utils/handle-error';
import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api';
import type { ComponentType } from 'svelte';
import type Icon from 'svelte-material-icons/DotsVertical.svelte';
import FaceRecognition from 'svelte-material-icons/FaceRecognition.svelte';
import FileJpgBox from 'svelte-material-icons/FileJpgBox.svelte';
import FileXmlBox from 'svelte-material-icons/FileXmlBox.svelte';
import LibraryShelves from 'svelte-material-icons/LibraryShelves.svelte';
import FolderMove from 'svelte-material-icons/FolderMove.svelte';
import Table from 'svelte-material-icons/Table.svelte';
import TagMultiple from 'svelte-material-icons/TagMultiple.svelte';
import VectorCircle from 'svelte-material-icons/VectorCircle.svelte';
import Video from 'svelte-material-icons/Video.svelte';
import {
mdiFaceRecognition,
mdiFileJpgBox,
mdiFileXmlBox,
mdiFolderMove,
mdiLibraryShelves,
mdiTable,
mdiTagMultiple,
mdiVectorCircle,
mdiVideo,
} from '@mdi/js';
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
import JobTile from './job-tile.svelte';
import StorageMigrationDescription from './storage-migration-description.svelte';
@ -29,7 +30,7 @@
allText?: string;
missingText?: string;
disabled?: boolean;
icon: typeof Icon;
icon: string;
allowForceCommand?: boolean;
component?: ComponentType;
handleCommand?: (jobId: JobName, jobCommand: JobCommandDto) => Promise<void>;
@ -53,17 +54,17 @@
$: jobDetails = <Partial<Record<JobName, JobDetails>>>{
[JobName.ThumbnailGeneration]: {
icon: FileJpgBox,
icon: mdiFileJpgBox,
title: api.getJobName(JobName.ThumbnailGeneration),
subtitle: 'Regenerate JPEG and WebP thumbnails',
},
[JobName.MetadataExtraction]: {
icon: Table,
icon: mdiTable,
title: api.getJobName(JobName.MetadataExtraction),
subtitle: 'Extract metadata information i.e. GPS, resolution...etc',
},
[JobName.Library]: {
icon: LibraryShelves,
icon: mdiLibraryShelves,
title: api.getJobName(JobName.Library),
subtitle: 'Perform library tasks',
allText: 'ALL',
@ -71,44 +72,44 @@
},
[JobName.Sidecar]: {
title: api.getJobName(JobName.Sidecar),
icon: FileXmlBox,
icon: mdiFileXmlBox,
subtitle: 'Discover or synchronize sidecar metadata from the filesystem',
allText: 'SYNC',
missingText: 'DISCOVER',
disabled: !$featureFlags.sidecar,
},
[JobName.ObjectTagging]: {
icon: TagMultiple,
icon: mdiTagMultiple,
title: api.getJobName(JobName.ObjectTagging),
subtitle: 'Run machine learning to tag objects\nNote that some assets may not have any objects detected',
disabled: !$featureFlags.tagImage,
},
[JobName.ClipEncoding]: {
icon: VectorCircle,
icon: mdiVectorCircle,
title: api.getJobName(JobName.ClipEncoding),
subtitle: 'Run machine learning to generate clip embeddings',
disabled: !$featureFlags.clipEncode,
},
[JobName.RecognizeFaces]: {
icon: FaceRecognition,
icon: mdiFaceRecognition,
title: api.getJobName(JobName.RecognizeFaces),
subtitle: 'Run machine learning to recognize faces',
handleCommand: handleFaceCommand,
disabled: !$featureFlags.facialRecognition,
},
[JobName.VideoConversion]: {
icon: Video,
icon: mdiVideo,
title: api.getJobName(JobName.VideoConversion),
subtitle: 'Transcode videos not in the desired format',
},
[JobName.StorageTemplateMigration]: {
icon: FolderMove,
icon: mdiFolderMove,
title: api.getJobName(JobName.StorageTemplateMigration),
allowForceCommand: false,
component: StorageMigrationDescription,
},
[JobName.Migration]: {
icon: FolderMove,
icon: mdiFolderMove,
title: api.getJobName(JobName.Migration),
subtitle: 'Migrate thumbnails for assets and faces to the latest folder structure',
allowForceCommand: false,

View file

@ -1,11 +1,10 @@
<script lang="ts">
import { locale } from '$lib/stores/preferences.store';
import type { ServerStatsResponseDto } from '@api';
import CameraIris from 'svelte-material-icons/CameraIris.svelte';
import Memory from 'svelte-material-icons/Memory.svelte';
import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
import { asByteUnitString, getBytesWithUnit } from '../../../utils/byte-units';
import { asByteUnitString, getBytesWithUnit } from '$lib/utils/byte-units';
import StatsCard from './stats-card.svelte';
import { mdiCameraIris, mdiMemory, mdiPlayCircle } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let stats: ServerStatsResponseDto = {
photos: 0,
@ -30,15 +29,15 @@
<p class="text-sm dark:text-immich-dark-fg">TOTAL USAGE</p>
<div class="mt-5 hidden justify-between lg:flex">
<StatsCard logo={CameraIris} title="PHOTOS" value={stats.photos} />
<StatsCard logo={PlayCircle} title="VIDEOS" value={stats.videos} />
<StatsCard logo={Memory} title="STORAGE" value={statsUsage} unit={statsUsageUnit} />
<StatsCard icon={mdiCameraIris} title="PHOTOS" value={stats.photos} />
<StatsCard icon={mdiPlayCircle} title="VIDEOS" value={stats.videos} />
<StatsCard icon={mdiMemory} title="STORAGE" value={statsUsage} unit={statsUsageUnit} />
</div>
<div class="mt-5 flex lg:hidden">
<div class="flex flex-col justify-between rounded-3xl bg-immich-gray p-5 dark:bg-immich-dark-gray">
<div class="flex flex-wrap gap-x-12">
<div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
<CameraIris size="25" />
<Icon path={mdiCameraIris} size="25" />
<p>PHOTOS</p>
</div>
@ -50,7 +49,7 @@
</div>
<div class="flex flex-wrap gap-x-12">
<div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
<PlayCircle size="25" />
<Icon path={mdiPlayCircle} size="25" />
<p>VIDEOS</p>
</div>
@ -62,7 +61,7 @@
</div>
<div class="flex flex-wrap gap-x-7">
<div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
<Memory size="25" />
<Icon path={mdiMemory} size="25" />
<p>STORAGE</p>
</div>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import type Icon from 'svelte-material-icons/AbTesting.svelte';
import Icon from '$lib/components/elements/icon.svelte';
export let logo: typeof Icon;
export let icon: string;
export let title: string;
export let value: number;
export let unit: string | undefined = undefined;
@ -17,7 +17,7 @@
<div class="flex h-[140px] w-[250px] flex-col justify-between rounded-3xl bg-immich-gray p-5 dark:bg-immich-dark-gray">
<div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
<svelte:component this={logo} size="40" />
<Icon path={icon} size="40" />
<p>{title}</p>
</div>

View file

@ -17,10 +17,11 @@
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
import SettingSelect from '../setting-select.svelte';
import SettingSwitch from '../setting-switch.svelte';
import HelpCircleOutline from 'svelte-material-icons/HelpCircleOutline.svelte';
import { isEqual } from 'lodash-es';
import { fade } from 'svelte/transition';
import SettingAccordion from '../setting-accordion.svelte';
import { mdiHelpCircleOutline } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let ffmpegConfig: SystemConfigFFmpegDto; // this is the config that is being edited
export let disabled = false;
@ -93,7 +94,7 @@
<form autocomplete="off" on:submit|preventDefault>
<div class="ml-4 mt-4 flex flex-col gap-4">
<p class="text-sm dark:text-immich-dark-fg">
<HelpCircleOutline class="inline" size="15" />
<Icon path={mdiHelpCircleOutline} class="inline" size="15" />
To learn more about the terminology used here, refer to FFmpeg documentation for
<a href="https://trac.ffmpeg.org/wiki/Encode/H.264" class="underline" target="_blank" rel="noreferrer"
>H.264 codec</a

View file

@ -3,10 +3,11 @@
import { locale } from '$lib/stores/preferences.store';
import { AlbumResponseDto, api, ThumbnailFormat, UserResponseDto } from '@api';
import { createEventDispatcher, onMount } from 'svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import IconButton from '../elements/buttons/icon-button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { OnClick, OnShowContextMenu } from './album-card';
import { getContextMenuPosition } from '../../utils/context-menu';
import { mdiDotsVertical } from '@mdi/js';
export let album: AlbumResponseDto;
export let isSharingView = false;
@ -75,7 +76,7 @@
data-testid="context-button-parent"
>
<IconButton color="transparent-primary">
<DotsVertical size="20" class="icon-white-drop-shadow" color="white" />
<Icon path={mdiDotsVertical} size="20" class="icon-white-drop-shadow text-white" />
</IconButton>
</div>
{/if}

View file

@ -7,8 +7,6 @@
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
import { TimeBucketSize, type AlbumResponseDto, type SharedLinkResponseDto } from '@api';
import { onDestroy, onMount } from 'svelte';
import FileImagePlusOutline from 'svelte-material-icons/FileImagePlusOutline.svelte';
import FolderDownloadOutline from 'svelte-material-icons/FolderDownloadOutline.svelte';
import { dateFormats } from '../../constants';
import { createAssetInteractionStore } from '../../stores/asset-interaction.store';
import { AssetStore } from '../../stores/assets.store';
@ -21,6 +19,7 @@
import ImmichLogo from '../shared-components/immich-logo.svelte';
import ThemeButton from '../shared-components/theme-button.svelte';
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
import { mdiFileImagePlusOutline, mdiFolderDownloadOutline } from '@mdi/js';
export let sharedLink: SharedLinkResponseDto;
@ -122,12 +121,12 @@
<CircleIconButton
title="Add Photos"
on:click={() => openFileUploadDialog(album.id)}
logo={FileImagePlusOutline}
icon={mdiFileImagePlusOutline}
/>
{/if}
{#if album.assetCount > 0 && sharedLink.allowDownload}
<CircleIconButton title="Download" on:click={() => downloadAlbum()} logo={FolderDownloadOutline} />
<CircleIconButton title="Download" on:click={() => downloadAlbum()} icon={mdiFolderDownloadOutline} />
{/if}
<ThemeButton />

View file

@ -3,7 +3,6 @@
import { AlbumResponseDto, api, UserResponseDto } from '@api';
import BaseModal from '../shared-components/base-modal.svelte';
import UserAvatar from '../shared-components/user-avatar.svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
@ -11,6 +10,7 @@
import { handleError } from '../../utils/handle-error';
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
import { getContextMenuPosition } from '../../utils/context-menu';
import { mdiDotsVertical } from '@mdi/js';
export let album: AlbumResponseDto;
@ -99,7 +99,7 @@
<div>
<CircleIconButton
on:click={(event) => showContextMenu(event, user)}
logo={DotsVertical}
icon={mdiDotsVertical}
backgroundColor="transparent"
hoverColor="#e2e7e9"
size="20"

View file

@ -3,12 +3,12 @@
import { AlbumResponseDto, api, SharedLinkResponseDto, UserResponseDto } from '@api';
import BaseModal from '../shared-components/base-modal.svelte';
import UserAvatar from '../shared-components/user-avatar.svelte';
import Link from 'svelte-material-icons/Link.svelte';
import ShareCircle from 'svelte-material-icons/ShareCircle.svelte';
import { goto } from '$app/navigation';
import ImmichLogo from '../shared-components/immich-logo.svelte';
import Button from '../elements/buttons/button.svelte';
import { AppRoute } from '$lib/constants';
import { mdiLink, mdiShareCircle } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let album: AlbumResponseDto;
let users: UserResponseDto[] = [];
@ -128,7 +128,7 @@
class="flex flex-col place-content-center place-items-center gap-2 hover:cursor-pointer"
on:click={() => dispatch('share')}
>
<Link size={24} />
<Icon path={mdiLink} size={24} />
<p class="text-sm">Create link</p>
</button>
@ -137,7 +137,7 @@
class="flex flex-col place-content-center place-items-center gap-2 hover:cursor-pointer"
on:click={() => goto(AppRoute.SHARED_LINKS)}
>
<ShareCircle size={24} />
<Icon path={mdiShareCircle} size={24} />
<p class="text-sm">View links</p>
</button>
{/if}

View file

@ -1,26 +1,28 @@
<script lang="ts">
import { page } from '$app/stores';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { photoZoomState } from '$lib/stores/zoom-image.store';
import { clickOutside } from '$lib/utils/click-outside';
import { getContextMenuPosition } from '$lib/utils/context-menu';
import { AssetJobName, AssetResponseDto, AssetTypeEnum, api } from '@api';
import {
mdiAlertOutline,
mdiArrowLeft,
mdiCloudDownloadOutline,
mdiContentCopy,
mdiDeleteOutline,
mdiDotsVertical,
mdiHeart,
mdiHeartOutline,
mdiInformationOutline,
mdiMagnifyMinusOutline,
mdiMagnifyPlusOutline,
mdiMotionPauseOutline,
mdiMoviePlayOutline,
} from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
import CloudDownloadOutline from 'svelte-material-icons/CloudDownloadOutline.svelte';
import AlertOutline from 'svelte-material-icons/AlertOutline.svelte';
import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import Heart from 'svelte-material-icons/Heart.svelte';
import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
import MagnifyMinusOutline from 'svelte-material-icons/MagnifyMinusOutline.svelte';
import MagnifyPlusOutline from 'svelte-material-icons/MagnifyPlusOutline.svelte';
import MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte';
import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
import { getContextMenuPosition } from '$lib/utils/context-menu';
export let asset: AssetResponseDto;
export let showCopyButton: boolean;
@ -74,13 +76,13 @@
class="z-[1001] flex h-16 place-items-center justify-between bg-gradient-to-b from-black/40 px-3 transition-transform duration-200"
>
<div class="text-white">
<CircleIconButton isOpacity={true} logo={ArrowLeft} on:click={() => dispatch('goBack')} />
<CircleIconButton isOpacity={true} icon={mdiArrowLeft} on:click={() => dispatch('goBack')} />
</div>
<div class="flex w-[calc(100%-3rem)] justify-end gap-2 overflow-hidden text-white">
{#if asset.isOffline}
<CircleIconButton
isOpacity={true}
logo={AlertOutline}
icon={mdiAlertOutline}
on:click={() => dispatch('showDetail')}
title="Asset Offline"
/>
@ -89,14 +91,14 @@
{#if isMotionPhotoPlaying}
<CircleIconButton
isOpacity={true}
logo={MotionPauseOutline}
icon={mdiMotionPauseOutline}
title="Stop Motion Photo"
on:click={() => dispatch('stopMotionPhoto')}
/>
{:else}
<CircleIconButton
isOpacity={true}
logo={MotionPlayOutline}
icon={mdiMoviePlayOutline}
title="Play Motion Photo"
on:click={() => dispatch('playMotionPhoto')}
/>
@ -106,7 +108,7 @@
<CircleIconButton
isOpacity={true}
hideMobile={true}
logo={$photoZoomState && $photoZoomState.currentZoom > 1 ? MagnifyMinusOutline : MagnifyPlusOutline}
icon={$photoZoomState && $photoZoomState.currentZoom > 1 ? mdiMagnifyMinusOutline : mdiMagnifyPlusOutline}
title="Zoom Image"
on:click={() => {
const zoomImage = new CustomEvent('zoomImage');
@ -117,7 +119,7 @@
{#if showCopyButton}
<CircleIconButton
isOpacity={true}
logo={ContentCopy}
icon={mdiContentCopy}
title="Copy Image"
on:click={() => {
const copyEvent = new CustomEvent('copyImage');
@ -129,7 +131,7 @@
{#if showDownloadButton}
<CircleIconButton
isOpacity={true}
logo={CloudDownloadOutline}
icon={mdiCloudDownloadOutline}
on:click={() => dispatch('download')}
title="Download"
/>
@ -137,7 +139,7 @@
{#if showDetailButton}
<CircleIconButton
isOpacity={true}
logo={InformationOutline}
icon={mdiInformationOutline}
on:click={() => dispatch('showDetail')}
title="Info"
/>
@ -145,7 +147,7 @@
{#if isOwner}
<CircleIconButton
isOpacity={true}
logo={asset.isFavorite ? Heart : HeartOutline}
icon={asset.isFavorite ? mdiHeart : mdiHeartOutline}
on:click={() => dispatch('favorite')}
title="Favorite"
/>
@ -153,10 +155,10 @@
{#if isOwner}
{#if !asset.isReadOnly || !asset.isExternal}
<CircleIconButton isOpacity={true} logo={DeleteOutline} on:click={() => dispatch('delete')} title="Delete" />
<CircleIconButton isOpacity={true} icon={mdiDeleteOutline} on:click={() => dispatch('delete')} title="Delete" />
{/if}
<div use:clickOutside on:outclick={() => (isShowAssetOptions = false)}>
<CircleIconButton isOpacity={true} logo={DotsVertical} on:click={showOptionsMenu} title="More" />
<CircleIconButton isOpacity={true} icon={mdiDotsVertical} on:click={showOptionsMenu} title="More" />
{#if isShowAssetOptions}
<ContextMenu {...contextMenuPosition} direction="left">
{#if showSlideshow}

View file

@ -2,9 +2,6 @@
import { goto } from '$app/navigation';
import { AlbumResponseDto, api, AssetJobName, AssetResponseDto, AssetTypeEnum, SharedLinkResponseDto } from '@api';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import ChevronLeft from 'svelte-material-icons/ChevronLeft.svelte';
import ChevronRight from 'svelte-material-icons/ChevronRight.svelte';
import ImageBrokenVariant from 'svelte-material-icons/ImageBrokenVariant.svelte';
import { fly } from 'svelte/transition';
import AlbumSelectionModal from '../shared-components/album-selection-modal.svelte';
import { notificationController, NotificationType } from '../shared-components/notification/notification';
@ -16,8 +13,6 @@
import { ProjectionType } from '$lib/constants';
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
import ProfileImageCropper from '../shared-components/profile-image-cropper.svelte';
import Pause from 'svelte-material-icons/Pause.svelte';
import Play from 'svelte-material-icons/Play.svelte';
import { isShowDetail } from '$lib/stores/preferences.store';
import { addAssetsToAlbum, downloadFile } from '$lib/utils/asset-utils';
import NavigationArea from './navigation-area.svelte';
@ -25,11 +20,11 @@
import { handleError } from '$lib/utils/handle-error';
import type { AssetStore } from '$lib/stores/assets.store';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import Close from 'svelte-material-icons/Close.svelte';
import ProgressBar, { ProgressBarStatus } from '../shared-components/progress-bar/progress-bar.svelte';
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
import { featureFlags } from '$lib/stores/server-config.store';
import { mdiChevronLeft, mdiChevronRight, mdiClose, mdiImageBrokenVariant, mdiPause, mdiPlay } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let assetStore: AssetStore | null = null;
export let asset: AssetResponseDto;
@ -368,14 +363,14 @@
<!-- SlideShowController -->
<div class="flex">
<div class="m-4 flex gap-2">
<CircleIconButton logo={Close} on:click={handleStopSlideshow} title="Exit Slideshow" />
<CircleIconButton icon={mdiClose} on:click={handleStopSlideshow} title="Exit Slideshow" />
<CircleIconButton
logo={progressBarStatus === ProgressBarStatus.Paused ? Play : Pause}
icon={progressBarStatus === ProgressBarStatus.Paused ? mdiPlay : mdiPause}
on:click={() => (progressBarStatus === ProgressBarStatus.Paused ? progressBar.play() : progressBar.pause())}
title={progressBarStatus === ProgressBarStatus.Paused ? 'Play' : 'Pause'}
/>
<CircleIconButton logo={ChevronLeft} on:click={navigateAssetBackward} title="Previous" />
<CircleIconButton logo={ChevronRight} on:click={navigateAssetForward} title="Next" />
<CircleIconButton icon={mdiChevronLeft} on:click={navigateAssetBackward} title="Previous" />
<CircleIconButton icon={mdiChevronRight} on:click={navigateAssetForward} title="Next" />
</div>
<ProgressBar
autoplay
@ -414,7 +409,7 @@
{#if !isSlideshowMode && showNavigation}
<div class="column-span-1 z-[999] col-start-1 row-span-1 row-start-2 mb-[60px] justify-self-start">
<NavigationArea on:click={navigateAssetBackward}><ChevronLeft size="36" /></NavigationArea>
<NavigationArea on:click={navigateAssetBackward}><Icon path={mdiChevronLeft} size="36" /></NavigationArea>
</div>
{/if}
@ -425,7 +420,7 @@
<div
class="px-auto flex aspect-square h-full items-center justify-center bg-gray-100 dark:bg-immich-dark-gray"
>
<ImageBrokenVariant size="25%" />
<Icon path={mdiImageBrokenVariant} size="25%" />
</div>
</div>
{:else if asset.type === AssetTypeEnum.Image}
@ -455,7 +450,7 @@
{#if !isSlideshowMode && showNavigation}
<div class="z-[999] col-span-1 col-start-4 row-span-1 row-start-2 mb-[60px] justify-self-end">
<NavigationArea on:click={navigateAssetForward}><ChevronRight size="36" /></NavigationArea>
<NavigationArea on:click={navigateAssetForward}><Icon path={mdiChevronRight} size="36" /></NavigationArea>
</div>
{/if}

View file

@ -7,14 +7,11 @@
import type { LatLngTuple } from 'leaflet';
import { DateTime } from 'luxon';
import { createEventDispatcher } from 'svelte';
import Calendar from 'svelte-material-icons/Calendar.svelte';
import CameraIris from 'svelte-material-icons/CameraIris.svelte';
import Close from 'svelte-material-icons/Close.svelte';
import ImageOutline from 'svelte-material-icons/ImageOutline.svelte';
import MapMarkerOutline from 'svelte-material-icons/MapMarkerOutline.svelte';
import { asByteUnitString } from '../../utils/byte-units';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import UserAvatar from '../shared-components/user-avatar.svelte';
import { mdiCalendar, mdiCameraIris, mdiClose, mdiImageOutline, mdiMapMarkerOutline } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let asset: AssetResponseDto;
export let albums: AlbumResponseDto[] = [];
@ -91,7 +88,7 @@
class="flex place-content-center place-items-center rounded-full p-3 transition-colors hover:bg-gray-200 dark:text-immich-dark-fg dark:hover:bg-gray-900"
on:click={() => dispatch('close')}
>
<Close size="24" />
<Icon path={mdiClose} size="24" />
</button>
<p class="text-lg text-immich-fg dark:text-immich-dark-fg">Info</p>
@ -186,7 +183,7 @@
})}
<div class="flex gap-4 py-4">
<div>
<Calendar size="24" />
<Icon path={mdiCalendar} size="24" />
</div>
<div>
@ -218,7 +215,7 @@
{#if asset.exifInfo?.fileSizeInByte}
<div class="flex gap-4 py-4">
<div><ImageOutline size="24" /></div>
<div><Icon path={mdiImageOutline} size="24" /></div>
<div>
<p class="break-all">
@ -242,7 +239,7 @@
{#if asset.exifInfo?.make || asset.exifInfo?.model || asset.exifInfo?.fNumber}
<div class="flex gap-4 py-4">
<div><CameraIris size="24" /></div>
<div><Icon path={mdiCameraIris} size="24" /></div>
<div>
<p>{asset.exifInfo.make || ''} {asset.exifInfo.model || ''}</p>
@ -271,7 +268,7 @@
{#if asset.exifInfo?.city}
<div class="flex gap-4 py-4">
<div><MapMarkerOutline size="24" /></div>
<div><Icon path={mdiMapMarkerOutline} size="24" /></div>
<div>
<p>{asset.exifInfo.city}</p>

View file

@ -1,10 +1,10 @@
<script lang="ts">
import { DownloadProgress, downloadAssets, downloadManager, isDownloading } from '$lib/stores/download';
import { locale } from '$lib/stores/preferences.store';
import Close from 'svelte-material-icons/Close.svelte';
import { fly, slide } from 'svelte/transition';
import { asByteUnitString } from '../../utils/byte-units';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { mdiClose } from '@mdi/js';
const abort = (downloadKey: string, download: DownloadProgress) => {
download.abort?.abort();
@ -39,7 +39,7 @@
</div>
</div>
<div class="absolute right-2">
<CircleIconButton on:click={() => abort(downloadKey, download)} size="20" logo={Close} forceDark />
<CircleIconButton on:click={() => abort(downloadKey, download)} size="20" icon={mdiClose} forceDark />
</div>
</div>
{/each}

View file

@ -3,7 +3,8 @@
import { fade } from 'svelte/transition';
import { thumbHashToDataURL } from 'thumbhash';
import { Buffer } from 'buffer';
import EyeOffOutline from 'svelte-material-icons/EyeOffOutline.svelte';
import { mdiEyeOffOutline } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let url: string;
export let altText: string;
@ -18,7 +19,7 @@
export let border = false;
let complete = false;
export let eyeColor = 'white';
export let eyeColor: 'black' | 'white' = 'white';
</script>
<img
@ -43,7 +44,7 @@
{#if hidden}
<div class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform">
<EyeOffOutline size="2em" color={eyeColor} />
<Icon path={mdiEyeOffOutline} size="2em" class="text-{eyeColor}" />
</div>
{/if}

View file

@ -4,16 +4,19 @@
import { timeToSeconds } from '$lib/utils/time-to-seconds';
import { api, AssetResponseDto, AssetTypeEnum, ThumbnailFormat } from '@api';
import { createEventDispatcher } from 'svelte';
import ArchiveArrowDownOutline from 'svelte-material-icons/ArchiveArrowDownOutline.svelte';
import CheckCircle from 'svelte-material-icons/CheckCircle.svelte';
import Heart from 'svelte-material-icons/Heart.svelte';
import ImageBrokenVariant from 'svelte-material-icons/ImageBrokenVariant.svelte';
import MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte';
import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
import { fade } from 'svelte/transition';
import ImageThumbnail from './image-thumbnail.svelte';
import VideoThumbnail from './video-thumbnail.svelte';
import Rotate360Icon from 'svelte-material-icons/Rotate360.svelte';
import {
mdiArchiveArrowDownOutline,
mdiCheckCircle,
mdiHeart,
mdiImageBrokenVariant,
mdiMotionPauseOutline,
mdiMotionPlayOutline,
mdiRotate360,
} from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
const dispatch = createEventDispatcher();
@ -93,13 +96,13 @@
{disabled}
>
{#if disabled}
<CheckCircle size="24" class="text-zinc-800" />
<Icon path={mdiCheckCircle} size="24" class="text-zinc-800" />
{:else if selected}
<div class="rounded-full bg-[#D9DCEF] dark:bg-[#232932]">
<CheckCircle size="24" class="text-immich-primary" />
<Icon path={mdiCheckCircle} size="24" class="text-immich-primary" />
</div>
{:else}
<CheckCircle size="24" class="text-white/80 hover:text-white" />
<Icon path={mdiCheckCircle} size="24" class="text-white/80 hover:text-white" />
{/if}
</button>
{/if}
@ -119,20 +122,20 @@
<!-- Favorite asset star -->
{#if !api.isSharedLink && asset.isFavorite}
<div class="absolute bottom-2 left-2 z-10">
<Heart size="24" class="text-white" />
<Icon path={mdiHeart} size="24" class="text-white" />
</div>
{/if}
{#if !api.isSharedLink && showArchiveIcon && asset.isArchived}
<div class="absolute {asset.isFavorite ? 'bottom-10' : 'bottom-2'} left-2 z-10">
<ArchiveArrowDownOutline size="24" class="text-white" />
<Icon path={mdiArchiveArrowDownOutline} size="24" class="text-white" />
</div>
{/if}
{#if asset.type === AssetTypeEnum.Image && asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR}
<div class="absolute right-0 top-0 z-20 flex place-items-center gap-1 text-xs font-medium text-white">
<span class="pr-2 pt-2">
<Rotate360Icon size="24" />
<Icon path={mdiRotate360} size="24" />
</span>
</div>
{/if}
@ -148,7 +151,7 @@
/>
{:else}
<div class="flex h-full w-full items-center justify-center p-4">
<ImageBrokenVariant size="48" />
<Icon path={mdiImageBrokenVariant} size="48" />
</div>
{/if}
@ -167,8 +170,8 @@
<div class="absolute top-0 h-full w-full">
<VideoThumbnail
url={api.getAssetFileUrl(asset.livePhotoVideoId, false, true)}
pauseIcon={MotionPauseOutline}
playIcon={MotionPlayOutline}
pauseIcon={mdiMotionPauseOutline}
playIcon={mdiMotionPlayOutline}
showTime={false}
curve={selected}
playbackOnIconHover

View file

@ -1,9 +1,8 @@
<script lang="ts">
import { Duration } from 'luxon';
import PauseCircleOutline from 'svelte-material-icons/PauseCircleOutline.svelte';
import PlayCircleOutline from 'svelte-material-icons/PlayCircleOutline.svelte';
import AlertCircleOutline from 'svelte-material-icons/AlertCircleOutline.svelte';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import { mdiAlertCircleOutline, mdiPauseCircleOutline, mdiPlayCircleOutline } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let url: string;
export let durationInSeconds = 0;
@ -11,8 +10,8 @@
export let playbackOnIconHover = false;
export let showTime = true;
export let curve = false;
export let playIcon = PlayCircleOutline;
export let pauseIcon = PauseCircleOutline;
export let playIcon = mdiPlayCircleOutline;
export let pauseIcon = mdiPauseCircleOutline;
let remainingSeconds = durationInSeconds;
let loading = true;
@ -55,12 +54,12 @@
{#if loading}
<LoadingSpinner />
{:else if error}
<AlertCircleOutline size="24" class="text-red-600" />
<Icon path={mdiAlertCircleOutline} size="24" class="text-red-600" />
{:else}
<svelte:component this={pauseIcon} size="24" />
<Icon path={pauseIcon} size="24" />
{/if}
{:else}
<svelte:component this={playIcon} size="24" />
<Icon path={playIcon} size="24" />
{/if}
</span>
</div>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import type Icon from 'svelte-material-icons/AbTesting.svelte';
import Icon from '$lib/components/elements/icon.svelte';
export let logo: typeof Icon;
export let icon: string;
export let backgroundColor = '';
export let hoverColor = '#e2e7e9';
export let padding = '3';
@ -23,7 +23,7 @@
{hideMobile && 'hidden sm:flex'}"
on:click
>
<svelte:component this={logo} {size} />
<Icon path={icon} {size} />
<slot />
</button>

View file

@ -5,12 +5,14 @@
</script>
<script lang="ts" generics="T">
import Icon from './icon.svelte';
import { mdiCheck } from '@mdi/js';
import _ from 'lodash';
import LinkButton from './buttons/link-button.svelte';
import { clickOutside } from '$lib/utils/click-outside';
import { fly } from 'svelte/transition';
import type Icon from 'svelte-material-icons/DotsVertical.svelte';
import Check from 'svelte-material-icons/Check.svelte';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{
@ -24,7 +26,7 @@
type RenderedOption = {
title: string;
icon?: typeof Icon;
icon?: string;
};
let showMenu = false;
@ -61,7 +63,7 @@
<LinkButton on:click={() => (showMenu = true)}>
<div class="flex place-items-center gap-2 text-sm">
{#if renderedSelectedOption?.icon}
<svelte:component this={renderedSelectedOption.icon} size="18" />
<Icon path={renderedSelectedOption.icon} size="18" />
{/if}
<p class="hidden sm:block">{renderedSelectedOption.title}</p>
</div>
@ -81,7 +83,7 @@
>
{#if _.isEqual(selectedOption, option)}
<div class="text-immich-primary dark:text-immich-dark-primary">
<Check size="18" />
<Icon path={mdiCheck} size="18" />
</div>
<p class="justify-self-start text-immich-primary dark:text-immich-dark-primary">
{renderedOption.title}

View file

@ -0,0 +1,36 @@
<script lang="ts">
import type { AriaRole } from 'svelte/elements';
export let size: string | number = '1em';
export let color = 'currentColor';
export let path: string;
export let title = '';
export let desc = '';
export let flipped = false;
let className = '';
export { className as class };
export let viewBox = '0 0 24 24';
export let role: AriaRole = 'img';
export let ariaHidden: boolean | undefined = undefined;
export let ariaLabel: string | undefined = undefined;
export let ariaLabelledby: string | undefined = undefined;
</script>
<svg
width={size}
height={size}
{viewBox}
class="{className} {flipped && '-scale-x-100'}"
{role}
aria-label={ariaLabel}
aria-hidden={ariaHidden}
aria-labelledby={ariaLabelledby}
>
{#if title}
<title>{title}</title>
{/if}
{#if desc}
<desc>{desc}</desc>
{/if}
<path d={path} fill={color} />
</svg>

View file

@ -6,15 +6,14 @@
import { fly } from 'svelte/transition';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import Button from '../elements/buttons/button.svelte';
import Merge from 'svelte-material-icons/Merge.svelte';
import CallMerge from 'svelte-material-icons/CallMerge.svelte';
import { flip } from 'svelte/animate';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
import { handleError } from '$lib/utils/handle-error';
import { goto, invalidateAll } from '$app/navigation';
import { AppRoute } from '$lib/constants';
import SwapHorizontal from 'svelte-material-icons/SwapHorizontal.svelte';
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let person: PersonResponseDto;
let people: PersonResponseDto[] = [];
@ -104,7 +103,7 @@
isShowConfirmation = true;
}}
>
<Merge size={18} />
<Icon path={mdiMerge} size={18} />
<span class="ml-2"> Merge</span></Button
>
</svelte:fragment>
@ -123,10 +122,10 @@
{#if hasSelection}
<span class="grid grid-cols-1"
><CallMerge size={48} class="rotate-90 dark:text-white" />
><Icon path={mdiCallMerge} size={48} class="rotate-90 dark:text-white" />
{#if selectedPeople.length === 1}
<button class="flex justify-center" on:click={handleSwapPeople}
><SwapHorizontal size={24} class="dark:text-white" />
><Icon path={mdiSwapHorizontal} size={24} class="dark:text-white" />
</button>
{/if}
</span>

View file

@ -2,12 +2,11 @@
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
import { api, type PersonResponseDto } from '@api';
import { createEventDispatcher } from 'svelte';
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
import Close from 'svelte-material-icons/Close.svelte';
import Merge from 'svelte-material-icons/Merge.svelte';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import Button from '../elements/buttons/button.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { mdiArrowLeft, mdiClose, mdiMerge } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
const dispatch = createEventDispatcher<{
reject: void;
@ -40,7 +39,7 @@
Merge faces - {title}
</h1>
<div class="p-2">
<CircleIconButton logo={Close} on:click={() => dispatch('close')} />
<CircleIconButton icon={mdiClose} on:click={() => dispatch('close')} />
</div>
</div>
@ -57,7 +56,7 @@
</div>
<div class="mx-0.5 flex md:mx-2">
<CircleIconButton
logo={Merge}
icon={mdiMerge}
on:click={() => ([personMerge1, personMerge2] = [personMerge2, personMerge1])}
/>
</div>
@ -83,7 +82,7 @@
{:else}
<div class="grid w-full grid-cols-1 gap-2">
<div class="px-2">
<button on:click={() => (choosePersonToMerge = false)}> <ArrowLeft /></button>
<button on:click={() => (choosePersonToMerge = false)}> <Icon path={mdiArrowLeft} /></button>
</div>
<div class="flex items-center justify-center">
<div class="flex flex-wrap justify-center md:grid md:grid-cols-{potentialMergePeople.length}">

View file

@ -3,12 +3,13 @@
import { getContextMenuPosition } from '$lib/utils/context-menu';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import IconButton from '../elements/buttons/icon-button.svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
import Portal from '../shared-components/portal/portal.svelte';
import { createEventDispatcher } from 'svelte';
import { AppRoute } from '$lib/constants';
import { mdiDotsVertical } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let person: PersonResponseDto;
@ -71,7 +72,7 @@
id={`icon-${person.id}`}
>
<IconButton color="transparent-primary">
<DotsVertical size="20" class="icon-white-drop-shadow" color="white" />
<Icon path={mdiDotsVertical} size="20" class="icon-white-drop-shadow text-white" />
</IconButton>
</button>
</div>

View file

@ -1,8 +1,9 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import Cake from 'svelte-material-icons/Cake.svelte';
import Button from '../elements/buttons/button.svelte';
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
import { mdiCake } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let birthDate: string;
@ -22,7 +23,7 @@
<div
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
>
<Cake size="4em" />
<Icon path={mdiCake} size="4em" />
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Set date of birth</h1>
<p class="text-sm dark:text-immich-dark-fg">

View file

@ -2,13 +2,10 @@
import { fly } from 'svelte/transition';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { quintOut } from 'svelte/easing';
import Close from 'svelte-material-icons/Close.svelte';
import IconButton from '../elements/buttons/icon-button.svelte';
import { createEventDispatcher } from 'svelte';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import Restart from 'svelte-material-icons/Restart.svelte';
import Eye from 'svelte-material-icons/Eye.svelte';
import EyeOff from 'svelte-material-icons/EyeOff.svelte';
import { mdiClose, mdiEye, mdiEyeOff, mdiRestart } from '@mdi/js';
const dispatch = createEventDispatcher();
@ -24,15 +21,19 @@
class="sticky top-0 z-10 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">
<CircleIconButton logo={Close} on:click={() => dispatch('closeClick')} />
<CircleIconButton icon={mdiClose} on:click={() => dispatch('closeClick')} />
<p class="ml-4 hidden sm:block">Show & hide faces</p>
</div>
<div class="flex items-center justify-end">
<div class="flex items-center md:mr-8">
<CircleIconButton title="Reset faces visibility" logo={Restart} on:click={() => dispatch('reset-visibility')} />
<CircleIconButton
title="Reset faces visibility"
icon={mdiRestart}
on:click={() => dispatch('reset-visibility')}
/>
<CircleIconButton
title="Toggle visibility"
logo={toggleVisibility ? Eye : EyeOff}
icon={toggleVisibility ? mdiEye : mdiEyeOff}
on:click={() => dispatch('toggle-visibility')}
/>
</div>

View file

@ -1,9 +1,10 @@
<script lang="ts">
import type { APIKeyResponseDto } from '@api';
import { createEventDispatcher } from 'svelte';
import KeyVariant from 'svelte-material-icons/KeyVariant.svelte';
import Button from '../elements/buttons/button.svelte';
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiKeyVariant } from '@mdi/js';
export let apiKey: Partial<APIKeyResponseDto>;
export let title = 'API Key';
@ -22,7 +23,7 @@
<div
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
>
<KeyVariant size="4em" />
<Icon path={mdiKeyVariant} size="4em" />
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">
{title}
</h1>

View file

@ -1,9 +1,10 @@
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import KeyVariant from 'svelte-material-icons/KeyVariant.svelte';
import { copyToClipboard } from '@api';
import Button from '../elements/buttons/button.svelte';
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
import { mdiKeyVariant } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let secret = '';
@ -24,7 +25,7 @@
<div
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
>
<KeyVariant size="4em" />
<Icon path={mdiKeyVariant} size="4em" />
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">API Key</h1>
<p class="text-sm dark:text-immich-dark-fg">

View file

@ -1,11 +1,10 @@
<script lang="ts">
import { AlbumResponseDto, api } from '@api';
import { createEventDispatcher } from 'svelte';
import ImageAlbum from 'svelte-material-icons/ImageAlbum.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import Button from '../elements/buttons/button.svelte';
import { handleError } from '../../utils/handle-error';
import { mdiImageAlbum } from '@mdi/js';
export let album: AlbumResponseDto;
@ -36,7 +35,7 @@
<div
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
>
<ImageAlbum size="4em" />
<Icon path={mdiImageAlbum} size="4em" />
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Edit album</h1>
</div>

View file

@ -1,11 +1,12 @@
<script lang="ts">
import { api, UserResponseDto } from '@api';
import { createEventDispatcher } from 'svelte';
import AccountEditOutline from 'svelte-material-icons/AccountEditOutline.svelte';
import { notificationController, NotificationType } from '../shared-components/notification/notification';
import Button from '../elements/buttons/button.svelte';
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
import { handleError } from '../../utils/handle-error';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiAccountEditOutline } from '@mdi/js';
export let user: UserResponseDto;
export let canResetPassword = true;
@ -72,7 +73,7 @@
<div
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
>
<AccountEditOutline size="4em" />
<Icon path={mdiAccountEditOutline} size="4em" />
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Edit user</h1>
</div>

View file

@ -1,8 +1,9 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import FolderRemove from 'svelte-material-icons/FolderRemove.svelte';
import Button from '../elements/buttons/button.svelte';
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiFolderRemove } from '@mdi/js';
export let exclusionPattern: string;
export let canDelete = false;
@ -20,7 +21,7 @@
<div
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
>
<FolderRemove size="4em" />
<Icon path={mdiFolderRemove} size="4em" />
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Add Exclusion pattern</h1>
</div>

View file

@ -1,8 +1,9 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import FolderSync from 'svelte-material-icons/FolderSync.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import Button from '../elements/buttons/button.svelte';
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
import { mdiFolderSync } from '@mdi/js';
export let importPath: string;
export let title = 'Import path';
@ -22,7 +23,7 @@
<div
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
>
<FolderSync size="4em" />
<Icon path={mdiFolderSync} size="4em" />
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">
{title}
</h1>

View file

@ -4,8 +4,9 @@
import { handleError } from '../../utils/handle-error';
import LibraryImportPathForm from './library-import-path-form.svelte';
import { onMount } from 'svelte';
import PencilOutline from 'svelte-material-icons/PencilOutline.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { LibraryResponseDto } from '@api';
import { mdiPencilOutline } from '@mdi/js';
export let library: Partial<LibraryResponseDto>;
@ -141,7 +142,7 @@
}}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
>
<PencilOutline size="16" />
<Icon path={mdiPencilOutline} size="16" />
</button>
</td>
</tr>

View file

@ -4,8 +4,9 @@
import { LibraryType, type LibraryResponseDto } from '@api';
import { handleError } from '../../utils/handle-error';
import { onMount } from 'svelte';
import PencilOutline from 'svelte-material-icons/PencilOutline.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import LibraryExclusionPatternForm from './library-exclusion-pattern-form.svelte';
import { mdiPencilOutline } from '@mdi/js';
export let library: Partial<LibraryResponseDto>;
@ -139,7 +140,7 @@
}}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
>
<PencilOutline size="16" />
<Icon path={mdiPencilOutline} size="16" />
</button>
</td>
</tr>

View file

@ -6,12 +6,6 @@
import { goto } from '$app/navigation';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import { fromLocalDateTime } from '$lib/utils/timeline-util';
import Play from 'svelte-material-icons/Play.svelte';
import Pause from 'svelte-material-icons/Pause.svelte';
import ChevronDown from 'svelte-material-icons/ChevronDown.svelte';
import ChevronUp from 'svelte-material-icons/ChevronUp.svelte';
import ChevronLeft from 'svelte-material-icons/ChevronLeft.svelte';
import ChevronRight from 'svelte-material-icons/ChevronRight.svelte';
import { AppRoute } from '$lib/constants';
import { page } from '$app/stores';
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
@ -20,6 +14,7 @@
import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte';
import { fade } from 'svelte/transition';
import { tweened } from 'svelte/motion';
import { mdiChevronDown, mdiChevronLeft, mdiChevronRight, mdiChevronUp, mdiPause, mdiPlay } from '@mdi/js';
const parseIndex = (s: string | null, max: number | null) => Math.max(Math.min(parseInt(s ?? '') || 0, max ?? 0), 0);
@ -115,7 +110,7 @@
{#if !galleryInView}
<div class="flex place-content-center place-items-center gap-2 overflow-hidden">
<CircleIconButton logo={paused ? Play : Pause} forceDark on:click={() => (paused = !paused)} />
<CircleIconButton icon={paused ? mdiPlay : mdiPause} forceDark on:click={() => (paused = !paused)} />
{#each currentMemory.assets as _, i}
<button class="relative w-full py-2" on:click={() => goto(`?memory=${memoryIndex}&asset=${i}`)}>
@ -147,7 +142,7 @@
class:opacity-100={galleryInView}
>
<button on:click={() => memoryWrapper.scrollIntoView({ behavior: 'smooth' })} disabled={!galleryInView}>
<CircleIconButton logo={ChevronUp} backgroundColor="white" forceDark />
<CircleIconButton icon={mdiChevronUp} backgroundColor="white" forceDark />
</button>
</div>
{/if}
@ -190,14 +185,14 @@
<div class="ml-4 flex h-full flex-col place-content-center place-items-center">
<div class="inline-block">
{#if canGoBack}
<CircleIconButton logo={ChevronLeft} backgroundColor="#202123" on:click={toPrevious} />
<CircleIconButton icon={mdiChevronLeft} backgroundColor="#202123" on:click={toPrevious} />
{/if}
</div>
</div>
<div class="mr-4 flex h-full flex-col place-content-center place-items-center">
<div class="inline-block">
{#if canGoForward}
<CircleIconButton logo={ChevronRight} backgroundColor="#202123" on:click={toNext} />
<CircleIconButton icon={mdiChevronRight} backgroundColor="#202123" on:click={toNext} />
{/if}
</div>
</div>
@ -260,7 +255,7 @@
class:opacity-100={!galleryInView}
>
<button on:click={() => memoryGallery.scrollIntoView({ behavior: 'smooth' })}>
<CircleIconButton logo={ChevronDown} backgroundColor="white" forceDark />
<CircleIconButton icon={mdiChevronDown} backgroundColor="white" forceDark />
</button>
</div>

View file

@ -6,11 +6,9 @@
} from '$lib/components/shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import { api } from '@api';
import ArchiveArrowDownOutline from 'svelte-material-icons/ArchiveArrowDownOutline.svelte';
import ArchiveArrowUpOutline from 'svelte-material-icons/ArchiveArrowUpOutline.svelte';
import TimerSand from 'svelte-material-icons/TimerSand.svelte';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { OnArchive, getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiArchiveArrowUpOutline, mdiArchiveArrowDownOutline, mdiTimerSand } from '@mdi/js';
export let onArchive: OnArchive | undefined = undefined;
@ -18,7 +16,7 @@
export let unarchive = false;
$: text = unarchive ? 'Unarchive' : 'Archive';
$: logo = unarchive ? ArchiveArrowUpOutline : ArchiveArrowDownOutline;
$: icon = unarchive ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline;
let loading = false;
@ -62,8 +60,8 @@
{#if !menuItem}
{#if loading}
<CircleIconButton title="Loading" logo={TimerSand} />
<CircleIconButton title="Loading" icon={mdiTimerSand} />
{:else}
<CircleIconButton title={text} {logo} on:click={handleArchive} />
<CircleIconButton title={text} {icon} on:click={handleArchive} />
{/if}
{/if}

View file

@ -1,9 +1,9 @@
<script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
import ShareVariantOutline from 'svelte-material-icons/ShareVariantOutline.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiShareVariantOutline } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
let showModal = false;
const dispatch = createEventDispatcher();
@ -14,7 +14,7 @@
};
</script>
<CircleIconButton title="Share" logo={ShareVariantOutline} on:click={() => (showModal = true)} />
<CircleIconButton title="Share" icon={mdiShareVariantOutline} on:click={() => (showModal = true)} />
{#if showModal}
<CreateSharedLinkModal

View file

@ -7,13 +7,11 @@
} from '$lib/components/shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import { api } from '@api';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import TimerSand from 'svelte-material-icons/TimerSand.svelte';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { OnAssetDelete, getAssetControlContext } from '../asset-select-control-bar.svelte';
import { createEventDispatcher } from 'svelte';
import { featureFlags } from '$lib/stores/server-config.store';
import { mdiTimerSand, mdiDeleteOutline } from '@mdi/js';
export let onAssetDelete: OnAssetDelete;
export let menuItem = false;
@ -70,9 +68,9 @@
{#if menuItem}
<MenuOption text={force ? 'Permanently Delete' : 'Delete'} on:click={handleTrash} />
{:else if loading}
<CircleIconButton title="Loading" logo={TimerSand} />
<CircleIconButton title="Loading" icon={mdiTimerSand} />
{:else}
<CircleIconButton title="Delete" logo={DeleteOutline} on:click={handleTrash} />
<CircleIconButton title="Delete" icon={mdiDeleteOutline} on:click={handleTrash} />
{/if}
{#if isShowConfirmation}

View file

@ -1,9 +1,9 @@
<script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { downloadArchive, downloadFile } from '$lib/utils/asset-utils';
import CloudDownloadOutline from 'svelte-material-icons/CloudDownloadOutline.svelte';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiCloudDownloadOutline } from '@mdi/js';
export let filename = 'immich.zip';
export let menuItem = false;
@ -26,5 +26,5 @@
{#if menuItem}
<MenuOption text="Download" on:click={handleDownloadFiles} />
{:else}
<CircleIconButton title="Download" logo={CloudDownloadOutline} on:click={handleDownloadFiles} />
<CircleIconButton title="Download" icon={mdiCloudDownloadOutline} on:click={handleDownloadFiles} />
{/if}

View file

@ -7,10 +7,8 @@
} from '$lib/components/shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import { api } from '@api';
import HeartMinusOutline from 'svelte-material-icons/HeartMinusOutline.svelte';
import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
import TimerSand from 'svelte-material-icons/TimerSand.svelte';
import { OnFavorite, getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiHeartMinusOutline, mdiHeartOutline, mdiTimerSand } from '@mdi/js';
export let onFavorite: OnFavorite | undefined = undefined;
@ -18,7 +16,7 @@
export let removeFavorite: boolean;
$: text = removeFavorite ? 'Remove from Favorites' : 'Favorite';
$: logo = removeFavorite ? HeartMinusOutline : HeartOutline;
$: icon = removeFavorite ? mdiHeartMinusOutline : mdiHeartOutline;
let loading = false;
@ -62,8 +60,8 @@
{#if !menuItem}
{#if loading}
<CircleIconButton title="Loading" logo={TimerSand} />
<CircleIconButton title="Loading" icon={mdiTimerSand} />
{:else}
<CircleIconButton title={text} {logo} on:click={handleFavorite} />
<CircleIconButton title={text} {icon} on:click={handleFavorite} />
{/if}
{/if}

View file

@ -6,9 +6,9 @@
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { AlbumResponseDto, api } from '@api';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiDeleteOutline } from '@mdi/js';
export let album: AlbumResponseDto;
export let onRemove: ((assetIds: string[]) => void) | undefined = undefined;
@ -53,7 +53,7 @@
{#if menuItem}
<MenuOption text="Remove from album" on:click={() => (isShowConfirmation = true)} />
{:else}
<CircleIconButton title="Remove from album" logo={DeleteOutline} on:click={() => (isShowConfirmation = true)} />
<CircleIconButton title="Remove from album" icon={mdiDeleteOutline} on:click={() => (isShowConfirmation = true)} />
{/if}
{#if isShowConfirmation}

View file

@ -1,11 +1,11 @@
<script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { SharedLinkResponseDto, api } from '@api';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
import { handleError } from '../../../utils/handle-error';
import { mdiDeleteOutline } from '@mdi/js';
export let sharedLink: SharedLinkResponseDto;
@ -45,7 +45,7 @@
};
</script>
<CircleIconButton title="Remove from shared link" on:click={() => (removing = true)} logo={DeleteOutline} />
<CircleIconButton title="Remove from shared link" on:click={() => (removing = true)} icon={mdiDeleteOutline} />
{#if removing}
<ConfirmDialogue

View file

@ -5,9 +5,10 @@
} from '$lib/components/shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import { api } from '@api';
import History from 'svelte-material-icons/History.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import Button from '../../elements/buttons/button.svelte';
import { OnRestore, getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiHistory } from '@mdi/js';
export let onRestore: OnRestore | undefined = undefined;
@ -38,6 +39,6 @@
</script>
<Button disabled={loading} size="sm" color="transparent-gray" shadow={false} rounded="lg" on:click={handleRestore}>
<History size="24" />
<Icon path={mdiHistory} size="24" />
<span class="ml-2">Restore</span>
</Button>

View file

@ -3,9 +3,8 @@
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
import { BucketPosition, type AssetStore } from '$lib/stores/assets.store';
import { handleError } from '$lib/utils/handle-error';
import SelectAll from 'svelte-material-icons/SelectAll.svelte';
import TimerSand from 'svelte-material-icons/TimerSand.svelte';
import { get } from 'svelte/store';
import { mdiTimerSand, mdiSelectAll } from '@mdi/js';
export let assetStore: AssetStore;
export let assetInteractionStore: AssetInteractionStore;
@ -32,8 +31,8 @@
</script>
{#if selecting}
<CircleIconButton title="Delete" logo={TimerSand} />
<CircleIconButton title="Delete" icon={mdiTimerSand} />
{/if}
{#if !selecting}
<CircleIconButton title="Select all" logo={SelectAll} on:click={handleSelectAll} />
<CircleIconButton title="Select all" icon={mdiSelectAll} on:click={handleSelectAll} />
{/if}

View file

@ -5,14 +5,14 @@
import type { AssetResponseDto } from '@api';
import justifiedLayout from 'justified-layout';
import { createEventDispatcher } from 'svelte';
import CheckCircle from 'svelte-material-icons/CheckCircle.svelte';
import CircleOutline from 'svelte-material-icons/CircleOutline.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { fly } from 'svelte/transition';
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import type { AssetStore } from '$lib/stores/assets.store';
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
import type { Viewport } from '$lib/stores/assets.store';
import { mdiCheckCircle, mdiCircleOutline } from '@mdi/js';
export let assets: AssetResponseDto[];
export let bucketDate: string;
@ -154,9 +154,9 @@
on:keydown={() => handleSelectGroup(groupTitle, groupAssets)}
>
{#if $selectedGroup.has(groupTitle)}
<CheckCircle size="24" color="#4250af" />
<Icon path={mdiCheckCircle} size="24" color="#4250af" />
{:else}
<CircleOutline size="24" color="#757575" />
<Icon path={mdiCircleOutline} size="24" color="#757575" />
{/if}
</div>
{/if}

View file

@ -9,10 +9,9 @@
<script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
import type Icon from 'svelte-material-icons/AbTesting.svelte';
import { getContextMenuPosition } from '$lib/utils/context-menu';
export let icon: typeof Icon;
export let icon: string;
export let title: string;
let showContextMenu = false;
@ -27,7 +26,7 @@
</script>
<div use:clickOutside on:outclick={() => (showContextMenu = false)}>
<CircleIconButton {title} logo={icon} on:click={handleShowMenu} />
<CircleIconButton {title} {icon} on:click={handleShowMenu} />
{#if showContextMenu}
<ContextMenu {...contextMenuPosition}>
<div class="flex flex-col rounded-lg">

View file

@ -19,8 +19,8 @@
<script lang="ts">
import { locale } from '$lib/stores/preferences.store';
import type { AssetResponseDto } from '@api';
import Close from 'svelte-material-icons/Close.svelte';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import { mdiClose } from '@mdi/js';
export let assets: Set<AssetResponseDto>;
export let clearSelect: () => void;
@ -28,7 +28,7 @@
setContext({ getAssets: () => assets, clearSelect });
</script>
<ControlAppBar on:close-button-click={clearSelect} backIcon={Close} tailwindClasses="bg-white shadow-md">
<ControlAppBar on:close-button-click={clearSelect} backIcon={mdiClose} tailwindClasses="bg-white shadow-md">
<p class="font-medium text-immich-primary dark:text-immich-dark-primary" slot="leading">
Selected {assets.size.toLocaleString($locale)}
</p>

View file

@ -1,11 +1,11 @@
<script lang="ts">
import { onMount } from 'svelte';
import { api } from '@api';
import ChevronLeft from 'svelte-material-icons/ChevronLeft.svelte';
import ChevronRight from 'svelte-material-icons/ChevronRight.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { memoryStore } from '$lib/stores/memory.store';
import { goto } from '$app/navigation';
import { fade } from 'svelte/transition';
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
$: shouldRender = $memoryStore?.length > 0;
@ -50,7 +50,7 @@
class="rounded-full border border-gray-500 bg-gray-100 p-2 text-gray-500 opacity-50 hover:opacity-100"
on:click={scrollLeft}
>
<ChevronLeft size="36" /></button
<Icon path={mdiChevronLeft} size="36" /></button
>
</div>
{/if}
@ -60,7 +60,7 @@
class="rounded-full border border-gray-500 bg-gray-100 p-2 text-gray-500 opacity-50 hover:opacity-100"
on:click={scrollRight}
>
<ChevronRight size="36" /></button
<Icon path={mdiChevronRight} size="36" /></button
>
</div>
{/if}

View file

@ -4,19 +4,16 @@
import { downloadArchive } from '$lib/utils/asset-utils';
import { api, AssetResponseDto, SharedLinkResponseDto } from '@api';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
import FileImagePlusOutline from 'svelte-material-icons/FileImagePlusOutline.svelte';
import FolderDownloadOutline from 'svelte-material-icons/FolderDownloadOutline.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import DownloadAction from '../photos-page/actions/download-action.svelte';
import RemoveFromSharedLink from '../photos-page/actions/remove-from-shared-link.svelte';
import AssetSelectControlBar from '../photos-page/asset-select-control-bar.svelte';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte';
import SelectAll from 'svelte-material-icons/SelectAll.svelte';
import ImmichLogo from '../shared-components/immich-logo.svelte';
import { notificationController, NotificationType } from '../shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import { mdiArrowLeft, mdiFileImagePlusOutline, mdiFolderDownloadOutline, mdiSelectAll } from '@mdi/js';
export let sharedLink: SharedLinkResponseDto;
export let isOwned: boolean;
@ -72,7 +69,7 @@
<section class="bg-immich-bg dark:bg-immich-dark-bg">
{#if isMultiSelectionMode}
<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}>
<CircleIconButton title="Select all" logo={SelectAll} on:click={handleSelectAll} />
<CircleIconButton title="Select all" icon={mdiSelectAll} on:click={handleSelectAll} />
{#if sharedLink?.allowDownload}
<DownloadAction filename="immich-shared.zip" />
{/if}
@ -81,7 +78,7 @@
{/if}
</AssetSelectControlBar>
{:else}
<ControlAppBar on:close-button-click={() => goto('/photos')} backIcon={ArrowLeft} showBackButton={false}>
<ControlAppBar on:close-button-click={() => goto('/photos')} backIcon={mdiArrowLeft} showBackButton={false}>
<svelte:fragment slot="leading">
<a
data-sveltekit-preload-data="hover"
@ -95,11 +92,11 @@
<svelte:fragment slot="trailing">
{#if sharedLink?.allowUpload}
<CircleIconButton title="Add Photos" on:click={() => handleUploadAssets()} logo={FileImagePlusOutline} />
<CircleIconButton title="Add Photos" on:click={() => handleUploadAssets()} icon={mdiFileImagePlusOutline} />
{/if}
{#if sharedLink?.allowDownload}
<CircleIconButton title="Download" on:click={downloadAssets} logo={FolderDownloadOutline} />
<CircleIconButton title="Download" on:click={downloadAssets} icon={mdiFolderDownloadOutline} />
{/if}
</svelte:fragment>
</ControlAppBar>

View file

@ -1,9 +1,10 @@
<script lang="ts">
import { AlbumResponseDto, api } from '@api';
import { createEventDispatcher, onMount } from 'svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import BaseModal from './base-modal.svelte';
import AlbumListItem from '../asset-viewer/album-list-item.svelte';
import { mdiPlus } from '@mdi/js';
let albums: AlbumResponseDto[] = [];
let recentAlbums: AlbumResponseDto[] = [];
@ -84,7 +85,7 @@
class="flex w-full items-center gap-4 px-6 py-2 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700"
>
<div class="flex h-12 w-12 items-center justify-center">
<Plus size="30" />
<Icon path={mdiPlus} size="30" />
</div>
<p class="">
New {#if shared}Shared {/if}Album {#if search.length > 0}<b>{search}</b>{/if}

View file

@ -1,11 +1,11 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import { quintOut } from 'svelte/easing';
import Close from 'svelte-material-icons/Close.svelte';
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
import { browser } from '$app/environment';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { clickOutside } from '$lib/utils/click-outside';
import { mdiClose } from '@mdi/js';
const dispatch = createEventDispatcher();
export let zIndex = 9999;
@ -46,7 +46,7 @@
</slot>
</div>
<CircleIconButton on:click={() => dispatch('close')} logo={Close} size={'20'} />
<CircleIconButton on:click={() => dispatch('close')} icon={mdiClose} size={'20'} />
</div>
<div class="">

View file

@ -2,12 +2,12 @@
import { browser } from '$app/environment';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import Close from 'svelte-material-icons/Close.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { fly } from 'svelte/transition';
import { mdiClose } from '@mdi/js';
export let showBackButton = true;
export let backIcon = Close;
export let backIcon = mdiClose;
export let tailwindClasses = '';
export let forceDark = false;
@ -51,7 +51,7 @@
{#if showBackButton}
<CircleIconButton
on:click={() => dispatch('close-button-click')}
logo={backIcon}
icon={backIcon}
backgroundColor={'transparent'}
hoverColor={'#e2e7e9'}
size={'24'}

View file

@ -7,11 +7,12 @@
import { handleError } from '$lib/utils/handle-error';
import { api, copyToClipboard, SharedLinkResponseDto, SharedLinkType } from '@api';
import { createEventDispatcher, onMount } from 'svelte';
import Link from 'svelte-material-icons/Link.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import BaseModal from '../base-modal.svelte';
import type { ImmichDropDownOption } from '../dropdown-button.svelte';
import DropdownButton from '../dropdown-button.svelte';
import { notificationController, NotificationType } from '../notification/notification';
import { mdiLink } from '@mdi/js';
export let albumId: string | undefined = undefined;
export let assetIds: string[] = [];
@ -140,7 +141,7 @@
<BaseModal on:close={() => dispatch('close')} on:escape={() => dispatch('escape')}>
<svelte:fragment slot="title">
<span class="flex place-items-center gap-2">
<Link size={24} />
<Icon path={mdiLink} size={24} />
{#if editingLink}
<p class="font-medium text-immich-fg dark:text-immich-dark-fg">Edit link</p>
{:else}

View file

@ -3,10 +3,10 @@
import { AppRoute } from '$lib/constants';
import type { UserResponseDto } from '@api';
import { createEventDispatcher } from 'svelte';
import Cog from 'svelte-material-icons/Cog.svelte';
import Logout from 'svelte-material-icons/Logout.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { fade } from 'svelte/transition';
import UserAvatar from '../user-avatar.svelte';
import { mdiCog, mdiLogout } from '@mdi/js';
export let user: UserResponseDto;
@ -35,7 +35,7 @@
<a href={AppRoute.USER_SETTINGS} on:click={() => dispatch('close')}>
<Button color="dark-gray" size="sm" shadow={false} border>
<div class="flex place-content-center place-items-center gap-2 px-2">
<Cog size="18" />
<Icon path={mdiCog} size="18" />
Account Settings
</div>
</Button>
@ -47,7 +47,7 @@
class="flex w-full place-content-center place-items-center gap-2 py-3 font-medium text-gray-500 hover:bg-immich-primary/10 dark:text-gray-300"
on:click={() => dispatch('logout')}
>
<Logout size={24} />
<Icon path={mdiLogout} size={24} />
Sign Out</button
>
</div>

View file

@ -4,7 +4,6 @@
import { clickOutside } from '$lib/utils/click-outside';
import { createEventDispatcher } from 'svelte';
import { fade, fly } from 'svelte/transition';
import TrayArrowUp from 'svelte-material-icons/TrayArrowUp.svelte';
import { api, UserResponseDto } from '@api';
import ThemeButton from '../theme-button.svelte';
import { AppRoute } from '../../../constants';
@ -12,11 +11,11 @@
import ImmichLogo from '../immich-logo.svelte';
import SearchBar from '../search-bar/search-bar.svelte';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import Magnify from 'svelte-material-icons/Magnify.svelte';
import IconButton from '$lib/components/elements/buttons/icon-button.svelte';
import Cog from 'svelte-material-icons/Cog.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import UserAvatar from '../user-avatar.svelte';
import { featureFlags } from '$lib/stores/server-config.store';
import { mdiMagnify, mdiTrayArrowUp, mdiCog } from '@mdi/js';
export let user: UserResponseDto;
export let showUploadButton = true;
@ -56,7 +55,7 @@
<a href={AppRoute.SEARCH} id="search-button" class="pl-4 sm:hidden">
<IconButton title="Search">
<div class="flex gap-2">
<Magnify size="1.5em" />
<Icon path={mdiMagnify} size="1.5em" />
</div>
</IconButton>
</a>
@ -68,7 +67,7 @@
<div in:fly={{ x: 50, duration: 250 }}>
<LinkButton on:click={() => dispatch('uploadClicked')}>
<div class="flex gap-2">
<TrayArrowUp size="1.5em" />
<Icon path={mdiTrayArrowUp} size="1.5em" />
<span class="hidden md:block">Upload</span>
</div>
</LinkButton>
@ -95,7 +94,8 @@
</span>
</div>
<div class="block sm:hidden" aria-hidden="true">
<Cog
<Icon
path={mdiCog}
size="1.5em"
class="dark:text-immich-dark-fg {$page.url.pathname.includes('/admin')
? 'text-immich-primary dark:text-immich-dark-primary'

View file

@ -1,15 +1,13 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import CloseCircleOutline from 'svelte-material-icons/CloseCircleOutline.svelte';
import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
import WindowClose from 'svelte-material-icons/WindowClose.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import {
ImmichNotification,
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import { onMount } from 'svelte';
import { mdiCloseCircleOutline, mdiInformationOutline, mdiWindowClose } from '@mdi/js';
export let notificationInfo: ImmichNotification;
@ -17,7 +15,7 @@
let errorPrimaryColor = '#E64132';
let warningPrimaryColor = '#D08613';
$: icon = notificationInfo.type === NotificationType.Error ? CloseCircleOutline : InformationOutline;
$: icon = notificationInfo.type === NotificationType.Error ? mdiCloseCircleOutline : mdiInformationOutline;
$: backgroundColor = () => {
if (notificationInfo.type === NotificationType.Info) {
@ -93,13 +91,13 @@
>
<div class="flex justify-between">
<div class="flex place-items-center gap-2">
<svelte:component this={icon} color={primaryColor()} size="20" />
<Icon path={icon} color={primaryColor()} size="20" />
<h2 style:color={primaryColor()} class="font-medium" data-testid="title">
{notificationInfo.type.toString()}
</h2>
</div>
<button on:click|stopPropagation={discard}>
<svelte:component this={WindowClose} size="20" />
<Icon path={mdiWindowClose} size="20" />
</button>
</div>

View file

@ -1,11 +1,11 @@
<script lang="ts">
import { AppRoute } from '$lib/constants';
import Magnify from 'svelte-material-icons/Magnify.svelte';
import Close from 'svelte-material-icons/Close.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { goto } from '$app/navigation';
import { isSearchEnabled, preventRaceConditionSearchBar, savedSearchTerms } from '$lib/stores/search.store';
import { fly } from 'svelte/transition';
import { clickOutside } from '$lib/utils/click-outside';
import { mdiClose, mdiMagnify } from '@mdi/js';
export let value = '';
export let grayTheme: boolean;
@ -82,7 +82,7 @@
<div class="absolute inset-y-0 left-0 flex items-center pl-6">
<div class="dark:text-immich-dark-fg/75">
<button class="flex items-center">
<Magnify size="1.5em" />
<Icon path={mdiMagnify} size="1.5em" />
</button>
</div>
</div>
@ -108,7 +108,7 @@
type="reset"
class="rounded-full p-2 hover:bg-immich-primary/5 active:bg-immich-primary/10 dark:text-immich-dark-fg/75 dark:hover:bg-immich-dark-primary/25 dark:active:bg-immich-dark-primary/[.35]"
>
<Close size="1.5em" />
<Icon path={mdiClose} size="1.5em" />
</button>
</div>
{/if}
@ -153,11 +153,13 @@
onSearch();
}}
>
<Magnify size="1.5em" />
<Icon path={mdiMagnify} size="1.5em" />
{savedSearchTerm}
</button>
<div class="absolute right-5 top-0 items-center justify-center py-3">
<button type="button" on:click={() => clearSearchTerm(savedSearchTerm)}><Close size="18" /></button>
<button type="button" on:click={() => clearSearchTerm(savedSearchTerm)}
><Icon path={mdiClose} size="18" /></button
>
</div>
</div>
</div>

View file

@ -1,8 +1,8 @@
<script lang="ts">
import Close from 'svelte-material-icons/Close.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { createEventDispatcher } from 'svelte';
import FullScreenModal from './full-screen-modal.svelte';
import { mdiClose } from '@mdi/js';
const shortcuts = {
general: [
@ -30,7 +30,7 @@
<div class="relative px-4 pt-4">
<h1 class="px-4 py-4 font-medium text-immich-primary dark:text-immich-dark-primary">Keyboard Shortcuts</h1>
<div class="absolute inset-y-0 right-0 px-4 py-4">
<CircleIconButton logo={Close} on:click={() => dispatch('close')} />
<CircleIconButton icon={mdiClose} on:click={() => dispatch('close')} />
</div>
</div>

View file

@ -4,32 +4,28 @@
import SideBarSection from '$lib/components/shared-components/side-bar/side-bar-section.svelte';
import StatusBox from '$lib/components/shared-components/status-box.svelte';
import { AppRoute } from '$lib/constants';
import AccountMultipleOutline from 'svelte-material-icons/AccountMultipleOutline.svelte';
import Cog from 'svelte-material-icons/Cog.svelte';
import Server from 'svelte-material-icons/Server.svelte';
import Tools from 'svelte-material-icons/Tools.svelte';
import Sync from 'svelte-material-icons/Sync.svelte';
import { mdiAccountMultipleOutline, mdiCog, mdiServer, mdiSync, mdiTools } from '@mdi/js';
</script>
<SideBarSection>
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_USER_MANAGEMENT} draggable="false">
<SideBarButton
title="Users"
logo={AccountMultipleOutline}
icon={mdiAccountMultipleOutline}
isSelected={$page.route.id === AppRoute.ADMIN_USER_MANAGEMENT}
/>
</a>
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_JOBS} draggable="false">
<SideBarButton title="Jobs" logo={Sync} isSelected={$page.route.id === AppRoute.ADMIN_JOBS} />
<SideBarButton title="Jobs" icon={mdiSync} isSelected={$page.route.id === AppRoute.ADMIN_JOBS} />
</a>
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_SETTINGS} draggable="false">
<SideBarButton title="Settings" logo={Cog} isSelected={$page.route.id === AppRoute.ADMIN_SETTINGS} />
<SideBarButton title="Settings" icon={mdiCog} isSelected={$page.route.id === AppRoute.ADMIN_SETTINGS} />
</a>
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_STATS} draggable="false">
<SideBarButton title="Server Stats" logo={Server} isSelected={$page.route.id === AppRoute.ADMIN_STATS} />
<SideBarButton title="Server Stats" icon={mdiServer} isSelected={$page.route.id === AppRoute.ADMIN_STATS} />
</a>
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_REPAIR} draggable="false">
<SideBarButton title="Repair" logo={Tools} isSelected={$page.route.id === AppRoute.ADMIN_REPAIR} />
<SideBarButton title="Repair" icon={mdiTools} isSelected={$page.route.id === AppRoute.ADMIN_REPAIR} />
</a>
<div class="mb-6 mt-auto">
<StatusBox />

View file

@ -1,11 +1,11 @@
<script lang="ts">
import type Icon from 'svelte-material-icons/AbTesting.svelte';
import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
import { fade } from 'svelte/transition';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiInformationOutline } from '@mdi/js';
export let title: string;
export let logo: typeof Icon;
export let icon: string;
export let isSelected: boolean;
export let flippedLogo = false;
@ -27,7 +27,7 @@
"
>
<div class="flex w-full place-items-center gap-4 overflow-hidden truncate">
<svelte:component this={logo} size="1.5em" class="shrink-0 {flippedLogo ? '-scale-x-100' : ''}" />
<Icon path={icon} size="1.5em" class="shrink-0" flipped={flippedLogo} />
<p class="text-sm font-medium">{title}</p>
</div>
@ -41,7 +41,7 @@
on:mouseleave={() => (showMoreInformation = false)}
>
<div class="p-1 text-gray-600 hover:cursor-help dark:text-gray-400">
<InformationOutline />
<Icon path={mdiInformationOutline} />
</div>
{#if showMoreInformation}

View file

@ -1,25 +1,27 @@
<script lang="ts">
import { page } from '$app/stores';
import { locale, sidebarSettings } from '$lib/stores/preferences.store';
import { featureFlags } from '$lib/stores/server-config.store';
import { AssetApiGetAssetStatsRequest, api } from '@api';
import AccountMultipleOutline from 'svelte-material-icons/AccountMultipleOutline.svelte';
import AccountMultiple from 'svelte-material-icons/AccountMultiple.svelte';
import ImageAlbum from 'svelte-material-icons/ImageAlbum.svelte';
import ImageMultipleOutline from 'svelte-material-icons/ImageMultipleOutline.svelte';
import ImageMultiple from 'svelte-material-icons/ImageMultiple.svelte';
import ArchiveArrowDownOutline from 'svelte-material-icons/ArchiveArrowDownOutline.svelte';
import Magnify from 'svelte-material-icons/Magnify.svelte';
import Map from 'svelte-material-icons/Map.svelte';
import Account from 'svelte-material-icons/Account.svelte';
import TrashCanOutline from 'svelte-material-icons/TrashCanOutline.svelte';
import HeartMultipleOutline from 'svelte-material-icons/HeartMultipleOutline.svelte';
import HeartMultiple from 'svelte-material-icons/HeartMultiple.svelte';
import {
mdiAccount,
mdiAccountMultiple,
mdiAccountMultipleOutline,
mdiArchiveArrowDownOutline,
mdiHeartMultiple,
mdiHeartMultipleOutline,
mdiImageAlbum,
mdiImageMultiple,
mdiImageMultipleOutline,
mdiMagnify,
mdiMap,
mdiTrashCanOutline,
} from '@mdi/js';
import { AppRoute } from '../../../constants';
import LoadingSpinner from '../loading-spinner.svelte';
import StatusBox from '../status-box.svelte';
import SideBarButton from './side-bar-button.svelte';
import { locale, sidebarSettings } from '$lib/stores/preferences.store';
import SideBarSection from './side-bar-section.svelte';
import { featureFlags } from '$lib/stores/server-config.store';
const getStats = async (dto: AssetApiGetAssetStatsRequest) => {
const { data: stats } = await api.assetApi.getAssetStats(dto);
@ -45,7 +47,7 @@
<a data-sveltekit-preload-data="hover" data-sveltekit-noscroll href={AppRoute.PHOTOS} draggable="false">
<SideBarButton
title="Photos"
logo={isPhotosSelected ? ImageMultiple : ImageMultipleOutline}
icon={isPhotosSelected ? mdiImageMultiple : mdiImageMultipleOutline}
isSelected={isPhotosSelected}
>
<svelte:fragment slot="moreInformation">
@ -62,23 +64,23 @@
</a>
{#if $featureFlags.search}
<a data-sveltekit-preload-data="hover" data-sveltekit-noscroll href={AppRoute.EXPLORE} draggable="false">
<SideBarButton title="Explore" logo={Magnify} isSelected={$page.route.id === '/(user)/explore'} />
<SideBarButton title="Explore" icon={mdiMagnify} isSelected={$page.route.id === '/(user)/explore'} />
</a>
{/if}
{#if $featureFlags.map}
<a data-sveltekit-preload-data="hover" href={AppRoute.MAP} draggable="false">
<SideBarButton title="Map" logo={Map} isSelected={$page.route.id === '/(user)/map'} />
<SideBarButton title="Map" icon={mdiMap} isSelected={$page.route.id === '/(user)/map'} />
</a>
{/if}
{#if $sidebarSettings.people}
<a data-sveltekit-preload-data="hover" href={AppRoute.PEOPLE} draggable="false">
<SideBarButton title="People" logo={Account} isSelected={$page.route.id === '/(user)/people'} />
<SideBarButton title="People" icon={mdiAccount} isSelected={$page.route.id === '/(user)/people'} />
</a>
{/if}
<a data-sveltekit-preload-data="hover" href={AppRoute.SHARING} draggable="false">
<SideBarButton
title="Sharing"
logo={isSharingSelected ? AccountMultiple : AccountMultipleOutline}
icon={isSharingSelected ? mdiAccountMultiple : mdiAccountMultipleOutline}
isSelected={isSharingSelected}
>
<svelte:fragment slot="moreInformation">
@ -100,7 +102,7 @@
<a data-sveltekit-preload-data="hover" href={AppRoute.FAVORITES} draggable="false">
<SideBarButton
title="Favorites"
logo={isFavoritesSelected ? HeartMultiple : HeartMultipleOutline}
icon={isFavoritesSelected ? mdiHeartMultiple : mdiHeartMultipleOutline}
isSelected={isFavoritesSelected}
>
<svelte:fragment slot="moreInformation">
@ -116,7 +118,12 @@
</SideBarButton>
</a>
<a data-sveltekit-preload-data="hover" href={AppRoute.ALBUMS} draggable="false">
<SideBarButton title="Albums" logo={ImageAlbum} flippedLogo={true} isSelected={$page.route.id === '/(user)/albums'}>
<SideBarButton
title="Albums"
icon={mdiImageAlbum}
flippedLogo={true}
isSelected={$page.route.id === '/(user)/albums'}
>
<svelte:fragment slot="moreInformation">
{#await getAlbumCount()}
<LoadingSpinner />
@ -129,7 +136,7 @@
</SideBarButton>
</a>
<a data-sveltekit-preload-data="hover" href={AppRoute.ARCHIVE} draggable="false">
<SideBarButton title="Archive" logo={ArchiveArrowDownOutline} isSelected={$page.route.id === '/(user)/archive'}>
<SideBarButton title="Archive" icon={mdiArchiveArrowDownOutline} isSelected={$page.route.id === '/(user)/archive'}>
<svelte:fragment slot="moreInformation">
{#await getStats({ isArchived: true })}
<LoadingSpinner />
@ -145,7 +152,7 @@
{#if $featureFlags.trash}
<a data-sveltekit-preload-data="hover" href={AppRoute.TRASH} draggable="false">
<SideBarButton title="Trash" logo={TrashCanOutline} isSelected={isTrashSelected}>
<SideBarButton title="Trash" icon={mdiTrashCanOutline} isSelected={isTrashSelected}>
<svelte:fragment slot="moreInformation">
{#await getStats({ isTrashed: true })}
<LoadingSpinner />

View file

@ -4,10 +4,10 @@
import { websocketStore } from '$lib/stores/websocket';
import { ServerInfoResponseDto, api } from '@api';
import { onDestroy, onMount } from 'svelte';
import Cloud from 'svelte-material-icons/Cloud.svelte';
import Dns from 'svelte-material-icons/Dns.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { asByteUnitString } from '../../utils/byte-units';
import LoadingSpinner from './loading-spinner.svelte';
import { mdiCloud, mdiDns } from '@mdi/js';
const { serverVersion, connected } = websocketStore;
@ -40,7 +40,7 @@
<div class="dark:text-immich-dark-fg">
<div class="storage-status grid grid-cols-[64px_auto]">
<div class="pb-[2.15rem] pl-5 pr-6 text-immich-primary dark:text-immich-dark-primary group-hover:sm:pb-0 md:pb-0">
<Cloud size={'24'} />
<Icon path={mdiCloud} size={'24'} />
</div>
<div class="hidden group-hover:sm:block md:block">
<p class="text-sm font-medium text-immich-primary dark:text-immich-dark-primary">Storage</p>
@ -68,7 +68,7 @@
</div>
<div class="server-status grid grid-cols-[64px_auto]">
<div class="pb-11 pl-5 pr-6 text-immich-primary dark:text-immich-dark-primary group-hover:sm:pb-0 md:pb-0">
<Dns size={'24'} />
<Icon path={mdiDns} size={'24'} />
</div>
<div class="hidden text-xs group-hover:sm:block md:block">
<p class="text-sm font-medium text-immich-primary dark:text-immich-dark-primary">Server</p>

View file

@ -7,9 +7,9 @@
import ImmichLogo from './immich-logo.svelte';
import { getFilenameExtension } from '$lib/utils/asset-utils';
import { uploadAssetsStore } from '$lib/stores/upload';
import Cancel from 'svelte-material-icons/Cancel.svelte';
import Refresh from 'svelte-material-icons/Refresh.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { fileUploadHandler } from '$lib/utils/file-uploader';
import { mdiRefresh, mdiCancel } from '@mdi/js';
export let uploadAsset: UploadAsset;
@ -84,14 +84,14 @@
title="Retry upload"
class="flex h-full w-full place-content-center place-items-center text-sm"
>
<span class="text-immich-dark-gray dark:text-immich-dark-fg"><Refresh size="20" /></span>
<span class="text-immich-dark-gray dark:text-immich-dark-fg"><Icon path={mdiRefresh} size="20" /></span>
</button>
<button
on:click={() => uploadAssetsStore.removeUploadAsset(uploadAsset.id)}
title="Dismiss error"
class="flex h-full w-full place-content-center place-items-center text-sm"
>
<span class="text-immich-error"><Cancel size="20" /></span>
<span class="text-immich-error"><Icon path={mdiCancel} size="20" /></span>
</button>
</div>
{/if}

View file

@ -2,14 +2,12 @@
import { quartInOut } from 'svelte/easing';
import { fade, scale } from 'svelte/transition';
import { uploadAssetsStore } from '$lib/stores/upload';
import CloudUploadOutline from 'svelte-material-icons/CloudUploadOutline.svelte';
import WindowMinimize from 'svelte-material-icons/WindowMinimize.svelte';
import Cancel from 'svelte-material-icons/Cancel.svelte';
import Cog from 'svelte-material-icons/Cog.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { notificationController, NotificationType } from './notification/notification';
import UploadAssetPreview from './upload-asset-preview.svelte';
import { uploadExecutionQueue } from '$lib/utils/file-uploader';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { mdiCog, mdiWindowMinimize, mdiCancel, mdiCloudUploadOutline } from '@mdi/js';
let showDetail = false;
let showOptions = false;
@ -75,14 +73,14 @@
<div class="flex flex-row">
<CircleIconButton
title="Toggle settings"
logo={Cog}
icon={mdiCog}
size="14"
padding="1"
on:click={() => (showOptions = !showOptions)}
/>
<CircleIconButton
title="Minimize"
logo={WindowMinimize}
icon={mdiWindowMinimize}
size="14"
padding="1"
on:click={() => (showDetail = false)}
@ -91,7 +89,7 @@
{#if $hasError}
<CircleIconButton
title="Dismiss all errors"
logo={Cancel}
icon={mdiCancel}
size="14"
padding="1"
on:click={() => uploadAssetsStore.dismissErrors()}
@ -148,7 +146,7 @@
class="flex h-16 w-16 place-content-center place-items-center rounded-full bg-gray-200 p-5 text-sm text-immich-primary shadow-lg dark:bg-gray-600 dark:text-immich-gray"
>
<div class="animate-pulse">
<CloudUploadOutline size="30" />
<Icon path={mdiCloudUploadOutline} size="30" />
</div>
</button>
</div>

View file

@ -1,14 +1,12 @@
<script lang="ts">
import { api, AssetResponseDto, SharedLinkResponseDto, SharedLinkType, ThumbnailFormat } from '@api';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import OpenInNew from 'svelte-material-icons/OpenInNew.svelte';
import Delete from 'svelte-material-icons/TrashCanOutline.svelte';
import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
import CircleEditOutline from 'svelte-material-icons/CircleEditOutline.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import * as luxon from 'luxon';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { createEventDispatcher } from 'svelte';
import { goto } from '$app/navigation';
import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiOpenInNew } from '@mdi/js';
export let link: SharedLinkResponseDto;
@ -110,7 +108,7 @@
on:click={() => goto(`/share/${link.key}`)}
on:keydown={() => goto(`/share/${link.key}`)}
>
<OpenInNew />
<Icon path={mdiOpenInNew} />
</div>
{/if}
</div>
@ -148,9 +146,9 @@
<div class="flex flex-auto flex-col place-content-center place-items-end text-right">
<div class="flex">
<CircleIconButton logo={Delete} on:click={() => dispatch('delete')} />
<CircleIconButton logo={CircleEditOutline} on:click={() => dispatch('edit')} />
<CircleIconButton logo={ContentCopy} on:click={() => dispatch('copy')} />
<CircleIconButton icon={mdiDelete} on:click={() => dispatch('delete')} />
<CircleIconButton icon={mdiCircleEditOutline} on:click={() => dispatch('edit')} />
<CircleIconButton icon={mdiContentCopy} on:click={() => dispatch('copy')} />
</div>
</div>
</div>

View file

@ -3,14 +3,17 @@
import type { AuthDeviceResponseDto } from '@api';
import { DateTime, ToRelativeCalendarOptions } from 'luxon';
import { createEventDispatcher } from 'svelte';
import Android from 'svelte-material-icons/Android.svelte';
import Apple from 'svelte-material-icons/Apple.svelte';
import AppleSafari from 'svelte-material-icons/AppleSafari.svelte';
import GoogleChrome from 'svelte-material-icons/GoogleChrome.svelte';
import Help from 'svelte-material-icons/Help.svelte';
import Linux from 'svelte-material-icons/Linux.svelte';
import MicrosoftWindows from 'svelte-material-icons/MicrosoftWindows.svelte';
import TrashCanOutline from 'svelte-material-icons/TrashCanOutline.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import {
mdiAndroid,
mdiApple,
mdiAppleSafari,
mdiMicrosoftWindows,
mdiLinux,
mdiGoogleChrome,
mdiTrashCanOutline,
mdiHelp,
} from '@mdi/js';
export let device: AuthDeviceResponseDto;
@ -26,19 +29,19 @@
<!-- TODO: Device Image -->
<div class="hidden items-center justify-center pr-2 text-immich-primary dark:text-immich-dark-primary sm:flex">
{#if device.deviceOS === 'Android'}
<Android size="40" />
<Icon path={mdiAndroid} size="40" />
{:else if device.deviceOS === 'iOS' || device.deviceOS === 'Mac OS'}
<Apple size="40" />
<Icon path={mdiApple} size="40" />
{:else if device.deviceOS.indexOf('Safari') !== -1}
<AppleSafari size="40" />
<Icon path={mdiAppleSafari} size="40" />
{:else if device.deviceOS.indexOf('Windows') !== -1}
<MicrosoftWindows size="40" />
<Icon path={mdiMicrosoftWindows} size="40" />
{:else if device.deviceOS === 'Linux'}
<Linux size="40" />
<Icon path={mdiLinux} size="40" />
{:else if device.deviceOS === 'Chromium OS' || device.deviceType === 'Chrome' || device.deviceType === 'Chromium'}
<GoogleChrome size="40" />
<Icon path={mdiGoogleChrome} size="40" />
{:else}
<Help size="40" />
<Icon path={mdiHelp} size="40" />
{/if}
</div>
<div class="flex grow flex-row justify-between gap-1 pl-4 sm:pl-0">
@ -62,7 +65,7 @@
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
title="Log out"
>
<TrashCanOutline size="16" />
<Icon path={mdiTrashCanOutline} size="16" />
</button>
</div>
{/if}

View file

@ -6,9 +6,7 @@
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
import { handleError } from '$lib/utils/handle-error';
import { fade } from 'svelte/transition';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import Database from 'svelte-material-icons/Database.svelte';
import Upload from 'svelte-material-icons/Upload.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import Pulse from 'svelte-loading-spinners/Pulse.svelte';
import { slide } from 'svelte/transition';
import LibraryImportPathsForm from '../forms/library-import-paths-form.svelte';
@ -19,6 +17,7 @@
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
import { getContextMenuPosition } from '$lib/utils/context-menu';
import { mdiDatabase, mdiDotsVertical, mdiUpload } from '@mdi/js';
let libraries: LibraryResponseDto[] = [];
@ -317,9 +316,9 @@
>
<td class="w-1/6 px-10 text-sm">
{#if library.type === LibraryType.External}
<Database size="40" title="External library (created on {library.createdAt})" />
<Icon path={mdiDatabase} size="40" title="External library (created on {library.createdAt})" />
{:else if library.type === LibraryType.Upload}
<Upload size="40" title="Upload library (created on {library.createdAt})" />
<Icon path={mdiUpload} size="40" title="Upload library (created on {library.createdAt})" />
{/if}</td
>
@ -340,7 +339,7 @@
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
on:click|stopPropagation|preventDefault={(e) => showMenu(e, library, index)}
>
<DotsVertical size="16" />
<Icon path={mdiDotsVertical} size="16" />
</button>
{#if showContextMenu}

View file

@ -1,12 +1,12 @@
<script lang="ts">
import { UserResponseDto, api } from '@api';
import UserAvatar from '../shared-components/user-avatar.svelte';
import Close from 'svelte-material-icons/Close.svelte';
import Button from '../elements/buttons/button.svelte';
import PartnerSelectionModal from './partner-selection-modal.svelte';
import { handleError } from '../../utils/handle-error';
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { mdiClose } from '@mdi/js';
export let user: UserResponseDto;
@ -64,7 +64,7 @@
</div>
<CircleIconButton
on:click={() => (removePartner = partner)}
logo={Close}
icon={mdiClose}
size={'16'}
title="Remove partner"
/>

View file

@ -1,7 +1,6 @@
<script lang="ts">
import { api, APIKeyResponseDto } from '@api';
import PencilOutline from 'svelte-material-icons/PencilOutline.svelte';
import TrashCanOutline from 'svelte-material-icons/TrashCanOutline.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { fade } from 'svelte/transition';
import { handleError } from '../../utils/handle-error';
import APIKeyForm from '../forms/api-key-form.svelte';
@ -10,6 +9,7 @@
import { notificationController, NotificationType } from '../shared-components/notification/notification';
import { locale } from '$lib/stores/preferences.store';
import Button from '../elements/buttons/button.svelte';
import { mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
export let keys: APIKeyResponseDto[];
@ -143,13 +143,13 @@
on:click={() => (editKey = key)}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
>
<PencilOutline size="16" />
<Icon path={mdiPencilOutline} size="16" />
</button>
<button
on:click={() => (deleteKey = key)}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
>
<TrashCanOutline size="16" />
<Icon path={mdiTrashCanOutline} size="16" />
</button>
</td>
</tr>

View file

@ -16,11 +16,7 @@
import { goto } from '$app/navigation';
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import FormatListBulletedSquare from 'svelte-material-icons/FormatListBulletedSquare.svelte';
import ViewGridOutline from 'svelte-material-icons/ViewGridOutline.svelte';
import type { PageData } from './$types';
import PlusBoxOutline from 'svelte-material-icons/PlusBoxOutline.svelte';
import { useAlbums } from './albums.bloc';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
@ -37,13 +33,20 @@
} from '$lib/components/shared-components/notification/notification';
import type { AlbumResponseDto } from '@api';
import TableHeader from '$lib/components/elements/table-header.svelte';
import ArrowDownThin from 'svelte-material-icons/ArrowDownThin.svelte';
import ArrowUpThin from 'svelte-material-icons/ArrowUpThin.svelte';
import PencilOutline from 'svelte-material-icons/PencilOutline.svelte';
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
import EditAlbumForm from '$lib/components/forms/edit-album-form.svelte';
import TrashCanOutline from 'svelte-material-icons/TrashCanOutline.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { orderBy } from 'lodash-es';
import {
mdiPlusBoxOutline,
mdiArrowDownThin,
mdiArrowUpThin,
mdiFormatListBulletedSquare,
mdiPencilOutline,
mdiTrashCanOutline,
mdiViewGridOutline,
mdiDeleteOutline,
} from '@mdi/js';
export let data: PageData;
let shouldShowEditUserForm = false;
@ -210,7 +213,7 @@
<div class="flex place-items-center gap-2" slot="buttons">
<LinkButton on:click={handleCreateAlbum}>
<div class="flex place-items-center gap-2 text-sm">
<PlusBoxOutline size="18" />
<Icon path={mdiPlusBoxOutline} size="18" />
Create album
</div>
</LinkButton>
@ -220,7 +223,7 @@
render={(option) => {
return {
title: option.sortTitle,
icon: option.sortDesc ? ArrowDownThin : ArrowUpThin,
icon: option.sortDesc ? mdiArrowDownThin : mdiArrowUpThin,
};
}}
on:select={(event) => {
@ -236,10 +239,10 @@
<LinkButton on:click={() => handleChangeListMode()}>
<div class="flex place-items-center gap-2 text-sm">
{#if $albumViewSettings.view === AlbumViewMode.List}
<ViewGridOutline size="18" />
<Icon path={mdiViewGridOutline} size="18" />
<p class="hidden sm:block">Cover</p>
{:else}
<FormatListBulletedSquare size="18" />
<Icon path={mdiFormatListBulletedSquare} size="18" />
<p class="hidden sm:block">List</p>
{/if}
</div>
@ -293,13 +296,13 @@
on:click|stopPropagation={() => handleEdit(album)}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
>
<PencilOutline size="16" />
<Icon path={mdiPencilOutline} size="16" />
</button>
<button
on:click|stopPropagation={() => chooseAlbumToDelete(album)}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
>
<TrashCanOutline size="16" />
<Icon path={mdiTrashCanOutline} size="16" />
</button>
</td>
</tr>
@ -323,7 +326,7 @@
<ContextMenu {...$contextMenuPosition} on:outclick={closeAlbumContextMenu} on:escape={closeAlbumContextMenu}>
<MenuOption on:click={() => setAlbumToDelete()}>
<span class="flex place-content-center place-items-center gap-2">
<DeleteOutline size="18" />
<Icon path={mdiDeleteOutline} size="18" />
<p>Delete album</p>
</span>
</MenuOption>

View file

@ -35,17 +35,20 @@
import { openFileUploadDialog } from '$lib/utils/file-uploader';
import { handleError } from '$lib/utils/handle-error';
import { TimeBucketSize, UserResponseDto, api } from '@api';
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import FileImagePlusOutline from 'svelte-material-icons/FileImagePlusOutline.svelte';
import FolderDownloadOutline from 'svelte-material-icons/FolderDownloadOutline.svelte';
import Link from 'svelte-material-icons/Link.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import ShareVariantOutline from 'svelte-material-icons/ShareVariantOutline.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { PageData } from './$types';
import { clickOutside } from '$lib/utils/click-outside';
import { getContextMenuPosition } from '$lib/utils/context-menu';
import {
mdiPlus,
mdiDotsVertical,
mdiArrowLeft,
mdiFileImagePlusOutline,
mdiShareVariantOutline,
mdiDeleteOutline,
mdiFolderDownloadOutline,
mdiLink,
} from '@mdi/js';
export let data: PageData;
@ -313,11 +316,11 @@
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
<CreateSharedLink />
<SelectAllAssets {assetStore} {assetInteractionStore} />
<AssetSelectContextMenu icon={Plus} title="Add">
<AssetSelectContextMenu icon={mdiPlus} title="Add">
<AddToAlbum />
<AddToAlbum shared />
</AssetSelectContextMenu>
<AssetSelectContextMenu icon={DotsVertical} title="Menu">
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
{#if isAllUserOwned}
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
{/if}
@ -333,33 +336,33 @@
</AssetSelectControlBar>
{:else}
{#if viewMode === ViewMode.VIEW || viewMode === ViewMode.ALBUM_OPTIONS}
<ControlAppBar showBackButton backIcon={ArrowLeft} on:close-button-click={() => goto(backUrl)}>
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close-button-click={() => goto(backUrl)}>
<svelte:fragment slot="trailing">
<CircleIconButton
title="Add Photos"
on:click={() => (viewMode = ViewMode.SELECT_ASSETS)}
logo={FileImagePlusOutline}
icon={mdiFileImagePlusOutline}
/>
{#if isOwned}
<CircleIconButton
title="Share"
on:click={() => (viewMode = ViewMode.SELECT_USERS)}
logo={ShareVariantOutline}
icon={mdiShareVariantOutline}
/>
<CircleIconButton
title="Delete album"
on:click={() => (viewMode = ViewMode.CONFIRM_DELETE)}
logo={DeleteOutline}
icon={mdiDeleteOutline}
/>
{/if}
{#if album.assetCount > 0}
<CircleIconButton title="Download" on:click={handleDownloadAlbum} logo={FolderDownloadOutline} />
<CircleIconButton title="Download" on:click={handleDownloadAlbum} icon={mdiFolderDownloadOutline} />
{#if isOwned}
<div use:clickOutside on:outclick={() => (viewMode = ViewMode.VIEW)}>
<CircleIconButton title="Album options" on:click={handleOpenAlbumOptions} logo={DotsVertical}>
<CircleIconButton title="Album options" on:click={handleOpenAlbumOptions} icon={mdiDotsVertical}>
{#if viewMode === ViewMode.ALBUM_OPTIONS}
<ContextMenu {...contextMenuPosition}>
<MenuOption on:click={() => (viewMode = ViewMode.SELECT_THUMBNAIL)} text="Set album cover" />
@ -465,7 +468,7 @@
backgroundColor="#d3d3d3"
forceDark
size="20"
logo={Link}
icon={mdiLink}
on:click={() => (viewMode = ViewMode.LINK_SHARING)}
/>
{/if}
@ -487,7 +490,7 @@
backgroundColor="#d3d3d3"
forceDark
size="20"
logo={Plus}
icon={mdiPlus}
on:click={() => (viewMode = ViewMode.SELECT_USERS)}
title="Add more users"
/>
@ -518,7 +521,9 @@
on:click={() => (viewMode = ViewMode.SELECT_ASSETS)}
class="mt-5 flex w-full place-items-center gap-6 rounded-md border bg-immich-bg px-8 py-8 text-immich-fg transition-all hover:bg-gray-100 hover:text-immich-primary dark:border-none dark:bg-immich-dark-gray dark:text-immich-dark-fg dark:hover:text-immich-dark-primary"
>
<span class="text-text-immich-primary dark:text-immich-dark-primary"><Plus size="24" /> </span>
<span class="text-text-immich-primary dark:text-immich-dark-primary"
><Icon path={mdiPlus} size="24" />
</span>
<span class="text-lg">Select photos</span>
</button>
</div>

View file

@ -15,9 +15,8 @@
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
import { AssetStore } from '$lib/stores/assets.store';
import { TimeBucketSize } from '@api';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import type { PageData } from './$types';
import { mdiPlus, mdiDotsVertical } from '@mdi/js';
export let data: PageData;
@ -33,12 +32,12 @@
<ArchiveAction unarchive onArchive={(ids) => assetStore.removeAssets(ids)} />
<CreateSharedLink />
<SelectAllAssets {assetStore} {assetInteractionStore} />
<AssetSelectContextMenu icon={Plus} title="Add">
<AssetSelectContextMenu icon={mdiPlus} title="Add">
<AddToAlbum />
<AddToAlbum shared />
</AssetSelectContextMenu>
<DeleteAssets onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
<AssetSelectContextMenu icon={DotsVertical} title="Add">
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
<DownloadAction menuItem />
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
</AssetSelectContextMenu>

View file

@ -4,12 +4,15 @@
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import { AppRoute } from '$lib/constants';
import { AssetTypeEnum, SearchExploreResponseDto, api } from '@api';
import ClockOutline from 'svelte-material-icons/ClockOutline.svelte';
import HeartMultipleOutline from 'svelte-material-icons/HeartMultipleOutline.svelte';
import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
import PlayCircleOutline from 'svelte-material-icons/PlayCircleOutline.svelte';
import Rotate360Icon from 'svelte-material-icons/Rotate360.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { PageData } from './$types';
import {
mdiHeartMultipleOutline,
mdiClockOutline,
mdiPlayCircleOutline,
mdiMotionPlayOutline,
mdiRotate360,
} from '@mdi/js';
export let data: PageData;
@ -118,7 +121,7 @@
class="flex w-full content-center gap-2 text-sm font-medium hover:text-immich-primary dark:hover:text-immich-dark-primary"
draggable="false"
>
<HeartMultipleOutline size={24} />
<Icon path={mdiHeartMultipleOutline} size={24} />
<span>Favorites</span>
</a>
<a
@ -126,7 +129,7 @@
class="flex w-full content-center gap-2 text-sm font-medium hover:text-immich-primary dark:hover:text-immich-dark-primary"
draggable="false"
>
<ClockOutline size={24} />
<Icon path={mdiClockOutline} size={24} />
<span>Recently added</span>
</a>
</div>
@ -138,7 +141,7 @@
href="/search?type={AssetTypeEnum.Video}"
class="flex w-full items-center gap-2 text-sm font-medium hover:text-immich-primary dark:hover:text-immich-dark-primary"
>
<PlayCircleOutline size={24} />
<Icon path={mdiPlayCircleOutline} size={24} />
<span>Videos</span>
</a>
<div>
@ -146,7 +149,7 @@
href="/search?motion=true"
class="flex w-full items-center gap-2 text-sm font-medium hover:text-immich-primary dark:hover:text-immich-dark-primary"
>
<MotionPlayOutline size={24} />
<Icon path={mdiMotionPlayOutline} size={24} />
<span>Motion photos</span>
</a>
</div>
@ -155,7 +158,7 @@
href="/search?exifInfo.projectionType=EQUIRECTANGULAR"
class="flex w-full items-center gap-2 text-sm font-medium hover:text-immich-primary dark:hover:text-immich-dark-primary"
>
<Rotate360Icon size={24} />
<Icon path={mdiRotate360} size={24} />
<span>Panorama photos</span>
</a>
</div>

View file

@ -15,9 +15,8 @@
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
import { AssetStore } from '$lib/stores/assets.store';
import { TimeBucketSize } from '@api';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import type { PageData } from './$types';
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
export let data: PageData;
@ -34,12 +33,12 @@
<FavoriteAction removeFavorite onFavorite={(ids) => assetStore.removeAssets(ids)} />
<CreateSharedLink />
<SelectAllAssets {assetStore} {assetInteractionStore} />
<AssetSelectContextMenu icon={Plus} title="Add">
<AssetSelectContextMenu icon={mdiPlus} title="Add">
<AddToAlbum />
<AddToAlbum shared />
</AssetSelectContextMenu>
<DeleteAssets onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
<AssetSelectContextMenu icon={DotsVertical} title="Menu">
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
<DownloadAction menuItem />
<ArchiveAction menuItem unarchive={isAllArchive} />
</AssetSelectContextMenu>

View file

@ -12,8 +12,9 @@
import { isEqual, omit } from 'lodash-es';
import { DateTime, Duration } from 'luxon';
import { onDestroy, onMount } from 'svelte';
import Cog from 'svelte-material-icons/Cog.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { PageData } from './$types';
import { mdiCog } from '@mdi/js';
export let data: PageData;
@ -135,7 +136,7 @@
title="Open map settings"
on:click={() => (showSettingsModal = true)}
>
<Cog size="100%" class="p-1" />
<Icon path={mdiCog} size="100%" class="p-1" />
</button>
</Control>
</Map>

View file

@ -12,9 +12,8 @@
import { AssetStore } from '$lib/stores/assets.store';
import { TimeBucketSize } from '@api';
import { onDestroy } from 'svelte';
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import type { PageData } from './$types';
import { mdiPlus, mdiArrowLeft } from '@mdi/js';
export let data: PageData;
@ -31,14 +30,14 @@
{#if $isMultiSelectState}
<AssetSelectControlBar assets={$selectedAssets} clearSelect={assetInteractionStore.clearMultiselect}>
<CreateSharedLink />
<AssetSelectContextMenu icon={Plus} title="Add">
<AssetSelectContextMenu icon={mdiPlus} title="Add">
<AddToAlbum />
<AddToAlbum shared />
</AssetSelectContextMenu>
<DownloadAction />
</AssetSelectControlBar>
{:else}
<ControlAppBar showBackButton backIcon={ArrowLeft} on:close-button-click={() => goto(AppRoute.SHARING)}>
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close-button-click={() => goto(AppRoute.SHARING)}>
<svelte:fragment slot="leading">
<p class="whitespace-nowrap text-immich-fg dark:text-immich-dark-fg">
{data.partner.firstName}

View file

@ -1,6 +1,5 @@
<script lang="ts">
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import AccountOff from 'svelte-material-icons/AccountOff.svelte';
import type { PageData } from './$types';
import PeopleCard from '$lib/components/faces-page/people-card.svelte';
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
@ -15,19 +14,20 @@
} from '$lib/components/shared-components/notification/notification';
import ShowHide from '$lib/components/faces-page/show-hide.svelte';
import IconButton from '$lib/components/elements/buttons/icon-button.svelte';
import EyeOutline from 'svelte-material-icons/EyeOutline.svelte';
import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
import { onDestroy, onMount } from 'svelte';
import { browser } from '$app/environment';
import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte';
import SetBirthDateModal from '$lib/components/faces-page/set-birth-date-modal.svelte';
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
import { mdiAccountOff, mdiEyeOutline } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let data: PageData;
let selectHidden = false;
let initialHiddenValues: Record<string, boolean> = {};
let eyeColorMap: Record<string, string> = {};
let eyeColorMap: Record<string, 'black' | 'white'> = {};
let people = data.people.people;
let countTotalPeople = data.people.total;
@ -362,7 +362,7 @@
{#if countTotalPeople > 0}
<IconButton on:click={() => (selectHidden = !selectHidden)}>
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
<EyeOutline size="18" />
<Icon path={mdiEyeOutline} size="18" />
<p class="ml-2">Show & hide faces</p>
</div>
</IconButton>
@ -388,7 +388,7 @@
{:else}
<div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white">
<div class="flex flex-col content-center items-center text-center">
<AccountOff size="3.5em" />
<Icon path={mdiAccountOff} size="3.5em" />
<p class="mt-5 text-3xl font-medium">No people</p>
</div>
</div>

View file

@ -29,13 +29,11 @@
import { handleError } from '$lib/utils/handle-error';
import { AssetResponseDto, PersonResponseDto, TimeBucketSize, api } from '@api';
import { onMount } from 'svelte';
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import type { PageData } from './$types';
import { clickOutside } from '$lib/utils/click-outside';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import { mdiPlus, mdiDotsVertical, mdiArrowLeft } from '@mdi/js';
export let data: PageData;
@ -370,12 +368,12 @@
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
<CreateSharedLink />
<SelectAllAssets {assetStore} {assetInteractionStore} />
<AssetSelectContextMenu icon={Plus} title="Add">
<AssetSelectContextMenu icon={mdiPlus} title="Add">
<AddToAlbum />
<AddToAlbum shared />
</AssetSelectContextMenu>
<DeleteAssets onAssetDelete={(assetId) => $assetStore.removeAsset(assetId)} />
<AssetSelectContextMenu icon={DotsVertical} title="Add">
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
<DownloadAction menuItem filename="{data.person.name || 'immich'}.zip" />
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
<ArchiveAction menuItem unarchive={isAllArchive} onArchive={(ids) => $assetStore.removeAssets(ids)} />
@ -383,9 +381,9 @@
</AssetSelectControlBar>
{:else}
{#if viewMode === ViewMode.VIEW_ASSETS || viewMode === ViewMode.SUGGEST_MERGE || viewMode === ViewMode.BIRTH_DATE}
<ControlAppBar showBackButton backIcon={ArrowLeft} on:close-button-click={() => goto(previousRoute)}>
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close-button-click={() => goto(previousRoute)}>
<svelte:fragment slot="trailing">
<AssetSelectContextMenu icon={DotsVertical} title="Menu">
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
<MenuOption text="Change feature photo" on:click={() => (viewMode = ViewMode.SELECT_FACE)} />
<MenuOption text="Set date of birth" on:click={() => (viewMode = ViewMode.BIRTH_DATE)} />
<MenuOption text="Merge face" on:click={() => (viewMode = ViewMode.MERGE_FACES)} />

View file

@ -18,10 +18,9 @@
import { AssetStore } from '$lib/stores/assets.store';
import { openFileUploadDialog } from '$lib/utils/file-uploader';
import { TimeBucketSize } from '@api';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import type { PageData } from './$types';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
export let data: PageData;
@ -52,7 +51,7 @@
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
<CreateSharedLink on:escape={() => (handleEscapeKey = true)} />
<SelectAllAssets {assetStore} {assetInteractionStore} />
<AssetSelectContextMenu icon={Plus} title="Add">
<AssetSelectContextMenu icon={mdiPlus} title="Add">
<AddToAlbum />
<AddToAlbum shared />
</AssetSelectContextMenu>
@ -60,7 +59,7 @@
on:escape={() => (handleEscapeKey = true)}
onAssetDelete={(assetId) => assetStore.removeAsset(assetId)}
/>
<AssetSelectContextMenu icon={DotsVertical} title="Menu">
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
<DownloadAction menuItem />
<ArchiveAction menuItem onArchive={(ids) => assetStore.removeAssets(ids)} />

View file

@ -13,12 +13,8 @@
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
import type { AssetResponseDto } from '@api';
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import ImageOffOutline from 'svelte-material-icons/ImageOffOutline.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import type { PageData } from './$types';
import SelectAll from 'svelte-material-icons/SelectAll.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { AppRoute } from '$lib/constants';
import AlbumCard from '$lib/components/album-page/album-card.svelte';
@ -28,6 +24,7 @@
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { preventRaceConditionSearchBar } from '$lib/stores/search.store';
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
import { mdiArrowLeft, mdiDotsVertical, mdiImageOffOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
export let data: PageData;
@ -109,21 +106,21 @@
{#if isMultiSelectionMode}
<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}>
<CreateSharedLink />
<CircleIconButton title="Select all" logo={SelectAll} on:click={handleSelectAll} />
<AssetSelectContextMenu icon={Plus} title="Add">
<CircleIconButton title="Select all" icon={mdiSelectAll} on:click={handleSelectAll} />
<AssetSelectContextMenu icon={mdiPlus} title="Add">
<AddToAlbum />
<AddToAlbum shared />
</AssetSelectContextMenu>
<DeleteAssets {onAssetDelete} />
<AssetSelectContextMenu icon={DotsVertical} title="Add">
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
<DownloadAction menuItem />
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
<ArchiveAction menuItem unarchive={isAllArchived} />
</AssetSelectContextMenu>
</AssetSelectControlBar>
{:else}
<ControlAppBar on:close-button-click={() => goto(previousRoute)} backIcon={ArrowLeft}>
<ControlAppBar on:close-button-click={() => goto(previousRoute)} backIcon={mdiArrowLeft}>
<div class="w-full flex-1 pl-4">
<SearchBar grayTheme={false} value={term} />
</div>
@ -155,7 +152,7 @@
{:else}
<div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white">
<div class="flex flex-col content-center items-center text-center">
<ImageOffOutline size="3.5em" />
<Icon path={mdiImageOffOutline} size="3.5em" />
<p class="mt-5 text-3xl font-medium">No results</p>
<p class="text-base font-normal">Try a synonym or more general keyword</p>
</div>

View file

@ -12,10 +12,10 @@
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
import { AppRoute } from '$lib/constants';
import { api } from '@api';
import Link from 'svelte-material-icons/Link.svelte';
import PlusBoxOutline from 'svelte-material-icons/PlusBoxOutline.svelte';
import { flip } from 'svelte/animate';
import type { PageData } from './$types';
import { mdiLink, mdiPlusBoxOutline } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let data: PageData;
@ -43,14 +43,14 @@
<div class="flex" slot="buttons">
<LinkButton on:click={createSharedAlbum}>
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
<PlusBoxOutline size="18" class="shrink-0" />
<Icon path={mdiPlusBoxOutline} size="18" class="shrink-0" />
<span class="leading-none max-sm:text-xs">Create shared album</span>
</div>
</LinkButton>
<LinkButton on:click={() => goto(AppRoute.SHARED_LINKS)}>
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
<Link size="18" class="shrink-0" />
<Icon path={mdiLink} size="18" class="shrink-0" />
<span class="leading-none max-sm:text-xs">Shared links</span>
</div>
</LinkButton>

View file

@ -1,6 +1,5 @@
<script lang="ts">
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
import { api, copyToClipboard, SharedLinkResponseDto } from '@api';
import { goto } from '$app/navigation';
import SharedLinkCard from '$lib/components/sharedlinks-page/shared-link-card.svelte';
@ -13,6 +12,7 @@
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
import { handleError } from '$lib/utils/handle-error';
import { AppRoute } from '$lib/constants';
import { mdiArrowLeft } from '@mdi/js';
let sharedLinks: SharedLinkResponseDto[] = [];
let editSharedLink: SharedLinkResponseDto | null = null;
@ -53,7 +53,7 @@
};
</script>
<ControlAppBar backIcon={ArrowLeft} on:close-button-click={() => goto(AppRoute.SHARING)}>
<ControlAppBar backIcon={mdiArrowLeft} on:close-button-click={() => goto(AppRoute.SHARING)}>
<svelte:fragment slot="leading">Shared links</svelte:fragment>
</ControlAppBar>

View file

@ -16,13 +16,13 @@
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import { AssetStore } from '$lib/stores/assets.store';
import { api, TimeBucketSize } from '@api';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import HistoryOutline from 'svelte-material-icons/History.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { PageData } from './$types';
import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
import { goto } from '$app/navigation';
import empty3Url from '$lib/assets/empty-3.svg';
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
import { mdiDeleteOutline, mdiHistory } from '@mdi/js';
export let data: PageData;
@ -74,13 +74,13 @@
<div class="flex place-items-center gap-2" slot="buttons">
<LinkButton on:click={handleRestoreTrash}>
<div class="flex place-items-center gap-2 text-sm">
<HistoryOutline size="18" />
<Icon path={mdiHistory} size="18" />
Restore All
</div>
</LinkButton>
<LinkButton on:click={() => (isShowEmptyConfirmation = true)}>
<div class="flex place-items-center gap-2 text-sm">
<DeleteOutline size="18" />
<Icon path={mdiDeleteOutline} size="18" />
Empty Trash
</div>
</LinkButton>

View file

@ -1,10 +1,8 @@
<script>
import { page } from '$app/stores';
import Icon from '$lib/components/elements/icon.svelte';
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
import CodeTags from 'svelte-material-icons/CodeTags.svelte';
import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
import Message from 'svelte-material-icons/Message.svelte';
import PartyPopper from 'svelte-material-icons/PartyPopper.svelte';
import { mdiCodeTags, mdiContentCopy, mdiMessage, mdiPartyPopper } from '@mdi/js';
import { copyToClipboard } from '../api/utils';
const handleCopy = async () => {
@ -43,7 +41,7 @@
on:click={() => handleCopy()}
class="rounded-full bg-immich-primary px-3 py-2 text-sm text-white shadow-md transition-colors hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-immich-dark-gray dark:hover:bg-immich-dark-primary/80"
>
<ContentCopy size={24} />
<Icon path={mdiContentCopy} size={24} />
</button>
</div>
</div>
@ -71,7 +69,7 @@
class="flex grow basis-0 justify-center p-4"
>
<button class="flex flex-col place-content-center place-items-center gap-2">
<Message size={24} />
<Icon path={mdiMessage} size={24} />
<p class="text-sm">Get Help</p>
</button>
</a>
@ -83,7 +81,7 @@
class="flex grow basis-0 justify-center p-4"
>
<button class="flex flex-col place-content-center place-items-center gap-2">
<PartyPopper size={24} />
<Icon path={mdiPartyPopper} size={24} />
<p class="text-sm">Read Changelog</p>
</button>
</a>
@ -95,7 +93,7 @@
class="flex grow basis-0 justify-center p-4"
>
<button class="flex flex-col place-content-center place-items-center gap-2">
<CodeTags size={24} />
<Icon path={mdiCodeTags} size={24} />
<p class="text-sm">Check Logs</p>
</button>
</a>

View file

@ -5,8 +5,9 @@
import { AppRoute } from '$lib/constants';
import { AllJobStatusResponseDto, api } from '@api';
import { onDestroy, onMount } from 'svelte';
import CogIcon from 'svelte-material-icons/Cog.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { PageData } from './$types';
import { mdiCog } from '@mdi/js';
export let data: PageData;
@ -34,7 +35,7 @@
<a href="{AppRoute.ADMIN_SETTINGS}?open=job-settings">
<LinkButton>
<div class="flex place-items-center gap-2 text-sm">
<CogIcon size="18" />
<Icon path={mdiCog} size="18" />
Manage Concurrency
</div>
</LinkButton>

View file

@ -12,12 +12,9 @@
import { downloadBlob } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
import { FileReportItemDto, api, copyToClipboard } from '@api';
import CheckAll from 'svelte-material-icons/CheckAll.svelte';
import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
import Download from 'svelte-material-icons/Download.svelte';
import Refresh from 'svelte-material-icons/Refresh.svelte';
import Wrench from 'svelte-material-icons/Wrench.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { PageData } from './$types';
import { mdiWrench, mdiCheckAll, mdiDownload, mdiRefresh, mdiContentCopy } from '@mdi/js';
export let data: PageData;
@ -178,25 +175,25 @@
<div class="flex justify-end gap-2" slot="buttons">
<LinkButton on:click={() => handleRepair()} disabled={matches.length === 0 || repairing}>
<div class="flex place-items-center gap-2 text-sm">
<Wrench size="18" />
<Icon path={mdiWrench} size="18" />
Repair All
</div>
</LinkButton>
<LinkButton on:click={() => handleCheckAll()} disabled={extras.length === 0 || checking}>
<div class="flex place-items-center gap-2 text-sm">
<CheckAll size="18" />
<Icon path={mdiCheckAll} size="18" />
Check All
</div>
</LinkButton>
<LinkButton on:click={() => handleDownload()} disabled={extras.length + orphans.length === 0}>
<div class="flex place-items-center gap-2 text-sm">
<Download size="18" />
<Icon path={mdiDownload} size="18" />
Export
</div>
</LinkButton>
<LinkButton on:click={() => handleRefresh()}>
<div class="flex place-items-center gap-2 text-sm">
<Refresh size="18" />
<Icon path={mdiRefresh} size="18" />
Refresh
</div>
</LinkButton>
@ -273,7 +270,7 @@
title={orphan.pathValue}
>
<td on:click={() => copyToClipboard(orphan.pathValue)}>
<CircleIconButton logo={ContentCopy} size="18" />
<CircleIconButton icon={mdiContentCopy} size="18" />
</td>
<td class="truncate text-sm font-mono text-left" title={orphan.pathValue}>
{orphan.pathValue}
@ -313,7 +310,7 @@
title={extra.filename}
>
<td on:click={() => copyToClipboard(extra.filename)}>
<CircleIconButton logo={ContentCopy} size="18" />
<CircleIconButton icon={mdiContentCopy} size="18" />
</td>
<td class="w-full text-md text-ellipsis flex justify-between pr-5">
<span class="text-ellipsis grow truncate font-mono text-sm pr-5" title={extra.filename}

View file

@ -17,11 +17,10 @@
import { featureFlags } from '$lib/stores/server-config.store';
import { downloadBlob } from '$lib/utils/asset-utils';
import { copyToClipboard } from '@api';
import Alert from 'svelte-material-icons/Alert.svelte';
import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
import Download from 'svelte-material-icons/Download.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import type { PageData } from './$types';
import NewVersionCheckSettings from '$lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte';
import { mdiAlert, mdiContentCopy, mdiDownload } from '@mdi/js';
export let data: PageData;
@ -39,7 +38,7 @@
{#if $featureFlags.configFile}
<div class="mb-8 flex flex-row items-center gap-2 rounded-md bg-gray-100 p-3 dark:bg-gray-800">
<Alert class="text-yellow-400" size={18} />
<Icon path={mdiAlert} class="text-yellow-400" size={18} />
<h2 class="text-md text-immich-primary dark:text-immich-dark-primary">Config is currently set by a config file</h2>
</div>
{/if}
@ -48,13 +47,13 @@
<div class="flex justify-end gap-2" slot="buttons">
<LinkButton on:click={() => copyToClipboard(JSON.stringify(configs, null, 2))}>
<div class="flex place-items-center gap-2 text-sm">
<ContentCopy size="18" />
<Icon path={mdiContentCopy} size="18" />
Copy to Clipboard
</div>
</LinkButton>
<LinkButton on:click={() => downloadConfig()}>
<div class="flex place-items-center gap-2 text-sm">
<Download size="18" />
<Icon path={mdiDownload} size="18" />
Export as JSON
</div>
</LinkButton>

View file

@ -1,12 +1,7 @@
<script lang="ts">
import { api, UserResponseDto } from '@api';
import { onMount } from 'svelte';
import PencilOutline from 'svelte-material-icons/PencilOutline.svelte';
import TrashCanOutline from 'svelte-material-icons/TrashCanOutline.svelte';
import DeleteRestore from 'svelte-material-icons/DeleteRestore.svelte';
import Check from 'svelte-material-icons/Check.svelte';
import Close from 'svelte-material-icons/Close.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
import CreateUserForm from '$lib/components/forms/create-user-form.svelte';
import EditUserForm from '$lib/components/forms/edit-user-form.svelte';
@ -17,6 +12,7 @@
import Button from '$lib/components/elements/buttons/button.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import type { PageData } from './$types';
import { mdiCheck, mdiClose, mdiDeleteRestore, mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
export let data: PageData;
@ -196,9 +192,9 @@
<td class="w-2/12 text-ellipsis break-all px-2 text-sm">
<div class="container mx-auto flex flex-wrap justify-center">
{#if user.externalPath}
<Check size="16" />
<Icon path={mdiCheck} size="16" />
{:else}
<Close size="16" />
<Icon path={mdiClose} size="16" />
{/if}
</div>
</td>
@ -208,14 +204,14 @@
on:click={() => editUserHandler(user)}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
>
<PencilOutline size="16" />
<Icon path={mdiPencilOutline} size="16" />
</button>
{#if user.id !== data.user.id}
<button
on:click={() => deleteUserHandler(user)}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
>
<TrashCanOutline size="16" />
<Icon path={mdiTrashCanOutline} size="16" />
</button>
{/if}
{/if}
@ -225,7 +221,7 @@
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
title={`scheduled removal on ${getDeleteDate(user)}`}
>
<DeleteRestore size="16" />
<Icon path={mdiDeleteRestore} size="16" />
</button>
{/if}
</td>
@ -265,13 +261,13 @@
on:click={() => editUserHandler(user)}
class="rounded-full bg-immich-primary p-2 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700 max-sm:mb-1 sm:p-3"
>
<PencilOutline size="16" />
<Icon path={mdiPencilOutline} size="16" />
</button>
<button
on:click={() => deleteUserHandler(user)}
class="rounded-full bg-immich-primary p-2 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700 sm:p-3"
>
<TrashCanOutline size="16" />
<Icon path={mdiTrashCanOutline} size="16" />
</button>
{/if}
{#if isDeleted(user)}
@ -280,7 +276,7 @@
class="rounded-full bg-immich-primary p-2 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700 sm:p-3"
title={`scheduled removal on ${getDeleteDate(user)}`}
>
<DeleteRestore size="16" />
<Icon path={mdiDeleteRestore} size="16" />
</button>
{/if}
</td>