forked from Cutlery/immich
refactor(web): material icons (#4636)
This commit is contained in:
parent
d5e19e45cd
commit
2ad389f64e
@ -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
|
// 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
|
// 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,
|
// unmockedModulePathPatterns: undefined,
|
||||||
|
26
web/package-lock.json
generated
26
web/package-lock.json
generated
@ -9,6 +9,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@egjs/svelte-view360": "^4.0.0-beta.7",
|
"@egjs/svelte-view360": "^4.0.0-beta.7",
|
||||||
|
"@mdi/js": "^7.3.67",
|
||||||
"@zoom-image/svelte": "^0.1.8",
|
"@zoom-image/svelte": "^0.1.8",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
@ -23,7 +24,6 @@
|
|||||||
"socket.io-client": "^4.6.1",
|
"socket.io-client": "^4.6.1",
|
||||||
"svelte-loading-spinners": "^0.3.4",
|
"svelte-loading-spinners": "^0.3.4",
|
||||||
"svelte-local-storage-store": "^0.5.0",
|
"svelte-local-storage-store": "^0.5.0",
|
||||||
"svelte-material-icons": "^3.0.5",
|
|
||||||
"thumbhash": "^0.1.1"
|
"thumbhash": "^0.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -3197,6 +3197,11 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@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": {
|
"node_modules/@namnode/store": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@namnode/store/-/store-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@namnode/store/-/store-0.1.0.tgz",
|
||||||
@ -11418,14 +11423,6 @@
|
|||||||
"svelte": "^3.48.0 || ^4.0.0"
|
"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": {
|
"node_modules/svelte-preprocess": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz",
|
||||||
@ -14495,6 +14492,11 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@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": {
|
"@namnode/store": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@namnode/store/-/store-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@namnode/store/-/store-0.1.0.tgz",
|
||||||
@ -20512,12 +20514,6 @@
|
|||||||
"integrity": "sha512-SEDrpapeia6fUqta+r1NvSLlJYPkZ4pBcl15EYIOSPNzy6vhpoXu8cnzUDmZxsWl7fZGAHxrVH9UyZCbyO4W+g==",
|
"integrity": "sha512-SEDrpapeia6fUqta+r1NvSLlJYPkZ4pBcl15EYIOSPNzy6vhpoXu8cnzUDmZxsWl7fZGAHxrVH9UyZCbyO4W+g==",
|
||||||
"requires": {}
|
"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": {
|
"svelte-preprocess": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz",
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@egjs/svelte-view360": "^4.0.0-beta.7",
|
"@egjs/svelte-view360": "^4.0.0-beta.7",
|
||||||
|
"@mdi/js": "^7.3.67",
|
||||||
"@zoom-image/svelte": "^0.1.8",
|
"@zoom-image/svelte": "^0.1.8",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
@ -76,7 +77,6 @@
|
|||||||
"socket.io-client": "^4.6.1",
|
"socket.io-client": "^4.6.1",
|
||||||
"svelte-loading-spinners": "^0.3.4",
|
"svelte-loading-spinners": "^0.3.4",
|
||||||
"svelte-local-storage-store": "^0.5.0",
|
"svelte-local-storage-store": "^0.5.0",
|
||||||
"svelte-material-icons": "^3.0.5",
|
|
||||||
"thumbhash": "^0.1.1"
|
"thumbhash": "^0.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,27 @@
|
|||||||
<script lang="ts">
|
<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 { locale } from '$lib/stores/preferences.store';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { JobCommand, JobCommandDto, JobCountsDto, QueueStatusDto } from '@api';
|
import { JobCommand, JobCommandDto, JobCountsDto, QueueStatusDto } from '@api';
|
||||||
import Badge from '$lib/components/elements/badge.svelte';
|
import Badge from '$lib/components/elements/badge.svelte';
|
||||||
import JobTileButton from './job-tile-button.svelte';
|
import JobTileButton from './job-tile-button.svelte';
|
||||||
import JobTileStatus from './job-tile-status.svelte';
|
import JobTileStatus from './job-tile-status.svelte';
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
import {
|
||||||
|
mdiAlertCircle,
|
||||||
|
mdiAllInclusive,
|
||||||
|
mdiClose,
|
||||||
|
mdiFastForward,
|
||||||
|
mdiPause,
|
||||||
|
mdiPlay,
|
||||||
|
mdiSelectionSearch,
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
export let title: string;
|
export let title: string;
|
||||||
export let subtitle: string | undefined = undefined;
|
export let subtitle: string | undefined = undefined;
|
||||||
export let jobCounts: JobCountsDto;
|
export let jobCounts: JobCountsDto;
|
||||||
export let queueStatus: QueueStatusDto;
|
export let queueStatus: QueueStatusDto;
|
||||||
export let allowForceCommand = true;
|
export let allowForceCommand = true;
|
||||||
export let icon: typeof Icon;
|
export let icon: string;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
|
|
||||||
export let allText: string;
|
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 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">
|
<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">
|
<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()}
|
{title.toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@ -102,12 +104,12 @@
|
|||||||
color="light-gray"
|
color="light-gray"
|
||||||
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
|
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
|
||||||
>
|
>
|
||||||
<AlertCircle size="36" /> DISABLED
|
<Icon path={mdiAlertCircle} size="36" /> DISABLED
|
||||||
</JobTileButton>
|
</JobTileButton>
|
||||||
{:else if !isIdle}
|
{:else if !isIdle}
|
||||||
{#if waitingCount > 0}
|
{#if waitingCount > 0}
|
||||||
<JobTileButton color="gray" on:click={() => dispatch('command', { command: JobCommand.Empty, force: false })}>
|
<JobTileButton color="gray" on:click={() => dispatch('command', { command: JobCommand.Empty, force: false })}>
|
||||||
<Close size="24" /> CLEAR
|
<Icon path={mdiClose} size="24" /> CLEAR
|
||||||
</JobTileButton>
|
</JobTileButton>
|
||||||
{/if}
|
{/if}
|
||||||
{#if queueStatus.isPaused}
|
{#if queueStatus.isPaused}
|
||||||
@ -117,26 +119,26 @@
|
|||||||
on:click={() => dispatch('command', { command: JobCommand.Resume, force: false })}
|
on:click={() => dispatch('command', { command: JobCommand.Resume, force: false })}
|
||||||
>
|
>
|
||||||
<!-- size property is not reactive, so have to use width and height -->
|
<!-- size property is not reactive, so have to use width and height -->
|
||||||
<FastForward width={size} height={size} /> RESUME
|
<Icon path={mdiFastForward} {size} /> RESUME
|
||||||
</JobTileButton>
|
</JobTileButton>
|
||||||
{:else}
|
{:else}
|
||||||
<JobTileButton
|
<JobTileButton
|
||||||
color="light-gray"
|
color="light-gray"
|
||||||
on:click={() => dispatch('command', { command: JobCommand.Pause, force: false })}
|
on:click={() => dispatch('command', { command: JobCommand.Pause, force: false })}
|
||||||
>
|
>
|
||||||
<Pause size="24" /> PAUSE
|
<Icon path={mdiPause} size="24" /> PAUSE
|
||||||
</JobTileButton>
|
</JobTileButton>
|
||||||
{/if}
|
{/if}
|
||||||
{:else if allowForceCommand}
|
{:else if allowForceCommand}
|
||||||
<JobTileButton color="gray" on:click={() => dispatch('command', { command: JobCommand.Start, force: true })}>
|
<JobTileButton color="gray" on:click={() => dispatch('command', { command: JobCommand.Start, force: true })}>
|
||||||
<AllInclusive size="24" />
|
<Icon path={mdiAllInclusive} size="24" />
|
||||||
{allText}
|
{allText}
|
||||||
</JobTileButton>
|
</JobTileButton>
|
||||||
<JobTileButton
|
<JobTileButton
|
||||||
color="light-gray"
|
color="light-gray"
|
||||||
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
|
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
|
||||||
>
|
>
|
||||||
<SelectionSearch size="24" />
|
<Icon path={mdiSelectionSearch} size="24" />
|
||||||
{missingText}
|
{missingText}
|
||||||
</JobTileButton>
|
</JobTileButton>
|
||||||
{:else}
|
{:else}
|
||||||
@ -144,7 +146,7 @@
|
|||||||
color="light-gray"
|
color="light-gray"
|
||||||
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
|
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
|
||||||
>
|
>
|
||||||
<Play size="48" /> START
|
<Icon path={mdiPlay} size="48" /> START
|
||||||
</JobTileButton>
|
</JobTileButton>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,16 +7,17 @@
|
|||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api';
|
import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api';
|
||||||
import type { ComponentType } from 'svelte';
|
import type { ComponentType } from 'svelte';
|
||||||
import type Icon from 'svelte-material-icons/DotsVertical.svelte';
|
import {
|
||||||
import FaceRecognition from 'svelte-material-icons/FaceRecognition.svelte';
|
mdiFaceRecognition,
|
||||||
import FileJpgBox from 'svelte-material-icons/FileJpgBox.svelte';
|
mdiFileJpgBox,
|
||||||
import FileXmlBox from 'svelte-material-icons/FileXmlBox.svelte';
|
mdiFileXmlBox,
|
||||||
import LibraryShelves from 'svelte-material-icons/LibraryShelves.svelte';
|
mdiFolderMove,
|
||||||
import FolderMove from 'svelte-material-icons/FolderMove.svelte';
|
mdiLibraryShelves,
|
||||||
import Table from 'svelte-material-icons/Table.svelte';
|
mdiTable,
|
||||||
import TagMultiple from 'svelte-material-icons/TagMultiple.svelte';
|
mdiTagMultiple,
|
||||||
import VectorCircle from 'svelte-material-icons/VectorCircle.svelte';
|
mdiVectorCircle,
|
||||||
import Video from 'svelte-material-icons/Video.svelte';
|
mdiVideo,
|
||||||
|
} from '@mdi/js';
|
||||||
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
|
||||||
import JobTile from './job-tile.svelte';
|
import JobTile from './job-tile.svelte';
|
||||||
import StorageMigrationDescription from './storage-migration-description.svelte';
|
import StorageMigrationDescription from './storage-migration-description.svelte';
|
||||||
@ -29,7 +30,7 @@
|
|||||||
allText?: string;
|
allText?: string;
|
||||||
missingText?: string;
|
missingText?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
icon: typeof Icon;
|
icon: string;
|
||||||
allowForceCommand?: boolean;
|
allowForceCommand?: boolean;
|
||||||
component?: ComponentType;
|
component?: ComponentType;
|
||||||
handleCommand?: (jobId: JobName, jobCommand: JobCommandDto) => Promise<void>;
|
handleCommand?: (jobId: JobName, jobCommand: JobCommandDto) => Promise<void>;
|
||||||
@ -53,17 +54,17 @@
|
|||||||
|
|
||||||
$: jobDetails = <Partial<Record<JobName, JobDetails>>>{
|
$: jobDetails = <Partial<Record<JobName, JobDetails>>>{
|
||||||
[JobName.ThumbnailGeneration]: {
|
[JobName.ThumbnailGeneration]: {
|
||||||
icon: FileJpgBox,
|
icon: mdiFileJpgBox,
|
||||||
title: api.getJobName(JobName.ThumbnailGeneration),
|
title: api.getJobName(JobName.ThumbnailGeneration),
|
||||||
subtitle: 'Regenerate JPEG and WebP thumbnails',
|
subtitle: 'Regenerate JPEG and WebP thumbnails',
|
||||||
},
|
},
|
||||||
[JobName.MetadataExtraction]: {
|
[JobName.MetadataExtraction]: {
|
||||||
icon: Table,
|
icon: mdiTable,
|
||||||
title: api.getJobName(JobName.MetadataExtraction),
|
title: api.getJobName(JobName.MetadataExtraction),
|
||||||
subtitle: 'Extract metadata information i.e. GPS, resolution...etc',
|
subtitle: 'Extract metadata information i.e. GPS, resolution...etc',
|
||||||
},
|
},
|
||||||
[JobName.Library]: {
|
[JobName.Library]: {
|
||||||
icon: LibraryShelves,
|
icon: mdiLibraryShelves,
|
||||||
title: api.getJobName(JobName.Library),
|
title: api.getJobName(JobName.Library),
|
||||||
subtitle: 'Perform library tasks',
|
subtitle: 'Perform library tasks',
|
||||||
allText: 'ALL',
|
allText: 'ALL',
|
||||||
@ -71,44 +72,44 @@
|
|||||||
},
|
},
|
||||||
[JobName.Sidecar]: {
|
[JobName.Sidecar]: {
|
||||||
title: api.getJobName(JobName.Sidecar),
|
title: api.getJobName(JobName.Sidecar),
|
||||||
icon: FileXmlBox,
|
icon: mdiFileXmlBox,
|
||||||
subtitle: 'Discover or synchronize sidecar metadata from the filesystem',
|
subtitle: 'Discover or synchronize sidecar metadata from the filesystem',
|
||||||
allText: 'SYNC',
|
allText: 'SYNC',
|
||||||
missingText: 'DISCOVER',
|
missingText: 'DISCOVER',
|
||||||
disabled: !$featureFlags.sidecar,
|
disabled: !$featureFlags.sidecar,
|
||||||
},
|
},
|
||||||
[JobName.ObjectTagging]: {
|
[JobName.ObjectTagging]: {
|
||||||
icon: TagMultiple,
|
icon: mdiTagMultiple,
|
||||||
title: api.getJobName(JobName.ObjectTagging),
|
title: api.getJobName(JobName.ObjectTagging),
|
||||||
subtitle: 'Run machine learning to tag objects\nNote that some assets may not have any objects detected',
|
subtitle: 'Run machine learning to tag objects\nNote that some assets may not have any objects detected',
|
||||||
disabled: !$featureFlags.tagImage,
|
disabled: !$featureFlags.tagImage,
|
||||||
},
|
},
|
||||||
[JobName.ClipEncoding]: {
|
[JobName.ClipEncoding]: {
|
||||||
icon: VectorCircle,
|
icon: mdiVectorCircle,
|
||||||
title: api.getJobName(JobName.ClipEncoding),
|
title: api.getJobName(JobName.ClipEncoding),
|
||||||
subtitle: 'Run machine learning to generate clip embeddings',
|
subtitle: 'Run machine learning to generate clip embeddings',
|
||||||
disabled: !$featureFlags.clipEncode,
|
disabled: !$featureFlags.clipEncode,
|
||||||
},
|
},
|
||||||
[JobName.RecognizeFaces]: {
|
[JobName.RecognizeFaces]: {
|
||||||
icon: FaceRecognition,
|
icon: mdiFaceRecognition,
|
||||||
title: api.getJobName(JobName.RecognizeFaces),
|
title: api.getJobName(JobName.RecognizeFaces),
|
||||||
subtitle: 'Run machine learning to recognize faces',
|
subtitle: 'Run machine learning to recognize faces',
|
||||||
handleCommand: handleFaceCommand,
|
handleCommand: handleFaceCommand,
|
||||||
disabled: !$featureFlags.facialRecognition,
|
disabled: !$featureFlags.facialRecognition,
|
||||||
},
|
},
|
||||||
[JobName.VideoConversion]: {
|
[JobName.VideoConversion]: {
|
||||||
icon: Video,
|
icon: mdiVideo,
|
||||||
title: api.getJobName(JobName.VideoConversion),
|
title: api.getJobName(JobName.VideoConversion),
|
||||||
subtitle: 'Transcode videos not in the desired format',
|
subtitle: 'Transcode videos not in the desired format',
|
||||||
},
|
},
|
||||||
[JobName.StorageTemplateMigration]: {
|
[JobName.StorageTemplateMigration]: {
|
||||||
icon: FolderMove,
|
icon: mdiFolderMove,
|
||||||
title: api.getJobName(JobName.StorageTemplateMigration),
|
title: api.getJobName(JobName.StorageTemplateMigration),
|
||||||
allowForceCommand: false,
|
allowForceCommand: false,
|
||||||
component: StorageMigrationDescription,
|
component: StorageMigrationDescription,
|
||||||
},
|
},
|
||||||
[JobName.Migration]: {
|
[JobName.Migration]: {
|
||||||
icon: FolderMove,
|
icon: mdiFolderMove,
|
||||||
title: api.getJobName(JobName.Migration),
|
title: api.getJobName(JobName.Migration),
|
||||||
subtitle: 'Migrate thumbnails for assets and faces to the latest folder structure',
|
subtitle: 'Migrate thumbnails for assets and faces to the latest folder structure',
|
||||||
allowForceCommand: false,
|
allowForceCommand: false,
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import type { ServerStatsResponseDto } from '@api';
|
import type { ServerStatsResponseDto } from '@api';
|
||||||
import CameraIris from 'svelte-material-icons/CameraIris.svelte';
|
import { asByteUnitString, getBytesWithUnit } from '$lib/utils/byte-units';
|
||||||
import Memory from 'svelte-material-icons/Memory.svelte';
|
|
||||||
import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
|
|
||||||
import { asByteUnitString, getBytesWithUnit } from '../../../utils/byte-units';
|
|
||||||
import StatsCard from './stats-card.svelte';
|
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 = {
|
export let stats: ServerStatsResponseDto = {
|
||||||
photos: 0,
|
photos: 0,
|
||||||
@ -30,15 +29,15 @@
|
|||||||
<p class="text-sm dark:text-immich-dark-fg">TOTAL USAGE</p>
|
<p class="text-sm dark:text-immich-dark-fg">TOTAL USAGE</p>
|
||||||
|
|
||||||
<div class="mt-5 hidden justify-between lg:flex">
|
<div class="mt-5 hidden justify-between lg:flex">
|
||||||
<StatsCard logo={CameraIris} title="PHOTOS" value={stats.photos} />
|
<StatsCard icon={mdiCameraIris} title="PHOTOS" value={stats.photos} />
|
||||||
<StatsCard logo={PlayCircle} title="VIDEOS" value={stats.videos} />
|
<StatsCard icon={mdiPlayCircle} title="VIDEOS" value={stats.videos} />
|
||||||
<StatsCard logo={Memory} title="STORAGE" value={statsUsage} unit={statsUsageUnit} />
|
<StatsCard icon={mdiMemory} title="STORAGE" value={statsUsage} unit={statsUsageUnit} />
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-5 flex lg:hidden">
|
<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-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 flex-wrap gap-x-12">
|
||||||
<div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
|
<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>
|
<p>PHOTOS</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -50,7 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-x-12">
|
<div class="flex flex-wrap gap-x-12">
|
||||||
<div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
|
<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>
|
<p>VIDEOS</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -62,7 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-x-7">
|
<div class="flex flex-wrap gap-x-7">
|
||||||
<div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
|
<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>
|
<p>STORAGE</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<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 title: string;
|
||||||
export let value: number;
|
export let value: number;
|
||||||
export let unit: string | undefined = undefined;
|
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 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">
|
<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>
|
<p>{title}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -17,10 +17,11 @@
|
|||||||
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
|
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
|
||||||
import SettingSelect from '../setting-select.svelte';
|
import SettingSelect from '../setting-select.svelte';
|
||||||
import SettingSwitch from '../setting-switch.svelte';
|
import SettingSwitch from '../setting-switch.svelte';
|
||||||
import HelpCircleOutline from 'svelte-material-icons/HelpCircleOutline.svelte';
|
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import SettingAccordion from '../setting-accordion.svelte';
|
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 ffmpegConfig: SystemConfigFFmpegDto; // this is the config that is being edited
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
@ -93,7 +94,7 @@
|
|||||||
<form autocomplete="off" on:submit|preventDefault>
|
<form autocomplete="off" on:submit|preventDefault>
|
||||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
<p class="text-sm dark:text-immich-dark-fg">
|
<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
|
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"
|
<a href="https://trac.ffmpeg.org/wiki/Encode/H.264" class="underline" target="_blank" rel="noreferrer"
|
||||||
>H.264 codec</a
|
>H.264 codec</a
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import { AlbumResponseDto, api, ThumbnailFormat, UserResponseDto } from '@api';
|
import { AlbumResponseDto, api, ThumbnailFormat, UserResponseDto } from '@api';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
|
||||||
import IconButton from '../elements/buttons/icon-button.svelte';
|
import IconButton from '../elements/buttons/icon-button.svelte';
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import type { OnClick, OnShowContextMenu } from './album-card';
|
import type { OnClick, OnShowContextMenu } from './album-card';
|
||||||
import { getContextMenuPosition } from '../../utils/context-menu';
|
import { getContextMenuPosition } from '../../utils/context-menu';
|
||||||
|
import { mdiDotsVertical } from '@mdi/js';
|
||||||
|
|
||||||
export let album: AlbumResponseDto;
|
export let album: AlbumResponseDto;
|
||||||
export let isSharingView = false;
|
export let isSharingView = false;
|
||||||
@ -75,7 +76,7 @@
|
|||||||
data-testid="context-button-parent"
|
data-testid="context-button-parent"
|
||||||
>
|
>
|
||||||
<IconButton color="transparent-primary">
|
<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>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
|
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
import { TimeBucketSize, type AlbumResponseDto, type SharedLinkResponseDto } from '@api';
|
import { TimeBucketSize, type AlbumResponseDto, type SharedLinkResponseDto } from '@api';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
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 { dateFormats } from '../../constants';
|
||||||
import { createAssetInteractionStore } from '../../stores/asset-interaction.store';
|
import { createAssetInteractionStore } from '../../stores/asset-interaction.store';
|
||||||
import { AssetStore } from '../../stores/assets.store';
|
import { AssetStore } from '../../stores/assets.store';
|
||||||
@ -21,6 +19,7 @@
|
|||||||
import ImmichLogo from '../shared-components/immich-logo.svelte';
|
import ImmichLogo from '../shared-components/immich-logo.svelte';
|
||||||
import ThemeButton from '../shared-components/theme-button.svelte';
|
import ThemeButton from '../shared-components/theme-button.svelte';
|
||||||
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
||||||
|
import { mdiFileImagePlusOutline, mdiFolderDownloadOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let sharedLink: SharedLinkResponseDto;
|
export let sharedLink: SharedLinkResponseDto;
|
||||||
|
|
||||||
@ -122,12 +121,12 @@
|
|||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="Add Photos"
|
title="Add Photos"
|
||||||
on:click={() => openFileUploadDialog(album.id)}
|
on:click={() => openFileUploadDialog(album.id)}
|
||||||
logo={FileImagePlusOutline}
|
icon={mdiFileImagePlusOutline}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if album.assetCount > 0 && sharedLink.allowDownload}
|
{#if album.assetCount > 0 && sharedLink.allowDownload}
|
||||||
<CircleIconButton title="Download" on:click={() => downloadAlbum()} logo={FolderDownloadOutline} />
|
<CircleIconButton title="Download" on:click={() => downloadAlbum()} icon={mdiFolderDownloadOutline} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<ThemeButton />
|
<ThemeButton />
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
import { AlbumResponseDto, api, UserResponseDto } from '@api';
|
import { AlbumResponseDto, api, UserResponseDto } from '@api';
|
||||||
import BaseModal from '../shared-components/base-modal.svelte';
|
import BaseModal from '../shared-components/base-modal.svelte';
|
||||||
import UserAvatar from '../shared-components/user-avatar.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 CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
||||||
@ -11,6 +10,7 @@
|
|||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
||||||
import { getContextMenuPosition } from '../../utils/context-menu';
|
import { getContextMenuPosition } from '../../utils/context-menu';
|
||||||
|
import { mdiDotsVertical } from '@mdi/js';
|
||||||
|
|
||||||
export let album: AlbumResponseDto;
|
export let album: AlbumResponseDto;
|
||||||
|
|
||||||
@ -99,7 +99,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
on:click={(event) => showContextMenu(event, user)}
|
on:click={(event) => showContextMenu(event, user)}
|
||||||
logo={DotsVertical}
|
icon={mdiDotsVertical}
|
||||||
backgroundColor="transparent"
|
backgroundColor="transparent"
|
||||||
hoverColor="#e2e7e9"
|
hoverColor="#e2e7e9"
|
||||||
size="20"
|
size="20"
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
import { AlbumResponseDto, api, SharedLinkResponseDto, UserResponseDto } from '@api';
|
import { AlbumResponseDto, api, SharedLinkResponseDto, UserResponseDto } from '@api';
|
||||||
import BaseModal from '../shared-components/base-modal.svelte';
|
import BaseModal from '../shared-components/base-modal.svelte';
|
||||||
import UserAvatar from '../shared-components/user-avatar.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 { goto } from '$app/navigation';
|
||||||
import ImmichLogo from '../shared-components/immich-logo.svelte';
|
import ImmichLogo from '../shared-components/immich-logo.svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
|
import { mdiLink, mdiShareCircle } from '@mdi/js';
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
|
||||||
export let album: AlbumResponseDto;
|
export let album: AlbumResponseDto;
|
||||||
let users: UserResponseDto[] = [];
|
let users: UserResponseDto[] = [];
|
||||||
@ -128,7 +128,7 @@
|
|||||||
class="flex flex-col place-content-center place-items-center gap-2 hover:cursor-pointer"
|
class="flex flex-col place-content-center place-items-center gap-2 hover:cursor-pointer"
|
||||||
on:click={() => dispatch('share')}
|
on:click={() => dispatch('share')}
|
||||||
>
|
>
|
||||||
<Link size={24} />
|
<Icon path={mdiLink} size={24} />
|
||||||
<p class="text-sm">Create link</p>
|
<p class="text-sm">Create link</p>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -137,7 +137,7 @@
|
|||||||
class="flex flex-col place-content-center place-items-center gap-2 hover:cursor-pointer"
|
class="flex flex-col place-content-center place-items-center gap-2 hover:cursor-pointer"
|
||||||
on:click={() => goto(AppRoute.SHARED_LINKS)}
|
on:click={() => goto(AppRoute.SHARED_LINKS)}
|
||||||
>
|
>
|
||||||
<ShareCircle size={24} />
|
<Icon path={mdiShareCircle} size={24} />
|
||||||
<p class="text-sm">View links</p>
|
<p class="text-sm">View links</p>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,26 +1,28 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
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 { photoZoomState } from '$lib/stores/zoom-image.store';
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
|
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
||||||
import { AssetJobName, AssetResponseDto, AssetTypeEnum, api } from '@api';
|
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 { 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 ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
|
||||||
|
|
||||||
export let asset: AssetResponseDto;
|
export let asset: AssetResponseDto;
|
||||||
export let showCopyButton: boolean;
|
export let showCopyButton: boolean;
|
||||||
@ -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"
|
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">
|
<div class="text-white">
|
||||||
<CircleIconButton isOpacity={true} logo={ArrowLeft} on:click={() => dispatch('goBack')} />
|
<CircleIconButton isOpacity={true} icon={mdiArrowLeft} on:click={() => dispatch('goBack')} />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex w-[calc(100%-3rem)] justify-end gap-2 overflow-hidden text-white">
|
<div class="flex w-[calc(100%-3rem)] justify-end gap-2 overflow-hidden text-white">
|
||||||
{#if asset.isOffline}
|
{#if asset.isOffline}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
isOpacity={true}
|
isOpacity={true}
|
||||||
logo={AlertOutline}
|
icon={mdiAlertOutline}
|
||||||
on:click={() => dispatch('showDetail')}
|
on:click={() => dispatch('showDetail')}
|
||||||
title="Asset Offline"
|
title="Asset Offline"
|
||||||
/>
|
/>
|
||||||
@ -89,14 +91,14 @@
|
|||||||
{#if isMotionPhotoPlaying}
|
{#if isMotionPhotoPlaying}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
isOpacity={true}
|
isOpacity={true}
|
||||||
logo={MotionPauseOutline}
|
icon={mdiMotionPauseOutline}
|
||||||
title="Stop Motion Photo"
|
title="Stop Motion Photo"
|
||||||
on:click={() => dispatch('stopMotionPhoto')}
|
on:click={() => dispatch('stopMotionPhoto')}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
isOpacity={true}
|
isOpacity={true}
|
||||||
logo={MotionPlayOutline}
|
icon={mdiMoviePlayOutline}
|
||||||
title="Play Motion Photo"
|
title="Play Motion Photo"
|
||||||
on:click={() => dispatch('playMotionPhoto')}
|
on:click={() => dispatch('playMotionPhoto')}
|
||||||
/>
|
/>
|
||||||
@ -106,7 +108,7 @@
|
|||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
isOpacity={true}
|
isOpacity={true}
|
||||||
hideMobile={true}
|
hideMobile={true}
|
||||||
logo={$photoZoomState && $photoZoomState.currentZoom > 1 ? MagnifyMinusOutline : MagnifyPlusOutline}
|
icon={$photoZoomState && $photoZoomState.currentZoom > 1 ? mdiMagnifyMinusOutline : mdiMagnifyPlusOutline}
|
||||||
title="Zoom Image"
|
title="Zoom Image"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
const zoomImage = new CustomEvent('zoomImage');
|
const zoomImage = new CustomEvent('zoomImage');
|
||||||
@ -117,7 +119,7 @@
|
|||||||
{#if showCopyButton}
|
{#if showCopyButton}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
isOpacity={true}
|
isOpacity={true}
|
||||||
logo={ContentCopy}
|
icon={mdiContentCopy}
|
||||||
title="Copy Image"
|
title="Copy Image"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
const copyEvent = new CustomEvent('copyImage');
|
const copyEvent = new CustomEvent('copyImage');
|
||||||
@ -129,7 +131,7 @@
|
|||||||
{#if showDownloadButton}
|
{#if showDownloadButton}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
isOpacity={true}
|
isOpacity={true}
|
||||||
logo={CloudDownloadOutline}
|
icon={mdiCloudDownloadOutline}
|
||||||
on:click={() => dispatch('download')}
|
on:click={() => dispatch('download')}
|
||||||
title="Download"
|
title="Download"
|
||||||
/>
|
/>
|
||||||
@ -137,7 +139,7 @@
|
|||||||
{#if showDetailButton}
|
{#if showDetailButton}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
isOpacity={true}
|
isOpacity={true}
|
||||||
logo={InformationOutline}
|
icon={mdiInformationOutline}
|
||||||
on:click={() => dispatch('showDetail')}
|
on:click={() => dispatch('showDetail')}
|
||||||
title="Info"
|
title="Info"
|
||||||
/>
|
/>
|
||||||
@ -145,7 +147,7 @@
|
|||||||
{#if isOwner}
|
{#if isOwner}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
isOpacity={true}
|
isOpacity={true}
|
||||||
logo={asset.isFavorite ? Heart : HeartOutline}
|
icon={asset.isFavorite ? mdiHeart : mdiHeartOutline}
|
||||||
on:click={() => dispatch('favorite')}
|
on:click={() => dispatch('favorite')}
|
||||||
title="Favorite"
|
title="Favorite"
|
||||||
/>
|
/>
|
||||||
@ -153,10 +155,10 @@
|
|||||||
|
|
||||||
{#if isOwner}
|
{#if isOwner}
|
||||||
{#if !asset.isReadOnly || !asset.isExternal}
|
{#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}
|
{/if}
|
||||||
<div use:clickOutside on:outclick={() => (isShowAssetOptions = false)}>
|
<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}
|
{#if isShowAssetOptions}
|
||||||
<ContextMenu {...contextMenuPosition} direction="left">
|
<ContextMenu {...contextMenuPosition} direction="left">
|
||||||
{#if showSlideshow}
|
{#if showSlideshow}
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { AlbumResponseDto, api, AssetJobName, AssetResponseDto, AssetTypeEnum, SharedLinkResponseDto } from '@api';
|
import { AlbumResponseDto, api, AssetJobName, AssetResponseDto, AssetTypeEnum, SharedLinkResponseDto } from '@api';
|
||||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
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 { fly } from 'svelte/transition';
|
||||||
import AlbumSelectionModal from '../shared-components/album-selection-modal.svelte';
|
import AlbumSelectionModal from '../shared-components/album-selection-modal.svelte';
|
||||||
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
||||||
@ -16,8 +13,6 @@
|
|||||||
import { ProjectionType } from '$lib/constants';
|
import { ProjectionType } from '$lib/constants';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||||
import ProfileImageCropper from '../shared-components/profile-image-cropper.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 { isShowDetail } from '$lib/stores/preferences.store';
|
||||||
import { addAssetsToAlbum, downloadFile } from '$lib/utils/asset-utils';
|
import { addAssetsToAlbum, downloadFile } from '$lib/utils/asset-utils';
|
||||||
import NavigationArea from './navigation-area.svelte';
|
import NavigationArea from './navigation-area.svelte';
|
||||||
@ -25,11 +20,11 @@
|
|||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import type { AssetStore } from '$lib/stores/assets.store';
|
import type { AssetStore } from '$lib/stores/assets.store';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
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 ProgressBar, { ProgressBarStatus } from '../shared-components/progress-bar/progress-bar.svelte';
|
||||||
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
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 assetStore: AssetStore | null = null;
|
||||||
export let asset: AssetResponseDto;
|
export let asset: AssetResponseDto;
|
||||||
@ -368,14 +363,14 @@
|
|||||||
<!-- SlideShowController -->
|
<!-- SlideShowController -->
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="m-4 flex gap-2">
|
<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
|
<CircleIconButton
|
||||||
logo={progressBarStatus === ProgressBarStatus.Paused ? Play : Pause}
|
icon={progressBarStatus === ProgressBarStatus.Paused ? mdiPlay : mdiPause}
|
||||||
on:click={() => (progressBarStatus === ProgressBarStatus.Paused ? progressBar.play() : progressBar.pause())}
|
on:click={() => (progressBarStatus === ProgressBarStatus.Paused ? progressBar.play() : progressBar.pause())}
|
||||||
title={progressBarStatus === ProgressBarStatus.Paused ? 'Play' : 'Pause'}
|
title={progressBarStatus === ProgressBarStatus.Paused ? 'Play' : 'Pause'}
|
||||||
/>
|
/>
|
||||||
<CircleIconButton logo={ChevronLeft} on:click={navigateAssetBackward} title="Previous" />
|
<CircleIconButton icon={mdiChevronLeft} on:click={navigateAssetBackward} title="Previous" />
|
||||||
<CircleIconButton logo={ChevronRight} on:click={navigateAssetForward} title="Next" />
|
<CircleIconButton icon={mdiChevronRight} on:click={navigateAssetForward} title="Next" />
|
||||||
</div>
|
</div>
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
autoplay
|
autoplay
|
||||||
@ -414,7 +409,7 @@
|
|||||||
|
|
||||||
{#if !isSlideshowMode && showNavigation}
|
{#if !isSlideshowMode && showNavigation}
|
||||||
<div class="column-span-1 z-[999] col-start-1 row-span-1 row-start-2 mb-[60px] justify-self-start">
|
<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>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@ -425,7 +420,7 @@
|
|||||||
<div
|
<div
|
||||||
class="px-auto flex aspect-square h-full items-center justify-center bg-gray-100 dark:bg-immich-dark-gray"
|
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>
|
||||||
</div>
|
</div>
|
||||||
{:else if asset.type === AssetTypeEnum.Image}
|
{:else if asset.type === AssetTypeEnum.Image}
|
||||||
@ -455,7 +450,7 @@
|
|||||||
|
|
||||||
{#if !isSlideshowMode && showNavigation}
|
{#if !isSlideshowMode && showNavigation}
|
||||||
<div class="z-[999] col-span-1 col-start-4 row-span-1 row-start-2 mb-[60px] justify-self-end">
|
<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>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -7,14 +7,11 @@
|
|||||||
import type { LatLngTuple } from 'leaflet';
|
import type { LatLngTuple } from 'leaflet';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { createEventDispatcher } from 'svelte';
|
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 { asByteUnitString } from '../../utils/byte-units';
|
||||||
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
||||||
import UserAvatar from '../shared-components/user-avatar.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 asset: AssetResponseDto;
|
||||||
export let albums: AlbumResponseDto[] = [];
|
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"
|
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')}
|
on:click={() => dispatch('close')}
|
||||||
>
|
>
|
||||||
<Close size="24" />
|
<Icon path={mdiClose} size="24" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<p class="text-lg text-immich-fg dark:text-immich-dark-fg">Info</p>
|
<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 class="flex gap-4 py-4">
|
||||||
<div>
|
<div>
|
||||||
<Calendar size="24" />
|
<Icon path={mdiCalendar} size="24" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -218,7 +215,7 @@
|
|||||||
|
|
||||||
{#if asset.exifInfo?.fileSizeInByte}
|
{#if asset.exifInfo?.fileSizeInByte}
|
||||||
<div class="flex gap-4 py-4">
|
<div class="flex gap-4 py-4">
|
||||||
<div><ImageOutline size="24" /></div>
|
<div><Icon path={mdiImageOutline} size="24" /></div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p class="break-all">
|
<p class="break-all">
|
||||||
@ -242,7 +239,7 @@
|
|||||||
|
|
||||||
{#if asset.exifInfo?.make || asset.exifInfo?.model || asset.exifInfo?.fNumber}
|
{#if asset.exifInfo?.make || asset.exifInfo?.model || asset.exifInfo?.fNumber}
|
||||||
<div class="flex gap-4 py-4">
|
<div class="flex gap-4 py-4">
|
||||||
<div><CameraIris size="24" /></div>
|
<div><Icon path={mdiCameraIris} size="24" /></div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p>{asset.exifInfo.make || ''} {asset.exifInfo.model || ''}</p>
|
<p>{asset.exifInfo.make || ''} {asset.exifInfo.model || ''}</p>
|
||||||
@ -271,7 +268,7 @@
|
|||||||
|
|
||||||
{#if asset.exifInfo?.city}
|
{#if asset.exifInfo?.city}
|
||||||
<div class="flex gap-4 py-4">
|
<div class="flex gap-4 py-4">
|
||||||
<div><MapMarkerOutline size="24" /></div>
|
<div><Icon path={mdiMapMarkerOutline} size="24" /></div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p>{asset.exifInfo.city}</p>
|
<p>{asset.exifInfo.city}</p>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DownloadProgress, downloadAssets, downloadManager, isDownloading } from '$lib/stores/download';
|
import { DownloadProgress, downloadAssets, downloadManager, isDownloading } from '$lib/stores/download';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
|
||||||
import { fly, slide } from 'svelte/transition';
|
import { fly, slide } from 'svelte/transition';
|
||||||
import { asByteUnitString } from '../../utils/byte-units';
|
import { asByteUnitString } from '../../utils/byte-units';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
|
import { mdiClose } from '@mdi/js';
|
||||||
|
|
||||||
const abort = (downloadKey: string, download: DownloadProgress) => {
|
const abort = (downloadKey: string, download: DownloadProgress) => {
|
||||||
download.abort?.abort();
|
download.abort?.abort();
|
||||||
@ -39,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="absolute right-2">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import { thumbHashToDataURL } from 'thumbhash';
|
import { thumbHashToDataURL } from 'thumbhash';
|
||||||
import { Buffer } from 'buffer';
|
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 url: string;
|
||||||
export let altText: string;
|
export let altText: string;
|
||||||
@ -18,7 +19,7 @@
|
|||||||
export let border = false;
|
export let border = false;
|
||||||
let complete = false;
|
let complete = false;
|
||||||
|
|
||||||
export let eyeColor = 'white';
|
export let eyeColor: 'black' | 'white' = 'white';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
@ -43,7 +44,7 @@
|
|||||||
|
|
||||||
{#if hidden}
|
{#if hidden}
|
||||||
<div class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform">
|
<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>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -4,16 +4,19 @@
|
|||||||
import { timeToSeconds } from '$lib/utils/time-to-seconds';
|
import { timeToSeconds } from '$lib/utils/time-to-seconds';
|
||||||
import { api, AssetResponseDto, AssetTypeEnum, ThumbnailFormat } from '@api';
|
import { api, AssetResponseDto, AssetTypeEnum, ThumbnailFormat } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
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 { fade } from 'svelte/transition';
|
||||||
import ImageThumbnail from './image-thumbnail.svelte';
|
import ImageThumbnail from './image-thumbnail.svelte';
|
||||||
import VideoThumbnail from './video-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();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
@ -93,13 +96,13 @@
|
|||||||
{disabled}
|
{disabled}
|
||||||
>
|
>
|
||||||
{#if disabled}
|
{#if disabled}
|
||||||
<CheckCircle size="24" class="text-zinc-800" />
|
<Icon path={mdiCheckCircle} size="24" class="text-zinc-800" />
|
||||||
{:else if selected}
|
{:else if selected}
|
||||||
<div class="rounded-full bg-[#D9DCEF] dark:bg-[#232932]">
|
<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>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<CheckCircle size="24" class="text-white/80 hover:text-white" />
|
<Icon path={mdiCheckCircle} size="24" class="text-white/80 hover:text-white" />
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
@ -119,20 +122,20 @@
|
|||||||
<!-- Favorite asset star -->
|
<!-- Favorite asset star -->
|
||||||
{#if !api.isSharedLink && asset.isFavorite}
|
{#if !api.isSharedLink && asset.isFavorite}
|
||||||
<div class="absolute bottom-2 left-2 z-10">
|
<div class="absolute bottom-2 left-2 z-10">
|
||||||
<Heart size="24" class="text-white" />
|
<Icon path={mdiHeart} size="24" class="text-white" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if !api.isSharedLink && showArchiveIcon && asset.isArchived}
|
{#if !api.isSharedLink && showArchiveIcon && asset.isArchived}
|
||||||
<div class="absolute {asset.isFavorite ? 'bottom-10' : 'bottom-2'} left-2 z-10">
|
<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>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if asset.type === AssetTypeEnum.Image && asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR}
|
{#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">
|
<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">
|
<span class="pr-2 pt-2">
|
||||||
<Rotate360Icon size="24" />
|
<Icon path={mdiRotate360} size="24" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -148,7 +151,7 @@
|
|||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex h-full w-full items-center justify-center p-4">
|
<div class="flex h-full w-full items-center justify-center p-4">
|
||||||
<ImageBrokenVariant size="48" />
|
<Icon path={mdiImageBrokenVariant} size="48" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@ -167,8 +170,8 @@
|
|||||||
<div class="absolute top-0 h-full w-full">
|
<div class="absolute top-0 h-full w-full">
|
||||||
<VideoThumbnail
|
<VideoThumbnail
|
||||||
url={api.getAssetFileUrl(asset.livePhotoVideoId, false, true)}
|
url={api.getAssetFileUrl(asset.livePhotoVideoId, false, true)}
|
||||||
pauseIcon={MotionPauseOutline}
|
pauseIcon={mdiMotionPauseOutline}
|
||||||
playIcon={MotionPlayOutline}
|
playIcon={mdiMotionPlayOutline}
|
||||||
showTime={false}
|
showTime={false}
|
||||||
curve={selected}
|
curve={selected}
|
||||||
playbackOnIconHover
|
playbackOnIconHover
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Duration } from 'luxon';
|
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 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 url: string;
|
||||||
export let durationInSeconds = 0;
|
export let durationInSeconds = 0;
|
||||||
@ -11,8 +10,8 @@
|
|||||||
export let playbackOnIconHover = false;
|
export let playbackOnIconHover = false;
|
||||||
export let showTime = true;
|
export let showTime = true;
|
||||||
export let curve = false;
|
export let curve = false;
|
||||||
export let playIcon = PlayCircleOutline;
|
export let playIcon = mdiPlayCircleOutline;
|
||||||
export let pauseIcon = PauseCircleOutline;
|
export let pauseIcon = mdiPauseCircleOutline;
|
||||||
|
|
||||||
let remainingSeconds = durationInSeconds;
|
let remainingSeconds = durationInSeconds;
|
||||||
let loading = true;
|
let loading = true;
|
||||||
@ -55,12 +54,12 @@
|
|||||||
{#if loading}
|
{#if loading}
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
{:else if error}
|
{:else if error}
|
||||||
<AlertCircleOutline size="24" class="text-red-600" />
|
<Icon path={mdiAlertCircleOutline} size="24" class="text-red-600" />
|
||||||
{:else}
|
{:else}
|
||||||
<svelte:component this={pauseIcon} size="24" />
|
<Icon path={pauseIcon} size="24" />
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<svelte:component this={playIcon} size="24" />
|
<Icon path={playIcon} size="24" />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<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 backgroundColor = '';
|
||||||
export let hoverColor = '#e2e7e9';
|
export let hoverColor = '#e2e7e9';
|
||||||
export let padding = '3';
|
export let padding = '3';
|
||||||
@ -23,7 +23,7 @@
|
|||||||
{hideMobile && 'hidden sm:flex'}"
|
{hideMobile && 'hidden sm:flex'}"
|
||||||
on:click
|
on:click
|
||||||
>
|
>
|
||||||
<svelte:component this={logo} {size} />
|
<Icon path={icon} {size} />
|
||||||
<slot />
|
<slot />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -5,12 +5,14 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" generics="T">
|
<script lang="ts" generics="T">
|
||||||
|
import Icon from './icon.svelte';
|
||||||
|
|
||||||
|
import { mdiCheck } from '@mdi/js';
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import LinkButton from './buttons/link-button.svelte';
|
import LinkButton from './buttons/link-button.svelte';
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
import { fly } from 'svelte/transition';
|
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';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
@ -24,7 +26,7 @@
|
|||||||
|
|
||||||
type RenderedOption = {
|
type RenderedOption = {
|
||||||
title: string;
|
title: string;
|
||||||
icon?: typeof Icon;
|
icon?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
let showMenu = false;
|
let showMenu = false;
|
||||||
@ -61,7 +63,7 @@
|
|||||||
<LinkButton on:click={() => (showMenu = true)}>
|
<LinkButton on:click={() => (showMenu = true)}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
{#if renderedSelectedOption?.icon}
|
{#if renderedSelectedOption?.icon}
|
||||||
<svelte:component this={renderedSelectedOption.icon} size="18" />
|
<Icon path={renderedSelectedOption.icon} size="18" />
|
||||||
{/if}
|
{/if}
|
||||||
<p class="hidden sm:block">{renderedSelectedOption.title}</p>
|
<p class="hidden sm:block">{renderedSelectedOption.title}</p>
|
||||||
</div>
|
</div>
|
||||||
@ -81,7 +83,7 @@
|
|||||||
>
|
>
|
||||||
{#if _.isEqual(selectedOption, option)}
|
{#if _.isEqual(selectedOption, option)}
|
||||||
<div class="text-immich-primary dark:text-immich-dark-primary">
|
<div class="text-immich-primary dark:text-immich-dark-primary">
|
||||||
<Check size="18" />
|
<Icon path={mdiCheck} size="18" />
|
||||||
</div>
|
</div>
|
||||||
<p class="justify-self-start text-immich-primary dark:text-immich-dark-primary">
|
<p class="justify-self-start text-immich-primary dark:text-immich-dark-primary">
|
||||||
{renderedOption.title}
|
{renderedOption.title}
|
||||||
|
36
web/src/lib/components/elements/icon.svelte
Normal file
36
web/src/lib/components/elements/icon.svelte
Normal 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>
|
@ -6,15 +6,14 @@
|
|||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
import Button from '../elements/buttons/button.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 { flip } from 'svelte/animate';
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { goto, invalidateAll } from '$app/navigation';
|
import { goto, invalidateAll } from '$app/navigation';
|
||||||
import { AppRoute } from '$lib/constants';
|
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;
|
export let person: PersonResponseDto;
|
||||||
let people: PersonResponseDto[] = [];
|
let people: PersonResponseDto[] = [];
|
||||||
@ -104,7 +103,7 @@
|
|||||||
isShowConfirmation = true;
|
isShowConfirmation = true;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Merge size={18} />
|
<Icon path={mdiMerge} size={18} />
|
||||||
<span class="ml-2"> Merge</span></Button
|
<span class="ml-2"> Merge</span></Button
|
||||||
>
|
>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
@ -123,10 +122,10 @@
|
|||||||
|
|
||||||
{#if hasSelection}
|
{#if hasSelection}
|
||||||
<span class="grid grid-cols-1"
|
<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}
|
{#if selectedPeople.length === 1}
|
||||||
<button class="flex justify-center" on:click={handleSwapPeople}
|
<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>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
|
@ -2,12 +2,11 @@
|
|||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
import { api, type PersonResponseDto } from '@api';
|
import { api, type PersonResponseDto } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
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 ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-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<{
|
const dispatch = createEventDispatcher<{
|
||||||
reject: void;
|
reject: void;
|
||||||
@ -40,7 +39,7 @@
|
|||||||
Merge faces - {title}
|
Merge faces - {title}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<CircleIconButton logo={Close} on:click={() => dispatch('close')} />
|
<CircleIconButton icon={mdiClose} on:click={() => dispatch('close')} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -57,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mx-0.5 flex md:mx-2">
|
<div class="mx-0.5 flex md:mx-2">
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
logo={Merge}
|
icon={mdiMerge}
|
||||||
on:click={() => ([personMerge1, personMerge2] = [personMerge2, personMerge1])}
|
on:click={() => ([personMerge1, personMerge2] = [personMerge2, personMerge1])}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -83,7 +82,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div class="grid w-full grid-cols-1 gap-2">
|
<div class="grid w-full grid-cols-1 gap-2">
|
||||||
<div class="px-2">
|
<div class="px-2">
|
||||||
<button on:click={() => (choosePersonToMerge = false)}> <ArrowLeft /></button>
|
<button on:click={() => (choosePersonToMerge = false)}> <Icon path={mdiArrowLeft} /></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-center">
|
<div class="flex items-center justify-center">
|
||||||
<div class="flex flex-wrap justify-center md:grid md:grid-cols-{potentialMergePeople.length}">
|
<div class="flex flex-wrap justify-center md:grid md:grid-cols-{potentialMergePeople.length}">
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
||||||
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
||||||
import IconButton from '../elements/buttons/icon-button.svelte';
|
import IconButton from '../elements/buttons/icon-button.svelte';
|
||||||
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
|
||||||
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
||||||
import Portal from '../shared-components/portal/portal.svelte';
|
import Portal from '../shared-components/portal/portal.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
|
import { mdiDotsVertical } from '@mdi/js';
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
|
||||||
export let person: PersonResponseDto;
|
export let person: PersonResponseDto;
|
||||||
|
|
||||||
@ -71,7 +72,7 @@
|
|||||||
id={`icon-${person.id}`}
|
id={`icon-${person.id}`}
|
||||||
>
|
>
|
||||||
<IconButton color="transparent-primary">
|
<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>
|
</IconButton>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Cake from 'svelte-material-icons/Cake.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.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;
|
export let birthDate: string;
|
||||||
|
|
||||||
@ -22,7 +23,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
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>
|
<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">
|
<p class="text-sm dark:text-immich-dark-fg">
|
||||||
|
@ -2,13 +2,10 @@
|
|||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
|
||||||
import IconButton from '../elements/buttons/icon-button.svelte';
|
import IconButton from '../elements/buttons/icon-button.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||||
import Restart from 'svelte-material-icons/Restart.svelte';
|
import { mdiClose, mdiEye, mdiEyeOff, mdiRestart } from '@mdi/js';
|
||||||
import Eye from 'svelte-material-icons/Eye.svelte';
|
|
||||||
import EyeOff from 'svelte-material-icons/EyeOff.svelte';
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
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"
|
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">
|
<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>
|
<p class="ml-4 hidden sm:block">Show & hide faces</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-end">
|
<div class="flex items-center justify-end">
|
||||||
<div class="flex items-center md:mr-8">
|
<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
|
<CircleIconButton
|
||||||
title="Toggle visibility"
|
title="Toggle visibility"
|
||||||
logo={toggleVisibility ? Eye : EyeOff}
|
icon={toggleVisibility ? mdiEye : mdiEyeOff}
|
||||||
on:click={() => dispatch('toggle-visibility')}
|
on:click={() => dispatch('toggle-visibility')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { APIKeyResponseDto } from '@api';
|
import type { APIKeyResponseDto } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import KeyVariant from 'svelte-material-icons/KeyVariant.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.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 apiKey: Partial<APIKeyResponseDto>;
|
||||||
export let title = 'API Key';
|
export let title = 'API Key';
|
||||||
@ -22,7 +23,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
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">
|
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">
|
||||||
{title}
|
{title}
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
import KeyVariant from 'svelte-material-icons/KeyVariant.svelte';
|
|
||||||
import { copyToClipboard } from '@api';
|
import { copyToClipboard } from '@api';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.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 = '';
|
export let secret = '';
|
||||||
|
|
||||||
@ -24,7 +25,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
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>
|
<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">
|
<p class="text-sm dark:text-immich-dark-fg">
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AlbumResponseDto, api } from '@api';
|
import { AlbumResponseDto, api } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
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 Button from '../elements/buttons/button.svelte';
|
||||||
|
|
||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
|
import { mdiImageAlbum } from '@mdi/js';
|
||||||
|
|
||||||
export let album: AlbumResponseDto;
|
export let album: AlbumResponseDto;
|
||||||
|
|
||||||
@ -36,7 +35,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
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>
|
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Edit album</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { api, UserResponseDto } from '@api';
|
import { api, UserResponseDto } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import AccountEditOutline from 'svelte-material-icons/AccountEditOutline.svelte';
|
|
||||||
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||||
import { handleError } from '../../utils/handle-error';
|
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 user: UserResponseDto;
|
||||||
export let canResetPassword = true;
|
export let canResetPassword = true;
|
||||||
@ -72,7 +73,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
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>
|
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Edit user</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import FolderRemove from 'svelte-material-icons/FolderRemove.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.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 exclusionPattern: string;
|
||||||
export let canDelete = false;
|
export let canDelete = false;
|
||||||
@ -20,7 +21,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
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>
|
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Add Exclusion pattern</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
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 Button from '../elements/buttons/button.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||||
|
import { mdiFolderSync } from '@mdi/js';
|
||||||
|
|
||||||
export let importPath: string;
|
export let importPath: string;
|
||||||
export let title = 'Import path';
|
export let title = 'Import path';
|
||||||
@ -22,7 +23,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
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">
|
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">
|
||||||
{title}
|
{title}
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import LibraryImportPathForm from './library-import-path-form.svelte';
|
import LibraryImportPathForm from './library-import-path-form.svelte';
|
||||||
import { onMount } from '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 type { LibraryResponseDto } from '@api';
|
||||||
|
import { mdiPencilOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let library: Partial<LibraryResponseDto>;
|
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"
|
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>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
import { LibraryType, type LibraryResponseDto } from '@api';
|
import { LibraryType, type LibraryResponseDto } from '@api';
|
||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import { onMount } from 'svelte';
|
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 LibraryExclusionPatternForm from './library-exclusion-pattern-form.svelte';
|
||||||
|
import { mdiPencilOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let library: Partial<LibraryResponseDto>;
|
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"
|
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>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -6,12 +6,6 @@
|
|||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import { fromLocalDateTime } from '$lib/utils/timeline-util';
|
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 { AppRoute } from '$lib/constants';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
|
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
|
||||||
@ -20,6 +14,7 @@
|
|||||||
import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte';
|
import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import { tweened } from 'svelte/motion';
|
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);
|
const parseIndex = (s: string | null, max: number | null) => Math.max(Math.min(parseInt(s ?? '') || 0, max ?? 0), 0);
|
||||||
|
|
||||||
@ -115,7 +110,7 @@
|
|||||||
|
|
||||||
{#if !galleryInView}
|
{#if !galleryInView}
|
||||||
<div class="flex place-content-center place-items-center gap-2 overflow-hidden">
|
<div class="flex place-content-center place-items-center gap-2 overflow-hidden">
|
||||||
<CircleIconButton logo={paused ? Play : Pause} forceDark on:click={() => (paused = !paused)} />
|
<CircleIconButton icon={paused ? mdiPlay : mdiPause} forceDark on:click={() => (paused = !paused)} />
|
||||||
|
|
||||||
{#each currentMemory.assets as _, i}
|
{#each currentMemory.assets as _, i}
|
||||||
<button class="relative w-full py-2" on:click={() => goto(`?memory=${memoryIndex}&asset=${i}`)}>
|
<button class="relative w-full py-2" on:click={() => goto(`?memory=${memoryIndex}&asset=${i}`)}>
|
||||||
@ -147,7 +142,7 @@
|
|||||||
class:opacity-100={galleryInView}
|
class:opacity-100={galleryInView}
|
||||||
>
|
>
|
||||||
<button on:click={() => memoryWrapper.scrollIntoView({ behavior: 'smooth' })} disabled={!galleryInView}>
|
<button on:click={() => memoryWrapper.scrollIntoView({ behavior: 'smooth' })} disabled={!galleryInView}>
|
||||||
<CircleIconButton logo={ChevronUp} backgroundColor="white" forceDark />
|
<CircleIconButton icon={mdiChevronUp} backgroundColor="white" forceDark />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -190,14 +185,14 @@
|
|||||||
<div class="ml-4 flex h-full flex-col place-content-center place-items-center">
|
<div class="ml-4 flex h-full flex-col place-content-center place-items-center">
|
||||||
<div class="inline-block">
|
<div class="inline-block">
|
||||||
{#if canGoBack}
|
{#if canGoBack}
|
||||||
<CircleIconButton logo={ChevronLeft} backgroundColor="#202123" on:click={toPrevious} />
|
<CircleIconButton icon={mdiChevronLeft} backgroundColor="#202123" on:click={toPrevious} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mr-4 flex h-full flex-col place-content-center place-items-center">
|
<div class="mr-4 flex h-full flex-col place-content-center place-items-center">
|
||||||
<div class="inline-block">
|
<div class="inline-block">
|
||||||
{#if canGoForward}
|
{#if canGoForward}
|
||||||
<CircleIconButton logo={ChevronRight} backgroundColor="#202123" on:click={toNext} />
|
<CircleIconButton icon={mdiChevronRight} backgroundColor="#202123" on:click={toNext} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -260,7 +255,7 @@
|
|||||||
class:opacity-100={!galleryInView}
|
class:opacity-100={!galleryInView}
|
||||||
>
|
>
|
||||||
<button on:click={() => memoryGallery.scrollIntoView({ behavior: 'smooth' })}>
|
<button on:click={() => memoryGallery.scrollIntoView({ behavior: 'smooth' })}>
|
||||||
<CircleIconButton logo={ChevronDown} backgroundColor="white" forceDark />
|
<CircleIconButton icon={mdiChevronDown} backgroundColor="white" forceDark />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -6,11 +6,9 @@
|
|||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { api } from '@api';
|
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 MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { OnArchive, getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { OnArchive, getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { mdiArchiveArrowUpOutline, mdiArchiveArrowDownOutline, mdiTimerSand } from '@mdi/js';
|
||||||
|
|
||||||
export let onArchive: OnArchive | undefined = undefined;
|
export let onArchive: OnArchive | undefined = undefined;
|
||||||
|
|
||||||
@ -18,7 +16,7 @@
|
|||||||
export let unarchive = false;
|
export let unarchive = false;
|
||||||
|
|
||||||
$: text = unarchive ? 'Unarchive' : 'Archive';
|
$: text = unarchive ? 'Unarchive' : 'Archive';
|
||||||
$: logo = unarchive ? ArchiveArrowUpOutline : ArchiveArrowDownOutline;
|
$: icon = unarchive ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline;
|
||||||
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
@ -62,8 +60,8 @@
|
|||||||
|
|
||||||
{#if !menuItem}
|
{#if !menuItem}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<CircleIconButton title="Loading" logo={TimerSand} />
|
<CircleIconButton title="Loading" icon={mdiTimerSand} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={text} {logo} on:click={handleArchive} />
|
<CircleIconButton title={text} {icon} on:click={handleArchive} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
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 CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
|
||||||
import ShareVariantOutline from 'svelte-material-icons/ShareVariantOutline.svelte';
|
import { mdiShareVariantOutline } from '@mdi/js';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
|
||||||
let showModal = false;
|
let showModal = false;
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
@ -14,7 +14,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CircleIconButton title="Share" logo={ShareVariantOutline} on:click={() => (showModal = true)} />
|
<CircleIconButton title="Share" icon={mdiShareVariantOutline} on:click={() => (showModal = true)} />
|
||||||
|
|
||||||
{#if showModal}
|
{#if showModal}
|
||||||
<CreateSharedLinkModal
|
<CreateSharedLinkModal
|
||||||
|
@ -7,13 +7,11 @@
|
|||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { api } from '@api';
|
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 MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { OnAssetDelete, getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { OnAssetDelete, getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
|
import { mdiTimerSand, mdiDeleteOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let onAssetDelete: OnAssetDelete;
|
export let onAssetDelete: OnAssetDelete;
|
||||||
export let menuItem = false;
|
export let menuItem = false;
|
||||||
@ -70,9 +68,9 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text={force ? 'Permanently Delete' : 'Delete'} on:click={handleTrash} />
|
<MenuOption text={force ? 'Permanently Delete' : 'Delete'} on:click={handleTrash} />
|
||||||
{:else if loading}
|
{:else if loading}
|
||||||
<CircleIconButton title="Loading" logo={TimerSand} />
|
<CircleIconButton title="Loading" icon={mdiTimerSand} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title="Delete" logo={DeleteOutline} on:click={handleTrash} />
|
<CircleIconButton title="Delete" icon={mdiDeleteOutline} on:click={handleTrash} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isShowConfirmation}
|
{#if isShowConfirmation}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import { downloadArchive, downloadFile } from '$lib/utils/asset-utils';
|
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 MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { mdiCloudDownloadOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let filename = 'immich.zip';
|
export let filename = 'immich.zip';
|
||||||
export let menuItem = false;
|
export let menuItem = false;
|
||||||
@ -26,5 +26,5 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text="Download" on:click={handleDownloadFiles} />
|
<MenuOption text="Download" on:click={handleDownloadFiles} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title="Download" logo={CloudDownloadOutline} on:click={handleDownloadFiles} />
|
<CircleIconButton title="Download" icon={mdiCloudDownloadOutline} on:click={handleDownloadFiles} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -7,10 +7,8 @@
|
|||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { api } from '@api';
|
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 { OnFavorite, getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { mdiHeartMinusOutline, mdiHeartOutline, mdiTimerSand } from '@mdi/js';
|
||||||
|
|
||||||
export let onFavorite: OnFavorite | undefined = undefined;
|
export let onFavorite: OnFavorite | undefined = undefined;
|
||||||
|
|
||||||
@ -18,7 +16,7 @@
|
|||||||
export let removeFavorite: boolean;
|
export let removeFavorite: boolean;
|
||||||
|
|
||||||
$: text = removeFavorite ? 'Remove from Favorites' : 'Favorite';
|
$: text = removeFavorite ? 'Remove from Favorites' : 'Favorite';
|
||||||
$: logo = removeFavorite ? HeartMinusOutline : HeartOutline;
|
$: icon = removeFavorite ? mdiHeartMinusOutline : mdiHeartOutline;
|
||||||
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
@ -62,8 +60,8 @@
|
|||||||
|
|
||||||
{#if !menuItem}
|
{#if !menuItem}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<CircleIconButton title="Loading" logo={TimerSand} />
|
<CircleIconButton title="Loading" icon={mdiTimerSand} />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleIconButton title={text} {logo} on:click={handleFavorite} />
|
<CircleIconButton title={text} {icon} on:click={handleFavorite} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
notificationController,
|
notificationController,
|
||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { AlbumResponseDto, api } from '@api';
|
import { AlbumResponseDto, api } from '@api';
|
||||||
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
|
|
||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { mdiDeleteOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let album: AlbumResponseDto;
|
export let album: AlbumResponseDto;
|
||||||
export let onRemove: ((assetIds: string[]) => void) | undefined = undefined;
|
export let onRemove: ((assetIds: string[]) => void) | undefined = undefined;
|
||||||
@ -53,7 +53,7 @@
|
|||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text="Remove from album" on:click={() => (isShowConfirmation = true)} />
|
<MenuOption text="Remove from album" on:click={() => (isShowConfirmation = true)} />
|
||||||
{:else}
|
{: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}
|
||||||
|
|
||||||
{#if isShowConfirmation}
|
{#if isShowConfirmation}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import { SharedLinkResponseDto, api } from '@api';
|
import { SharedLinkResponseDto, api } from '@api';
|
||||||
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
|
|
||||||
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
|
||||||
import { handleError } from '../../../utils/handle-error';
|
import { handleError } from '../../../utils/handle-error';
|
||||||
|
import { mdiDeleteOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let sharedLink: SharedLinkResponseDto;
|
export let sharedLink: SharedLinkResponseDto;
|
||||||
|
|
||||||
@ -45,7 +45,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</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}
|
{#if removing}
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { api } from '@api';
|
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 Button from '../../elements/buttons/button.svelte';
|
||||||
import { OnRestore, getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { OnRestore, getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
|
import { mdiHistory } from '@mdi/js';
|
||||||
|
|
||||||
export let onRestore: OnRestore | undefined = undefined;
|
export let onRestore: OnRestore | undefined = undefined;
|
||||||
|
|
||||||
@ -38,6 +39,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button disabled={loading} size="sm" color="transparent-gray" shadow={false} rounded="lg" on:click={handleRestore}>
|
<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>
|
<span class="ml-2">Restore</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -3,9 +3,8 @@
|
|||||||
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||||
import { BucketPosition, type AssetStore } from '$lib/stores/assets.store';
|
import { BucketPosition, type AssetStore } from '$lib/stores/assets.store';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
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 { get } from 'svelte/store';
|
||||||
|
import { mdiTimerSand, mdiSelectAll } from '@mdi/js';
|
||||||
|
|
||||||
export let assetStore: AssetStore;
|
export let assetStore: AssetStore;
|
||||||
export let assetInteractionStore: AssetInteractionStore;
|
export let assetInteractionStore: AssetInteractionStore;
|
||||||
@ -32,8 +31,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if selecting}
|
{#if selecting}
|
||||||
<CircleIconButton title="Delete" logo={TimerSand} />
|
<CircleIconButton title="Delete" icon={mdiTimerSand} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if !selecting}
|
{#if !selecting}
|
||||||
<CircleIconButton title="Select all" logo={SelectAll} on:click={handleSelectAll} />
|
<CircleIconButton title="Select all" icon={mdiSelectAll} on:click={handleSelectAll} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
import type { AssetResponseDto } from '@api';
|
import type { AssetResponseDto } from '@api';
|
||||||
import justifiedLayout from 'justified-layout';
|
import justifiedLayout from 'justified-layout';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import CheckCircle from 'svelte-material-icons/CheckCircle.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import CircleOutline from 'svelte-material-icons/CircleOutline.svelte';
|
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
|
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
|
||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||||
import type { AssetStore } from '$lib/stores/assets.store';
|
import type { AssetStore } from '$lib/stores/assets.store';
|
||||||
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||||
import type { Viewport } from '$lib/stores/assets.store';
|
import type { Viewport } from '$lib/stores/assets.store';
|
||||||
|
import { mdiCheckCircle, mdiCircleOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let assets: AssetResponseDto[];
|
export let assets: AssetResponseDto[];
|
||||||
export let bucketDate: string;
|
export let bucketDate: string;
|
||||||
@ -154,9 +154,9 @@
|
|||||||
on:keydown={() => handleSelectGroup(groupTitle, groupAssets)}
|
on:keydown={() => handleSelectGroup(groupTitle, groupAssets)}
|
||||||
>
|
>
|
||||||
{#if $selectedGroup.has(groupTitle)}
|
{#if $selectedGroup.has(groupTitle)}
|
||||||
<CheckCircle size="24" color="#4250af" />
|
<Icon path={mdiCheckCircle} size="24" color="#4250af" />
|
||||||
{:else}
|
{:else}
|
||||||
<CircleOutline size="24" color="#757575" />
|
<Icon path={mdiCircleOutline} size="24" color="#757575" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -9,10 +9,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
||||||
import type Icon from 'svelte-material-icons/AbTesting.svelte';
|
|
||||||
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
||||||
|
|
||||||
export let icon: typeof Icon;
|
export let icon: string;
|
||||||
export let title: string;
|
export let title: string;
|
||||||
|
|
||||||
let showContextMenu = false;
|
let showContextMenu = false;
|
||||||
@ -27,7 +26,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:clickOutside on:outclick={() => (showContextMenu = false)}>
|
<div use:clickOutside on:outclick={() => (showContextMenu = false)}>
|
||||||
<CircleIconButton {title} logo={icon} on:click={handleShowMenu} />
|
<CircleIconButton {title} {icon} on:click={handleShowMenu} />
|
||||||
{#if showContextMenu}
|
{#if showContextMenu}
|
||||||
<ContextMenu {...contextMenuPosition}>
|
<ContextMenu {...contextMenuPosition}>
|
||||||
<div class="flex flex-col rounded-lg">
|
<div class="flex flex-col rounded-lg">
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import type { AssetResponseDto } from '@api';
|
import type { AssetResponseDto } from '@api';
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
|
import { mdiClose } from '@mdi/js';
|
||||||
|
|
||||||
export let assets: Set<AssetResponseDto>;
|
export let assets: Set<AssetResponseDto>;
|
||||||
export let clearSelect: () => void;
|
export let clearSelect: () => void;
|
||||||
@ -28,7 +28,7 @@
|
|||||||
setContext({ getAssets: () => assets, clearSelect });
|
setContext({ getAssets: () => assets, clearSelect });
|
||||||
</script>
|
</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">
|
<p class="font-medium text-immich-primary dark:text-immich-dark-primary" slot="leading">
|
||||||
Selected {assets.size.toLocaleString($locale)}
|
Selected {assets.size.toLocaleString($locale)}
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { api } from '@api';
|
import { api } from '@api';
|
||||||
import ChevronLeft from 'svelte-material-icons/ChevronLeft.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import ChevronRight from 'svelte-material-icons/ChevronRight.svelte';
|
|
||||||
import { memoryStore } from '$lib/stores/memory.store';
|
import { memoryStore } from '$lib/stores/memory.store';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
|
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
|
||||||
|
|
||||||
$: shouldRender = $memoryStore?.length > 0;
|
$: 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"
|
class="rounded-full border border-gray-500 bg-gray-100 p-2 text-gray-500 opacity-50 hover:opacity-100"
|
||||||
on:click={scrollLeft}
|
on:click={scrollLeft}
|
||||||
>
|
>
|
||||||
<ChevronLeft size="36" /></button
|
<Icon path={mdiChevronLeft} size="36" /></button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/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"
|
class="rounded-full border border-gray-500 bg-gray-100 p-2 text-gray-500 opacity-50 hover:opacity-100"
|
||||||
on:click={scrollRight}
|
on:click={scrollRight}
|
||||||
>
|
>
|
||||||
<ChevronRight size="36" /></button
|
<Icon path={mdiChevronRight} size="36" /></button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -4,19 +4,16 @@
|
|||||||
import { downloadArchive } from '$lib/utils/asset-utils';
|
import { downloadArchive } from '$lib/utils/asset-utils';
|
||||||
import { api, AssetResponseDto, SharedLinkResponseDto } from '@api';
|
import { api, AssetResponseDto, SharedLinkResponseDto } from '@api';
|
||||||
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
|
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 CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import DownloadAction from '../photos-page/actions/download-action.svelte';
|
import DownloadAction from '../photos-page/actions/download-action.svelte';
|
||||||
import RemoveFromSharedLink from '../photos-page/actions/remove-from-shared-link.svelte';
|
import RemoveFromSharedLink from '../photos-page/actions/remove-from-shared-link.svelte';
|
||||||
import AssetSelectControlBar from '../photos-page/asset-select-control-bar.svelte';
|
import AssetSelectControlBar from '../photos-page/asset-select-control-bar.svelte';
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte';
|
import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte';
|
||||||
import SelectAll from 'svelte-material-icons/SelectAll.svelte';
|
|
||||||
import ImmichLogo from '../shared-components/immich-logo.svelte';
|
import ImmichLogo from '../shared-components/immich-logo.svelte';
|
||||||
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
|
import { mdiArrowLeft, mdiFileImagePlusOutline, mdiFolderDownloadOutline, mdiSelectAll } from '@mdi/js';
|
||||||
|
|
||||||
export let sharedLink: SharedLinkResponseDto;
|
export let sharedLink: SharedLinkResponseDto;
|
||||||
export let isOwned: boolean;
|
export let isOwned: boolean;
|
||||||
@ -72,7 +69,7 @@
|
|||||||
<section class="bg-immich-bg dark:bg-immich-dark-bg">
|
<section class="bg-immich-bg dark:bg-immich-dark-bg">
|
||||||
{#if isMultiSelectionMode}
|
{#if isMultiSelectionMode}
|
||||||
<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}>
|
<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}
|
{#if sharedLink?.allowDownload}
|
||||||
<DownloadAction filename="immich-shared.zip" />
|
<DownloadAction filename="immich-shared.zip" />
|
||||||
{/if}
|
{/if}
|
||||||
@ -81,7 +78,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</AssetSelectControlBar>
|
</AssetSelectControlBar>
|
||||||
{:else}
|
{: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">
|
<svelte:fragment slot="leading">
|
||||||
<a
|
<a
|
||||||
data-sveltekit-preload-data="hover"
|
data-sveltekit-preload-data="hover"
|
||||||
@ -95,11 +92,11 @@
|
|||||||
|
|
||||||
<svelte:fragment slot="trailing">
|
<svelte:fragment slot="trailing">
|
||||||
{#if sharedLink?.allowUpload}
|
{#if sharedLink?.allowUpload}
|
||||||
<CircleIconButton title="Add Photos" on:click={() => handleUploadAssets()} logo={FileImagePlusOutline} />
|
<CircleIconButton title="Add Photos" on:click={() => handleUploadAssets()} icon={mdiFileImagePlusOutline} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if sharedLink?.allowDownload}
|
{#if sharedLink?.allowDownload}
|
||||||
<CircleIconButton title="Download" on:click={downloadAssets} logo={FolderDownloadOutline} />
|
<CircleIconButton title="Download" on:click={downloadAssets} icon={mdiFolderDownloadOutline} />
|
||||||
{/if}
|
{/if}
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ControlAppBar>
|
</ControlAppBar>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AlbumResponseDto, api } from '@api';
|
import { AlbumResponseDto, api } from '@api';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
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 BaseModal from './base-modal.svelte';
|
||||||
import AlbumListItem from '../asset-viewer/album-list-item.svelte';
|
import AlbumListItem from '../asset-viewer/album-list-item.svelte';
|
||||||
|
import { mdiPlus } from '@mdi/js';
|
||||||
|
|
||||||
let albums: AlbumResponseDto[] = [];
|
let albums: AlbumResponseDto[] = [];
|
||||||
let recentAlbums: 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"
|
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">
|
<div class="flex h-12 w-12 items-center justify-center">
|
||||||
<Plus size="30" />
|
<Icon path={mdiPlus} size="30" />
|
||||||
</div>
|
</div>
|
||||||
<p class="">
|
<p class="">
|
||||||
New {#if shared}Shared {/if}Album {#if search.length > 0}<b>{search}</b>{/if}
|
New {#if shared}Shared {/if}Album {#if search.length > 0}<b>{search}</b>{/if}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
|
||||||
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
|
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
|
import { mdiClose } from '@mdi/js';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
export let zIndex = 9999;
|
export let zIndex = 9999;
|
||||||
@ -46,7 +46,7 @@
|
|||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CircleIconButton on:click={() => dispatch('close')} logo={Close} size={'20'} />
|
<CircleIconButton on:click={() => dispatch('close')} icon={mdiClose} size={'20'} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="">
|
<div class="">
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
|
|
||||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
|
import { mdiClose } from '@mdi/js';
|
||||||
|
|
||||||
export let showBackButton = true;
|
export let showBackButton = true;
|
||||||
export let backIcon = Close;
|
export let backIcon = mdiClose;
|
||||||
export let tailwindClasses = '';
|
export let tailwindClasses = '';
|
||||||
export let forceDark = false;
|
export let forceDark = false;
|
||||||
|
|
||||||
@ -51,7 +51,7 @@
|
|||||||
{#if showBackButton}
|
{#if showBackButton}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
on:click={() => dispatch('close-button-click')}
|
on:click={() => dispatch('close-button-click')}
|
||||||
logo={backIcon}
|
icon={backIcon}
|
||||||
backgroundColor={'transparent'}
|
backgroundColor={'transparent'}
|
||||||
hoverColor={'#e2e7e9'}
|
hoverColor={'#e2e7e9'}
|
||||||
size={'24'}
|
size={'24'}
|
||||||
|
@ -7,11 +7,12 @@
|
|||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { api, copyToClipboard, SharedLinkResponseDto, SharedLinkType } from '@api';
|
import { api, copyToClipboard, SharedLinkResponseDto, SharedLinkType } from '@api';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
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 BaseModal from '../base-modal.svelte';
|
||||||
import type { ImmichDropDownOption } from '../dropdown-button.svelte';
|
import type { ImmichDropDownOption } from '../dropdown-button.svelte';
|
||||||
import DropdownButton from '../dropdown-button.svelte';
|
import DropdownButton from '../dropdown-button.svelte';
|
||||||
import { notificationController, NotificationType } from '../notification/notification';
|
import { notificationController, NotificationType } from '../notification/notification';
|
||||||
|
import { mdiLink } from '@mdi/js';
|
||||||
|
|
||||||
export let albumId: string | undefined = undefined;
|
export let albumId: string | undefined = undefined;
|
||||||
export let assetIds: string[] = [];
|
export let assetIds: string[] = [];
|
||||||
@ -140,7 +141,7 @@
|
|||||||
<BaseModal on:close={() => dispatch('close')} on:escape={() => dispatch('escape')}>
|
<BaseModal on:close={() => dispatch('close')} on:escape={() => dispatch('escape')}>
|
||||||
<svelte:fragment slot="title">
|
<svelte:fragment slot="title">
|
||||||
<span class="flex place-items-center gap-2">
|
<span class="flex place-items-center gap-2">
|
||||||
<Link size={24} />
|
<Icon path={mdiLink} size={24} />
|
||||||
{#if editingLink}
|
{#if editingLink}
|
||||||
<p class="font-medium text-immich-fg dark:text-immich-dark-fg">Edit link</p>
|
<p class="font-medium text-immich-fg dark:text-immich-dark-fg">Edit link</p>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import type { UserResponseDto } from '@api';
|
import type { UserResponseDto } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Cog from 'svelte-material-icons/Cog.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import Logout from 'svelte-material-icons/Logout.svelte';
|
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import UserAvatar from '../user-avatar.svelte';
|
import UserAvatar from '../user-avatar.svelte';
|
||||||
|
import { mdiCog, mdiLogout } from '@mdi/js';
|
||||||
|
|
||||||
export let user: UserResponseDto;
|
export let user: UserResponseDto;
|
||||||
|
|
||||||
@ -35,7 +35,7 @@
|
|||||||
<a href={AppRoute.USER_SETTINGS} on:click={() => dispatch('close')}>
|
<a href={AppRoute.USER_SETTINGS} on:click={() => dispatch('close')}>
|
||||||
<Button color="dark-gray" size="sm" shadow={false} border>
|
<Button color="dark-gray" size="sm" shadow={false} border>
|
||||||
<div class="flex place-content-center place-items-center gap-2 px-2">
|
<div class="flex place-content-center place-items-center gap-2 px-2">
|
||||||
<Cog size="18" />
|
<Icon path={mdiCog} size="18" />
|
||||||
Account Settings
|
Account Settings
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</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"
|
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')}
|
on:click={() => dispatch('logout')}
|
||||||
>
|
>
|
||||||
<Logout size={24} />
|
<Icon path={mdiLogout} size={24} />
|
||||||
Sign Out</button
|
Sign Out</button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { fade, fly } from 'svelte/transition';
|
import { fade, fly } from 'svelte/transition';
|
||||||
import TrayArrowUp from 'svelte-material-icons/TrayArrowUp.svelte';
|
|
||||||
import { api, UserResponseDto } from '@api';
|
import { api, UserResponseDto } from '@api';
|
||||||
import ThemeButton from '../theme-button.svelte';
|
import ThemeButton from '../theme-button.svelte';
|
||||||
import { AppRoute } from '../../../constants';
|
import { AppRoute } from '../../../constants';
|
||||||
@ -12,11 +11,11 @@
|
|||||||
import ImmichLogo from '../immich-logo.svelte';
|
import ImmichLogo from '../immich-logo.svelte';
|
||||||
import SearchBar from '../search-bar/search-bar.svelte';
|
import SearchBar from '../search-bar/search-bar.svelte';
|
||||||
import LinkButton from '$lib/components/elements/buttons/link-button.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 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 UserAvatar from '../user-avatar.svelte';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
|
import { mdiMagnify, mdiTrayArrowUp, mdiCog } from '@mdi/js';
|
||||||
export let user: UserResponseDto;
|
export let user: UserResponseDto;
|
||||||
export let showUploadButton = true;
|
export let showUploadButton = true;
|
||||||
|
|
||||||
@ -56,7 +55,7 @@
|
|||||||
<a href={AppRoute.SEARCH} id="search-button" class="pl-4 sm:hidden">
|
<a href={AppRoute.SEARCH} id="search-button" class="pl-4 sm:hidden">
|
||||||
<IconButton title="Search">
|
<IconButton title="Search">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Magnify size="1.5em" />
|
<Icon path={mdiMagnify} size="1.5em" />
|
||||||
</div>
|
</div>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</a>
|
</a>
|
||||||
@ -68,7 +67,7 @@
|
|||||||
<div in:fly={{ x: 50, duration: 250 }}>
|
<div in:fly={{ x: 50, duration: 250 }}>
|
||||||
<LinkButton on:click={() => dispatch('uploadClicked')}>
|
<LinkButton on:click={() => dispatch('uploadClicked')}>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<TrayArrowUp size="1.5em" />
|
<Icon path={mdiTrayArrowUp} size="1.5em" />
|
||||||
<span class="hidden md:block">Upload</span>
|
<span class="hidden md:block">Upload</span>
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
@ -95,7 +94,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="block sm:hidden" aria-hidden="true">
|
<div class="block sm:hidden" aria-hidden="true">
|
||||||
<Cog
|
<Icon
|
||||||
|
path={mdiCog}
|
||||||
size="1.5em"
|
size="1.5em"
|
||||||
class="dark:text-immich-dark-fg {$page.url.pathname.includes('/admin')
|
class="dark:text-immich-dark-fg {$page.url.pathname.includes('/admin')
|
||||||
? 'text-immich-primary dark:text-immich-dark-primary'
|
? 'text-immich-primary dark:text-immich-dark-primary'
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import CloseCircleOutline from 'svelte-material-icons/CloseCircleOutline.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
|
|
||||||
import WindowClose from 'svelte-material-icons/WindowClose.svelte';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ImmichNotification,
|
ImmichNotification,
|
||||||
notificationController,
|
notificationController,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { mdiCloseCircleOutline, mdiInformationOutline, mdiWindowClose } from '@mdi/js';
|
||||||
|
|
||||||
export let notificationInfo: ImmichNotification;
|
export let notificationInfo: ImmichNotification;
|
||||||
|
|
||||||
@ -17,7 +15,7 @@
|
|||||||
let errorPrimaryColor = '#E64132';
|
let errorPrimaryColor = '#E64132';
|
||||||
let warningPrimaryColor = '#D08613';
|
let warningPrimaryColor = '#D08613';
|
||||||
|
|
||||||
$: icon = notificationInfo.type === NotificationType.Error ? CloseCircleOutline : InformationOutline;
|
$: icon = notificationInfo.type === NotificationType.Error ? mdiCloseCircleOutline : mdiInformationOutline;
|
||||||
|
|
||||||
$: backgroundColor = () => {
|
$: backgroundColor = () => {
|
||||||
if (notificationInfo.type === NotificationType.Info) {
|
if (notificationInfo.type === NotificationType.Info) {
|
||||||
@ -93,13 +91,13 @@
|
|||||||
>
|
>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="flex place-items-center gap-2">
|
<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">
|
<h2 style:color={primaryColor()} class="font-medium" data-testid="title">
|
||||||
{notificationInfo.type.toString()}
|
{notificationInfo.type.toString()}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<button on:click|stopPropagation={discard}>
|
<button on:click|stopPropagation={discard}>
|
||||||
<svelte:component this={WindowClose} size="20" />
|
<Icon path={mdiWindowClose} size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import Magnify from 'svelte-material-icons/Magnify.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { isSearchEnabled, preventRaceConditionSearchBar, savedSearchTerms } from '$lib/stores/search.store';
|
import { isSearchEnabled, preventRaceConditionSearchBar, savedSearchTerms } from '$lib/stores/search.store';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
|
import { mdiClose, mdiMagnify } from '@mdi/js';
|
||||||
export let value = '';
|
export let value = '';
|
||||||
export let grayTheme: boolean;
|
export let grayTheme: boolean;
|
||||||
|
|
||||||
@ -82,7 +82,7 @@
|
|||||||
<div class="absolute inset-y-0 left-0 flex items-center pl-6">
|
<div class="absolute inset-y-0 left-0 flex items-center pl-6">
|
||||||
<div class="dark:text-immich-dark-fg/75">
|
<div class="dark:text-immich-dark-fg/75">
|
||||||
<button class="flex items-center">
|
<button class="flex items-center">
|
||||||
<Magnify size="1.5em" />
|
<Icon path={mdiMagnify} size="1.5em" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -108,7 +108,7 @@
|
|||||||
type="reset"
|
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]"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -153,11 +153,13 @@
|
|||||||
onSearch();
|
onSearch();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Magnify size="1.5em" />
|
<Icon path={mdiMagnify} size="1.5em" />
|
||||||
{savedSearchTerm}
|
{savedSearchTerm}
|
||||||
</button>
|
</button>
|
||||||
<div class="absolute right-5 top-0 items-center justify-center py-3">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import FullScreenModal from './full-screen-modal.svelte';
|
import FullScreenModal from './full-screen-modal.svelte';
|
||||||
|
import { mdiClose } from '@mdi/js';
|
||||||
|
|
||||||
const shortcuts = {
|
const shortcuts = {
|
||||||
general: [
|
general: [
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<div class="relative px-4 pt-4">
|
<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>
|
<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">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -4,32 +4,28 @@
|
|||||||
import SideBarSection from '$lib/components/shared-components/side-bar/side-bar-section.svelte';
|
import SideBarSection from '$lib/components/shared-components/side-bar/side-bar-section.svelte';
|
||||||
import StatusBox from '$lib/components/shared-components/status-box.svelte';
|
import StatusBox from '$lib/components/shared-components/status-box.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import AccountMultipleOutline from 'svelte-material-icons/AccountMultipleOutline.svelte';
|
import { mdiAccountMultipleOutline, mdiCog, mdiServer, mdiSync, mdiTools } from '@mdi/js';
|
||||||
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';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SideBarSection>
|
<SideBarSection>
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_USER_MANAGEMENT} draggable="false">
|
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_USER_MANAGEMENT} draggable="false">
|
||||||
<SideBarButton
|
<SideBarButton
|
||||||
title="Users"
|
title="Users"
|
||||||
logo={AccountMultipleOutline}
|
icon={mdiAccountMultipleOutline}
|
||||||
isSelected={$page.route.id === AppRoute.ADMIN_USER_MANAGEMENT}
|
isSelected={$page.route.id === AppRoute.ADMIN_USER_MANAGEMENT}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_JOBS} draggable="false">
|
<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>
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_SETTINGS} draggable="false">
|
<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>
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_STATS} draggable="false">
|
<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>
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.ADMIN_REPAIR} draggable="false">
|
<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>
|
</a>
|
||||||
<div class="mb-6 mt-auto">
|
<div class="mb-6 mt-auto">
|
||||||
<StatusBox />
|
<StatusBox />
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<script lang="ts">
|
<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 { 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 title: string;
|
||||||
export let logo: typeof Icon;
|
export let icon: string;
|
||||||
export let isSelected: boolean;
|
export let isSelected: boolean;
|
||||||
export let flippedLogo = false;
|
export let flippedLogo = false;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div class="flex w-full place-items-center gap-4 overflow-hidden truncate">
|
<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>
|
<p class="text-sm font-medium">{title}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -41,7 +41,7 @@
|
|||||||
on:mouseleave={() => (showMoreInformation = false)}
|
on:mouseleave={() => (showMoreInformation = false)}
|
||||||
>
|
>
|
||||||
<div class="p-1 text-gray-600 hover:cursor-help dark:text-gray-400">
|
<div class="p-1 text-gray-600 hover:cursor-help dark:text-gray-400">
|
||||||
<InformationOutline />
|
<Icon path={mdiInformationOutline} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if showMoreInformation}
|
{#if showMoreInformation}
|
||||||
|
@ -1,25 +1,27 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
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 { AssetApiGetAssetStatsRequest, api } from '@api';
|
||||||
import AccountMultipleOutline from 'svelte-material-icons/AccountMultipleOutline.svelte';
|
import {
|
||||||
import AccountMultiple from 'svelte-material-icons/AccountMultiple.svelte';
|
mdiAccount,
|
||||||
import ImageAlbum from 'svelte-material-icons/ImageAlbum.svelte';
|
mdiAccountMultiple,
|
||||||
import ImageMultipleOutline from 'svelte-material-icons/ImageMultipleOutline.svelte';
|
mdiAccountMultipleOutline,
|
||||||
import ImageMultiple from 'svelte-material-icons/ImageMultiple.svelte';
|
mdiArchiveArrowDownOutline,
|
||||||
import ArchiveArrowDownOutline from 'svelte-material-icons/ArchiveArrowDownOutline.svelte';
|
mdiHeartMultiple,
|
||||||
import Magnify from 'svelte-material-icons/Magnify.svelte';
|
mdiHeartMultipleOutline,
|
||||||
import Map from 'svelte-material-icons/Map.svelte';
|
mdiImageAlbum,
|
||||||
import Account from 'svelte-material-icons/Account.svelte';
|
mdiImageMultiple,
|
||||||
import TrashCanOutline from 'svelte-material-icons/TrashCanOutline.svelte';
|
mdiImageMultipleOutline,
|
||||||
import HeartMultipleOutline from 'svelte-material-icons/HeartMultipleOutline.svelte';
|
mdiMagnify,
|
||||||
import HeartMultiple from 'svelte-material-icons/HeartMultiple.svelte';
|
mdiMap,
|
||||||
|
mdiTrashCanOutline,
|
||||||
|
} from '@mdi/js';
|
||||||
import { AppRoute } from '../../../constants';
|
import { AppRoute } from '../../../constants';
|
||||||
import LoadingSpinner from '../loading-spinner.svelte';
|
import LoadingSpinner from '../loading-spinner.svelte';
|
||||||
import StatusBox from '../status-box.svelte';
|
import StatusBox from '../status-box.svelte';
|
||||||
import SideBarButton from './side-bar-button.svelte';
|
import SideBarButton from './side-bar-button.svelte';
|
||||||
import { locale, sidebarSettings } from '$lib/stores/preferences.store';
|
|
||||||
import SideBarSection from './side-bar-section.svelte';
|
import SideBarSection from './side-bar-section.svelte';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
|
||||||
|
|
||||||
const getStats = async (dto: AssetApiGetAssetStatsRequest) => {
|
const getStats = async (dto: AssetApiGetAssetStatsRequest) => {
|
||||||
const { data: stats } = await api.assetApi.getAssetStats(dto);
|
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">
|
<a data-sveltekit-preload-data="hover" data-sveltekit-noscroll href={AppRoute.PHOTOS} draggable="false">
|
||||||
<SideBarButton
|
<SideBarButton
|
||||||
title="Photos"
|
title="Photos"
|
||||||
logo={isPhotosSelected ? ImageMultiple : ImageMultipleOutline}
|
icon={isPhotosSelected ? mdiImageMultiple : mdiImageMultipleOutline}
|
||||||
isSelected={isPhotosSelected}
|
isSelected={isPhotosSelected}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="moreInformation">
|
<svelte:fragment slot="moreInformation">
|
||||||
@ -62,23 +64,23 @@
|
|||||||
</a>
|
</a>
|
||||||
{#if $featureFlags.search}
|
{#if $featureFlags.search}
|
||||||
<a data-sveltekit-preload-data="hover" data-sveltekit-noscroll href={AppRoute.EXPLORE} draggable="false">
|
<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>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $featureFlags.map}
|
{#if $featureFlags.map}
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.MAP} draggable="false">
|
<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>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $sidebarSettings.people}
|
{#if $sidebarSettings.people}
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.PEOPLE} draggable="false">
|
<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>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.SHARING} draggable="false">
|
<a data-sveltekit-preload-data="hover" href={AppRoute.SHARING} draggable="false">
|
||||||
<SideBarButton
|
<SideBarButton
|
||||||
title="Sharing"
|
title="Sharing"
|
||||||
logo={isSharingSelected ? AccountMultiple : AccountMultipleOutline}
|
icon={isSharingSelected ? mdiAccountMultiple : mdiAccountMultipleOutline}
|
||||||
isSelected={isSharingSelected}
|
isSelected={isSharingSelected}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="moreInformation">
|
<svelte:fragment slot="moreInformation">
|
||||||
@ -100,7 +102,7 @@
|
|||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.FAVORITES} draggable="false">
|
<a data-sveltekit-preload-data="hover" href={AppRoute.FAVORITES} draggable="false">
|
||||||
<SideBarButton
|
<SideBarButton
|
||||||
title="Favorites"
|
title="Favorites"
|
||||||
logo={isFavoritesSelected ? HeartMultiple : HeartMultipleOutline}
|
icon={isFavoritesSelected ? mdiHeartMultiple : mdiHeartMultipleOutline}
|
||||||
isSelected={isFavoritesSelected}
|
isSelected={isFavoritesSelected}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="moreInformation">
|
<svelte:fragment slot="moreInformation">
|
||||||
@ -116,7 +118,12 @@
|
|||||||
</SideBarButton>
|
</SideBarButton>
|
||||||
</a>
|
</a>
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.ALBUMS} draggable="false">
|
<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">
|
<svelte:fragment slot="moreInformation">
|
||||||
{#await getAlbumCount()}
|
{#await getAlbumCount()}
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
@ -129,7 +136,7 @@
|
|||||||
</SideBarButton>
|
</SideBarButton>
|
||||||
</a>
|
</a>
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.ARCHIVE} draggable="false">
|
<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">
|
<svelte:fragment slot="moreInformation">
|
||||||
{#await getStats({ isArchived: true })}
|
{#await getStats({ isArchived: true })}
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
@ -145,7 +152,7 @@
|
|||||||
|
|
||||||
{#if $featureFlags.trash}
|
{#if $featureFlags.trash}
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.TRASH} draggable="false">
|
<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">
|
<svelte:fragment slot="moreInformation">
|
||||||
{#await getStats({ isTrashed: true })}
|
{#await getStats({ isTrashed: true })}
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
import { websocketStore } from '$lib/stores/websocket';
|
import { websocketStore } from '$lib/stores/websocket';
|
||||||
import { ServerInfoResponseDto, api } from '@api';
|
import { ServerInfoResponseDto, api } from '@api';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import Cloud from 'svelte-material-icons/Cloud.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import Dns from 'svelte-material-icons/Dns.svelte';
|
|
||||||
import { asByteUnitString } from '../../utils/byte-units';
|
import { asByteUnitString } from '../../utils/byte-units';
|
||||||
import LoadingSpinner from './loading-spinner.svelte';
|
import LoadingSpinner from './loading-spinner.svelte';
|
||||||
|
import { mdiCloud, mdiDns } from '@mdi/js';
|
||||||
|
|
||||||
const { serverVersion, connected } = websocketStore;
|
const { serverVersion, connected } = websocketStore;
|
||||||
|
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<div class="dark:text-immich-dark-fg">
|
<div class="dark:text-immich-dark-fg">
|
||||||
<div class="storage-status grid grid-cols-[64px_auto]">
|
<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">
|
<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>
|
||||||
<div class="hidden group-hover:sm:block md:block">
|
<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>
|
<p class="text-sm font-medium text-immich-primary dark:text-immich-dark-primary">Storage</p>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="server-status grid grid-cols-[64px_auto]">
|
<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">
|
<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>
|
||||||
<div class="hidden text-xs group-hover:sm:block md:block">
|
<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>
|
<p class="text-sm font-medium text-immich-primary dark:text-immich-dark-primary">Server</p>
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
import ImmichLogo from './immich-logo.svelte';
|
import ImmichLogo from './immich-logo.svelte';
|
||||||
import { getFilenameExtension } from '$lib/utils/asset-utils';
|
import { getFilenameExtension } from '$lib/utils/asset-utils';
|
||||||
import { uploadAssetsStore } from '$lib/stores/upload';
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
||||||
import Cancel from 'svelte-material-icons/Cancel.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import Refresh from 'svelte-material-icons/Refresh.svelte';
|
|
||||||
import { fileUploadHandler } from '$lib/utils/file-uploader';
|
import { fileUploadHandler } from '$lib/utils/file-uploader';
|
||||||
|
import { mdiRefresh, mdiCancel } from '@mdi/js';
|
||||||
|
|
||||||
export let uploadAsset: UploadAsset;
|
export let uploadAsset: UploadAsset;
|
||||||
|
|
||||||
@ -84,14 +84,14 @@
|
|||||||
title="Retry upload"
|
title="Retry upload"
|
||||||
class="flex h-full w-full place-content-center place-items-center text-sm"
|
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>
|
||||||
<button
|
<button
|
||||||
on:click={() => uploadAssetsStore.removeUploadAsset(uploadAsset.id)}
|
on:click={() => uploadAssetsStore.removeUploadAsset(uploadAsset.id)}
|
||||||
title="Dismiss error"
|
title="Dismiss error"
|
||||||
class="flex h-full w-full place-content-center place-items-center text-sm"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,14 +2,12 @@
|
|||||||
import { quartInOut } from 'svelte/easing';
|
import { quartInOut } from 'svelte/easing';
|
||||||
import { fade, scale } from 'svelte/transition';
|
import { fade, scale } from 'svelte/transition';
|
||||||
import { uploadAssetsStore } from '$lib/stores/upload';
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
||||||
import CloudUploadOutline from 'svelte-material-icons/CloudUploadOutline.svelte';
|
import Icon from '$lib/components/elements/icon.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 { notificationController, NotificationType } from './notification/notification';
|
import { notificationController, NotificationType } from './notification/notification';
|
||||||
import UploadAssetPreview from './upload-asset-preview.svelte';
|
import UploadAssetPreview from './upload-asset-preview.svelte';
|
||||||
import { uploadExecutionQueue } from '$lib/utils/file-uploader';
|
import { uploadExecutionQueue } from '$lib/utils/file-uploader';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
|
import { mdiCog, mdiWindowMinimize, mdiCancel, mdiCloudUploadOutline } from '@mdi/js';
|
||||||
|
|
||||||
let showDetail = false;
|
let showDetail = false;
|
||||||
let showOptions = false;
|
let showOptions = false;
|
||||||
@ -75,14 +73,14 @@
|
|||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="Toggle settings"
|
title="Toggle settings"
|
||||||
logo={Cog}
|
icon={mdiCog}
|
||||||
size="14"
|
size="14"
|
||||||
padding="1"
|
padding="1"
|
||||||
on:click={() => (showOptions = !showOptions)}
|
on:click={() => (showOptions = !showOptions)}
|
||||||
/>
|
/>
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="Minimize"
|
title="Minimize"
|
||||||
logo={WindowMinimize}
|
icon={mdiWindowMinimize}
|
||||||
size="14"
|
size="14"
|
||||||
padding="1"
|
padding="1"
|
||||||
on:click={() => (showDetail = false)}
|
on:click={() => (showDetail = false)}
|
||||||
@ -91,7 +89,7 @@
|
|||||||
{#if $hasError}
|
{#if $hasError}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="Dismiss all errors"
|
title="Dismiss all errors"
|
||||||
logo={Cancel}
|
icon={mdiCancel}
|
||||||
size="14"
|
size="14"
|
||||||
padding="1"
|
padding="1"
|
||||||
on:click={() => uploadAssetsStore.dismissErrors()}
|
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"
|
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">
|
<div class="animate-pulse">
|
||||||
<CloudUploadOutline size="30" />
|
<Icon path={mdiCloudUploadOutline} size="30" />
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { api, AssetResponseDto, SharedLinkResponseDto, SharedLinkType, ThumbnailFormat } from '@api';
|
import { api, AssetResponseDto, SharedLinkResponseDto, SharedLinkType, ThumbnailFormat } from '@api';
|
||||||
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
||||||
import OpenInNew from 'svelte-material-icons/OpenInNew.svelte';
|
import Icon from '$lib/components/elements/icon.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 * as luxon from 'luxon';
|
import * as luxon from 'luxon';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiOpenInNew } from '@mdi/js';
|
||||||
|
|
||||||
export let link: SharedLinkResponseDto;
|
export let link: SharedLinkResponseDto;
|
||||||
|
|
||||||
@ -110,7 +108,7 @@
|
|||||||
on:click={() => goto(`/share/${link.key}`)}
|
on:click={() => goto(`/share/${link.key}`)}
|
||||||
on:keydown={() => goto(`/share/${link.key}`)}
|
on:keydown={() => goto(`/share/${link.key}`)}
|
||||||
>
|
>
|
||||||
<OpenInNew />
|
<Icon path={mdiOpenInNew} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
@ -148,9 +146,9 @@
|
|||||||
|
|
||||||
<div class="flex flex-auto flex-col place-content-center place-items-end text-right">
|
<div class="flex flex-auto flex-col place-content-center place-items-end text-right">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<CircleIconButton logo={Delete} on:click={() => dispatch('delete')} />
|
<CircleIconButton icon={mdiDelete} on:click={() => dispatch('delete')} />
|
||||||
<CircleIconButton logo={CircleEditOutline} on:click={() => dispatch('edit')} />
|
<CircleIconButton icon={mdiCircleEditOutline} on:click={() => dispatch('edit')} />
|
||||||
<CircleIconButton logo={ContentCopy} on:click={() => dispatch('copy')} />
|
<CircleIconButton icon={mdiContentCopy} on:click={() => dispatch('copy')} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
import type { AuthDeviceResponseDto } from '@api';
|
import type { AuthDeviceResponseDto } from '@api';
|
||||||
import { DateTime, ToRelativeCalendarOptions } from 'luxon';
|
import { DateTime, ToRelativeCalendarOptions } from 'luxon';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Android from 'svelte-material-icons/Android.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import Apple from 'svelte-material-icons/Apple.svelte';
|
import {
|
||||||
import AppleSafari from 'svelte-material-icons/AppleSafari.svelte';
|
mdiAndroid,
|
||||||
import GoogleChrome from 'svelte-material-icons/GoogleChrome.svelte';
|
mdiApple,
|
||||||
import Help from 'svelte-material-icons/Help.svelte';
|
mdiAppleSafari,
|
||||||
import Linux from 'svelte-material-icons/Linux.svelte';
|
mdiMicrosoftWindows,
|
||||||
import MicrosoftWindows from 'svelte-material-icons/MicrosoftWindows.svelte';
|
mdiLinux,
|
||||||
import TrashCanOutline from 'svelte-material-icons/TrashCanOutline.svelte';
|
mdiGoogleChrome,
|
||||||
|
mdiTrashCanOutline,
|
||||||
|
mdiHelp,
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
export let device: AuthDeviceResponseDto;
|
export let device: AuthDeviceResponseDto;
|
||||||
|
|
||||||
@ -26,19 +29,19 @@
|
|||||||
<!-- TODO: Device Image -->
|
<!-- TODO: Device Image -->
|
||||||
<div class="hidden items-center justify-center pr-2 text-immich-primary dark:text-immich-dark-primary sm:flex">
|
<div class="hidden items-center justify-center pr-2 text-immich-primary dark:text-immich-dark-primary sm:flex">
|
||||||
{#if device.deviceOS === 'Android'}
|
{#if device.deviceOS === 'Android'}
|
||||||
<Android size="40" />
|
<Icon path={mdiAndroid} size="40" />
|
||||||
{:else if device.deviceOS === 'iOS' || device.deviceOS === 'Mac OS'}
|
{:else if device.deviceOS === 'iOS' || device.deviceOS === 'Mac OS'}
|
||||||
<Apple size="40" />
|
<Icon path={mdiApple} size="40" />
|
||||||
{:else if device.deviceOS.indexOf('Safari') !== -1}
|
{:else if device.deviceOS.indexOf('Safari') !== -1}
|
||||||
<AppleSafari size="40" />
|
<Icon path={mdiAppleSafari} size="40" />
|
||||||
{:else if device.deviceOS.indexOf('Windows') !== -1}
|
{:else if device.deviceOS.indexOf('Windows') !== -1}
|
||||||
<MicrosoftWindows size="40" />
|
<Icon path={mdiMicrosoftWindows} size="40" />
|
||||||
{:else if device.deviceOS === 'Linux'}
|
{: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'}
|
{:else if device.deviceOS === 'Chromium OS' || device.deviceType === 'Chrome' || device.deviceType === 'Chromium'}
|
||||||
<GoogleChrome size="40" />
|
<Icon path={mdiGoogleChrome} size="40" />
|
||||||
{:else}
|
{:else}
|
||||||
<Help size="40" />
|
<Icon path={mdiHelp} size="40" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex grow flex-row justify-between gap-1 pl-4 sm:pl-0">
|
<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"
|
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"
|
title="Log out"
|
||||||
>
|
>
|
||||||
<TrashCanOutline size="16" />
|
<Icon path={mdiTrashCanOutline} size="16" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -6,9 +6,7 @@
|
|||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import Database from 'svelte-material-icons/Database.svelte';
|
|
||||||
import Upload from 'svelte-material-icons/Upload.svelte';
|
|
||||||
import Pulse from 'svelte-loading-spinners/Pulse.svelte';
|
import Pulse from 'svelte-loading-spinners/Pulse.svelte';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import LibraryImportPathsForm from '../forms/library-import-paths-form.svelte';
|
import LibraryImportPathsForm from '../forms/library-import-paths-form.svelte';
|
||||||
@ -19,6 +17,7 @@
|
|||||||
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
||||||
|
import { mdiDatabase, mdiDotsVertical, mdiUpload } from '@mdi/js';
|
||||||
|
|
||||||
let libraries: LibraryResponseDto[] = [];
|
let libraries: LibraryResponseDto[] = [];
|
||||||
|
|
||||||
@ -317,9 +316,9 @@
|
|||||||
>
|
>
|
||||||
<td class="w-1/6 px-10 text-sm">
|
<td class="w-1/6 px-10 text-sm">
|
||||||
{#if library.type === LibraryType.External}
|
{#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}
|
{: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
|
{/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"
|
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)}
|
on:click|stopPropagation|preventDefault={(e) => showMenu(e, library, index)}
|
||||||
>
|
>
|
||||||
<DotsVertical size="16" />
|
<Icon path={mdiDotsVertical} size="16" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{#if showContextMenu}
|
{#if showContextMenu}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { UserResponseDto, api } from '@api';
|
import { UserResponseDto, api } from '@api';
|
||||||
import UserAvatar from '../shared-components/user-avatar.svelte';
|
import UserAvatar from '../shared-components/user-avatar.svelte';
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import PartnerSelectionModal from './partner-selection-modal.svelte';
|
import PartnerSelectionModal from './partner-selection-modal.svelte';
|
||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
|
import { mdiClose } from '@mdi/js';
|
||||||
|
|
||||||
export let user: UserResponseDto;
|
export let user: UserResponseDto;
|
||||||
|
|
||||||
@ -64,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
on:click={() => (removePartner = partner)}
|
on:click={() => (removePartner = partner)}
|
||||||
logo={Close}
|
icon={mdiClose}
|
||||||
size={'16'}
|
size={'16'}
|
||||||
title="Remove partner"
|
title="Remove partner"
|
||||||
/>
|
/>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { api, APIKeyResponseDto } from '@api';
|
import { api, APIKeyResponseDto } from '@api';
|
||||||
import PencilOutline from 'svelte-material-icons/PencilOutline.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import TrashCanOutline from 'svelte-material-icons/TrashCanOutline.svelte';
|
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import APIKeyForm from '../forms/api-key-form.svelte';
|
import APIKeyForm from '../forms/api-key-form.svelte';
|
||||||
@ -10,6 +9,7 @@
|
|||||||
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
|
import { mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let keys: APIKeyResponseDto[];
|
export let keys: APIKeyResponseDto[];
|
||||||
|
|
||||||
@ -143,13 +143,13 @@
|
|||||||
on:click={() => (editKey = key)}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
on:click={() => (deleteKey = key)}
|
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"
|
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>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -16,11 +16,7 @@
|
|||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.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 type { PageData } from './$types';
|
||||||
import PlusBoxOutline from 'svelte-material-icons/PlusBoxOutline.svelte';
|
|
||||||
import { useAlbums } from './albums.bloc';
|
import { useAlbums } from './albums.bloc';
|
||||||
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
@ -37,13 +33,20 @@
|
|||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import type { AlbumResponseDto } from '@api';
|
import type { AlbumResponseDto } from '@api';
|
||||||
import TableHeader from '$lib/components/elements/table-header.svelte';
|
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 FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
import EditAlbumForm from '$lib/components/forms/edit-album-form.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 { orderBy } from 'lodash-es';
|
||||||
|
import {
|
||||||
|
mdiPlusBoxOutline,
|
||||||
|
mdiArrowDownThin,
|
||||||
|
mdiArrowUpThin,
|
||||||
|
mdiFormatListBulletedSquare,
|
||||||
|
mdiPencilOutline,
|
||||||
|
mdiTrashCanOutline,
|
||||||
|
mdiViewGridOutline,
|
||||||
|
mdiDeleteOutline,
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
let shouldShowEditUserForm = false;
|
let shouldShowEditUserForm = false;
|
||||||
@ -210,7 +213,7 @@
|
|||||||
<div class="flex place-items-center gap-2" slot="buttons">
|
<div class="flex place-items-center gap-2" slot="buttons">
|
||||||
<LinkButton on:click={handleCreateAlbum}>
|
<LinkButton on:click={handleCreateAlbum}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<PlusBoxOutline size="18" />
|
<Icon path={mdiPlusBoxOutline} size="18" />
|
||||||
Create album
|
Create album
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
@ -220,7 +223,7 @@
|
|||||||
render={(option) => {
|
render={(option) => {
|
||||||
return {
|
return {
|
||||||
title: option.sortTitle,
|
title: option.sortTitle,
|
||||||
icon: option.sortDesc ? ArrowDownThin : ArrowUpThin,
|
icon: option.sortDesc ? mdiArrowDownThin : mdiArrowUpThin,
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
on:select={(event) => {
|
on:select={(event) => {
|
||||||
@ -236,10 +239,10 @@
|
|||||||
<LinkButton on:click={() => handleChangeListMode()}>
|
<LinkButton on:click={() => handleChangeListMode()}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
{#if $albumViewSettings.view === AlbumViewMode.List}
|
{#if $albumViewSettings.view === AlbumViewMode.List}
|
||||||
<ViewGridOutline size="18" />
|
<Icon path={mdiViewGridOutline} size="18" />
|
||||||
<p class="hidden sm:block">Cover</p>
|
<p class="hidden sm:block">Cover</p>
|
||||||
{:else}
|
{:else}
|
||||||
<FormatListBulletedSquare size="18" />
|
<Icon path={mdiFormatListBulletedSquare} size="18" />
|
||||||
<p class="hidden sm:block">List</p>
|
<p class="hidden sm:block">List</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
@ -293,13 +296,13 @@
|
|||||||
on:click|stopPropagation={() => handleEdit(album)}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
on:click|stopPropagation={() => chooseAlbumToDelete(album)}
|
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"
|
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>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -323,7 +326,7 @@
|
|||||||
<ContextMenu {...$contextMenuPosition} on:outclick={closeAlbumContextMenu} on:escape={closeAlbumContextMenu}>
|
<ContextMenu {...$contextMenuPosition} on:outclick={closeAlbumContextMenu} on:escape={closeAlbumContextMenu}>
|
||||||
<MenuOption on:click={() => setAlbumToDelete()}>
|
<MenuOption on:click={() => setAlbumToDelete()}>
|
||||||
<span class="flex place-content-center place-items-center gap-2">
|
<span class="flex place-content-center place-items-center gap-2">
|
||||||
<DeleteOutline size="18" />
|
<Icon path={mdiDeleteOutline} size="18" />
|
||||||
<p>Delete album</p>
|
<p>Delete album</p>
|
||||||
</span>
|
</span>
|
||||||
</MenuOption>
|
</MenuOption>
|
||||||
|
@ -35,17 +35,20 @@
|
|||||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { TimeBucketSize, UserResponseDto, api } from '@api';
|
import { TimeBucketSize, UserResponseDto, api } from '@api';
|
||||||
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
|
import Icon from '$lib/components/elements/icon.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 type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
||||||
|
import {
|
||||||
|
mdiPlus,
|
||||||
|
mdiDotsVertical,
|
||||||
|
mdiArrowLeft,
|
||||||
|
mdiFileImagePlusOutline,
|
||||||
|
mdiShareVariantOutline,
|
||||||
|
mdiDeleteOutline,
|
||||||
|
mdiFolderDownloadOutline,
|
||||||
|
mdiLink,
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -313,11 +316,11 @@
|
|||||||
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
|
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
||||||
<AssetSelectContextMenu icon={Plus} title="Add">
|
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
<AddToAlbum shared />
|
<AddToAlbum shared />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
<AssetSelectContextMenu icon={DotsVertical} title="Menu">
|
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
|
||||||
{#if isAllUserOwned}
|
{#if isAllUserOwned}
|
||||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||||
{/if}
|
{/if}
|
||||||
@ -333,33 +336,33 @@
|
|||||||
</AssetSelectControlBar>
|
</AssetSelectControlBar>
|
||||||
{:else}
|
{:else}
|
||||||
{#if viewMode === ViewMode.VIEW || viewMode === ViewMode.ALBUM_OPTIONS}
|
{#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">
|
<svelte:fragment slot="trailing">
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="Add Photos"
|
title="Add Photos"
|
||||||
on:click={() => (viewMode = ViewMode.SELECT_ASSETS)}
|
on:click={() => (viewMode = ViewMode.SELECT_ASSETS)}
|
||||||
logo={FileImagePlusOutline}
|
icon={mdiFileImagePlusOutline}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if isOwned}
|
{#if isOwned}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="Share"
|
title="Share"
|
||||||
on:click={() => (viewMode = ViewMode.SELECT_USERS)}
|
on:click={() => (viewMode = ViewMode.SELECT_USERS)}
|
||||||
logo={ShareVariantOutline}
|
icon={mdiShareVariantOutline}
|
||||||
/>
|
/>
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="Delete album"
|
title="Delete album"
|
||||||
on:click={() => (viewMode = ViewMode.CONFIRM_DELETE)}
|
on:click={() => (viewMode = ViewMode.CONFIRM_DELETE)}
|
||||||
logo={DeleteOutline}
|
icon={mdiDeleteOutline}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if album.assetCount > 0}
|
{#if album.assetCount > 0}
|
||||||
<CircleIconButton title="Download" on:click={handleDownloadAlbum} logo={FolderDownloadOutline} />
|
<CircleIconButton title="Download" on:click={handleDownloadAlbum} icon={mdiFolderDownloadOutline} />
|
||||||
|
|
||||||
{#if isOwned}
|
{#if isOwned}
|
||||||
<div use:clickOutside on:outclick={() => (viewMode = ViewMode.VIEW)}>
|
<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}
|
{#if viewMode === ViewMode.ALBUM_OPTIONS}
|
||||||
<ContextMenu {...contextMenuPosition}>
|
<ContextMenu {...contextMenuPosition}>
|
||||||
<MenuOption on:click={() => (viewMode = ViewMode.SELECT_THUMBNAIL)} text="Set album cover" />
|
<MenuOption on:click={() => (viewMode = ViewMode.SELECT_THUMBNAIL)} text="Set album cover" />
|
||||||
@ -465,7 +468,7 @@
|
|||||||
backgroundColor="#d3d3d3"
|
backgroundColor="#d3d3d3"
|
||||||
forceDark
|
forceDark
|
||||||
size="20"
|
size="20"
|
||||||
logo={Link}
|
icon={mdiLink}
|
||||||
on:click={() => (viewMode = ViewMode.LINK_SHARING)}
|
on:click={() => (viewMode = ViewMode.LINK_SHARING)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
@ -487,7 +490,7 @@
|
|||||||
backgroundColor="#d3d3d3"
|
backgroundColor="#d3d3d3"
|
||||||
forceDark
|
forceDark
|
||||||
size="20"
|
size="20"
|
||||||
logo={Plus}
|
icon={mdiPlus}
|
||||||
on:click={() => (viewMode = ViewMode.SELECT_USERS)}
|
on:click={() => (viewMode = ViewMode.SELECT_USERS)}
|
||||||
title="Add more users"
|
title="Add more users"
|
||||||
/>
|
/>
|
||||||
@ -518,7 +521,9 @@
|
|||||||
on:click={() => (viewMode = ViewMode.SELECT_ASSETS)}
|
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"
|
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>
|
<span class="text-lg">Select photos</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,9 +15,8 @@
|
|||||||
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||||
import { AssetStore } from '$lib/stores/assets.store';
|
import { AssetStore } from '$lib/stores/assets.store';
|
||||||
import { TimeBucketSize } from '@api';
|
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 type { PageData } from './$types';
|
||||||
|
import { mdiPlus, mdiDotsVertical } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -33,12 +32,12 @@
|
|||||||
<ArchiveAction unarchive onArchive={(ids) => assetStore.removeAssets(ids)} />
|
<ArchiveAction unarchive onArchive={(ids) => assetStore.removeAssets(ids)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
||||||
<AssetSelectContextMenu icon={Plus} title="Add">
|
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
<AddToAlbum shared />
|
<AddToAlbum shared />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
<DeleteAssets onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
|
<DeleteAssets onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
|
||||||
<AssetSelectContextMenu icon={DotsVertical} title="Add">
|
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
|
||||||
<DownloadAction menuItem />
|
<DownloadAction menuItem />
|
||||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
|
@ -4,12 +4,15 @@
|
|||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import { AssetTypeEnum, SearchExploreResponseDto, api } from '@api';
|
import { AssetTypeEnum, SearchExploreResponseDto, api } from '@api';
|
||||||
import ClockOutline from 'svelte-material-icons/ClockOutline.svelte';
|
import Icon from '$lib/components/elements/icon.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 type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import {
|
||||||
|
mdiHeartMultipleOutline,
|
||||||
|
mdiClockOutline,
|
||||||
|
mdiPlayCircleOutline,
|
||||||
|
mdiMotionPlayOutline,
|
||||||
|
mdiRotate360,
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
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"
|
class="flex w-full content-center gap-2 text-sm font-medium hover:text-immich-primary dark:hover:text-immich-dark-primary"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
>
|
>
|
||||||
<HeartMultipleOutline size={24} />
|
<Icon path={mdiHeartMultipleOutline} size={24} />
|
||||||
<span>Favorites</span>
|
<span>Favorites</span>
|
||||||
</a>
|
</a>
|
||||||
<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"
|
class="flex w-full content-center gap-2 text-sm font-medium hover:text-immich-primary dark:hover:text-immich-dark-primary"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
>
|
>
|
||||||
<ClockOutline size={24} />
|
<Icon path={mdiClockOutline} size={24} />
|
||||||
<span>Recently added</span>
|
<span>Recently added</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -138,7 +141,7 @@
|
|||||||
href="/search?type={AssetTypeEnum.Video}"
|
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"
|
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>
|
<span>Videos</span>
|
||||||
</a>
|
</a>
|
||||||
<div>
|
<div>
|
||||||
@ -146,7 +149,7 @@
|
|||||||
href="/search?motion=true"
|
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"
|
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>
|
<span>Motion photos</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -155,7 +158,7 @@
|
|||||||
href="/search?exifInfo.projectionType=EQUIRECTANGULAR"
|
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"
|
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>
|
<span>Panorama photos</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,9 +15,8 @@
|
|||||||
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||||
import { AssetStore } from '$lib/stores/assets.store';
|
import { AssetStore } from '$lib/stores/assets.store';
|
||||||
import { TimeBucketSize } from '@api';
|
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 type { PageData } from './$types';
|
||||||
|
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -34,12 +33,12 @@
|
|||||||
<FavoriteAction removeFavorite onFavorite={(ids) => assetStore.removeAssets(ids)} />
|
<FavoriteAction removeFavorite onFavorite={(ids) => assetStore.removeAssets(ids)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
||||||
<AssetSelectContextMenu icon={Plus} title="Add">
|
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
<AddToAlbum shared />
|
<AddToAlbum shared />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
<DeleteAssets onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
|
<DeleteAssets onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
|
||||||
<AssetSelectContextMenu icon={DotsVertical} title="Menu">
|
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
|
||||||
<DownloadAction menuItem />
|
<DownloadAction menuItem />
|
||||||
<ArchiveAction menuItem unarchive={isAllArchive} />
|
<ArchiveAction menuItem unarchive={isAllArchive} />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
|
@ -12,8 +12,9 @@
|
|||||||
import { isEqual, omit } from 'lodash-es';
|
import { isEqual, omit } from 'lodash-es';
|
||||||
import { DateTime, Duration } from 'luxon';
|
import { DateTime, Duration } from 'luxon';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
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 type { PageData } from './$types';
|
||||||
|
import { mdiCog } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -135,7 +136,7 @@
|
|||||||
title="Open map settings"
|
title="Open map settings"
|
||||||
on:click={() => (showSettingsModal = true)}
|
on:click={() => (showSettingsModal = true)}
|
||||||
>
|
>
|
||||||
<Cog size="100%" class="p-1" />
|
<Icon path={mdiCog} size="100%" class="p-1" />
|
||||||
</button>
|
</button>
|
||||||
</Control>
|
</Control>
|
||||||
</Map>
|
</Map>
|
||||||
|
@ -12,9 +12,8 @@
|
|||||||
import { AssetStore } from '$lib/stores/assets.store';
|
import { AssetStore } from '$lib/stores/assets.store';
|
||||||
import { TimeBucketSize } from '@api';
|
import { TimeBucketSize } from '@api';
|
||||||
import { onDestroy } from 'svelte';
|
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 type { PageData } from './$types';
|
||||||
|
import { mdiPlus, mdiArrowLeft } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -31,14 +30,14 @@
|
|||||||
{#if $isMultiSelectState}
|
{#if $isMultiSelectState}
|
||||||
<AssetSelectControlBar assets={$selectedAssets} clearSelect={assetInteractionStore.clearMultiselect}>
|
<AssetSelectControlBar assets={$selectedAssets} clearSelect={assetInteractionStore.clearMultiselect}>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<AssetSelectContextMenu icon={Plus} title="Add">
|
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
<AddToAlbum shared />
|
<AddToAlbum shared />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
<DownloadAction />
|
<DownloadAction />
|
||||||
</AssetSelectControlBar>
|
</AssetSelectControlBar>
|
||||||
{:else}
|
{: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">
|
<svelte:fragment slot="leading">
|
||||||
<p class="whitespace-nowrap text-immich-fg dark:text-immich-dark-fg">
|
<p class="whitespace-nowrap text-immich-fg dark:text-immich-dark-fg">
|
||||||
{data.partner.firstName}
|
{data.partner.firstName}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
import AccountOff from 'svelte-material-icons/AccountOff.svelte';
|
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import PeopleCard from '$lib/components/faces-page/people-card.svelte';
|
import PeopleCard from '$lib/components/faces-page/people-card.svelte';
|
||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
@ -15,19 +14,20 @@
|
|||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import ShowHide from '$lib/components/faces-page/show-hide.svelte';
|
import ShowHide from '$lib/components/faces-page/show-hide.svelte';
|
||||||
import IconButton from '$lib/components/elements/buttons/icon-button.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 ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte';
|
import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte';
|
||||||
import SetBirthDateModal from '$lib/components/faces-page/set-birth-date-modal.svelte';
|
import SetBirthDateModal from '$lib/components/faces-page/set-birth-date-modal.svelte';
|
||||||
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
||||||
|
import { mdiAccountOff, mdiEyeOutline } from '@mdi/js';
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
let selectHidden = false;
|
let selectHidden = false;
|
||||||
let initialHiddenValues: Record<string, boolean> = {};
|
let initialHiddenValues: Record<string, boolean> = {};
|
||||||
|
|
||||||
let eyeColorMap: Record<string, string> = {};
|
let eyeColorMap: Record<string, 'black' | 'white'> = {};
|
||||||
|
|
||||||
let people = data.people.people;
|
let people = data.people.people;
|
||||||
let countTotalPeople = data.people.total;
|
let countTotalPeople = data.people.total;
|
||||||
@ -362,7 +362,7 @@
|
|||||||
{#if countTotalPeople > 0}
|
{#if countTotalPeople > 0}
|
||||||
<IconButton on:click={() => (selectHidden = !selectHidden)}>
|
<IconButton on:click={() => (selectHidden = !selectHidden)}>
|
||||||
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
|
<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>
|
<p class="ml-2">Show & hide faces</p>
|
||||||
</div>
|
</div>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -388,7 +388,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white">
|
<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">
|
<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>
|
<p class="mt-5 text-3xl font-medium">No people</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,13 +29,11 @@
|
|||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { AssetResponseDto, PersonResponseDto, TimeBucketSize, api } from '@api';
|
import { AssetResponseDto, PersonResponseDto, TimeBucketSize, api } from '@api';
|
||||||
import { onMount } from 'svelte';
|
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 type { PageData } from './$types';
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||||
|
import { mdiPlus, mdiDotsVertical, mdiArrowLeft } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -370,12 +368,12 @@
|
|||||||
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
|
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
||||||
<AssetSelectContextMenu icon={Plus} title="Add">
|
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
<AddToAlbum shared />
|
<AddToAlbum shared />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
<DeleteAssets onAssetDelete={(assetId) => $assetStore.removeAsset(assetId)} />
|
<DeleteAssets onAssetDelete={(assetId) => $assetStore.removeAsset(assetId)} />
|
||||||
<AssetSelectContextMenu icon={DotsVertical} title="Add">
|
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
|
||||||
<DownloadAction menuItem filename="{data.person.name || 'immich'}.zip" />
|
<DownloadAction menuItem filename="{data.person.name || 'immich'}.zip" />
|
||||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||||
<ArchiveAction menuItem unarchive={isAllArchive} onArchive={(ids) => $assetStore.removeAssets(ids)} />
|
<ArchiveAction menuItem unarchive={isAllArchive} onArchive={(ids) => $assetStore.removeAssets(ids)} />
|
||||||
@ -383,9 +381,9 @@
|
|||||||
</AssetSelectControlBar>
|
</AssetSelectControlBar>
|
||||||
{:else}
|
{:else}
|
||||||
{#if viewMode === ViewMode.VIEW_ASSETS || viewMode === ViewMode.SUGGEST_MERGE || viewMode === ViewMode.BIRTH_DATE}
|
{#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">
|
<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="Change feature photo" on:click={() => (viewMode = ViewMode.SELECT_FACE)} />
|
||||||
<MenuOption text="Set date of birth" on:click={() => (viewMode = ViewMode.BIRTH_DATE)} />
|
<MenuOption text="Set date of birth" on:click={() => (viewMode = ViewMode.BIRTH_DATE)} />
|
||||||
<MenuOption text="Merge face" on:click={() => (viewMode = ViewMode.MERGE_FACES)} />
|
<MenuOption text="Merge face" on:click={() => (viewMode = ViewMode.MERGE_FACES)} />
|
||||||
|
@ -18,10 +18,9 @@
|
|||||||
import { AssetStore } from '$lib/stores/assets.store';
|
import { AssetStore } from '$lib/stores/assets.store';
|
||||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
import { TimeBucketSize } from '@api';
|
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 type { PageData } from './$types';
|
||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||||
|
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -52,7 +51,7 @@
|
|||||||
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
|
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
|
||||||
<CreateSharedLink on:escape={() => (handleEscapeKey = true)} />
|
<CreateSharedLink on:escape={() => (handleEscapeKey = true)} />
|
||||||
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
||||||
<AssetSelectContextMenu icon={Plus} title="Add">
|
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
<AddToAlbum shared />
|
<AddToAlbum shared />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
@ -60,7 +59,7 @@
|
|||||||
on:escape={() => (handleEscapeKey = true)}
|
on:escape={() => (handleEscapeKey = true)}
|
||||||
onAssetDelete={(assetId) => assetStore.removeAsset(assetId)}
|
onAssetDelete={(assetId) => assetStore.removeAsset(assetId)}
|
||||||
/>
|
/>
|
||||||
<AssetSelectContextMenu icon={DotsVertical} title="Menu">
|
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
|
||||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||||
<DownloadAction menuItem />
|
<DownloadAction menuItem />
|
||||||
<ArchiveAction menuItem onArchive={(ids) => assetStore.removeAssets(ids)} />
|
<ArchiveAction menuItem onArchive={(ids) => assetStore.removeAssets(ids)} />
|
||||||
|
@ -13,12 +13,8 @@
|
|||||||
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
|
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 SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
|
||||||
import type { AssetResponseDto } from '@api';
|
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 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 CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import AlbumCard from '$lib/components/album-page/album-card.svelte';
|
import AlbumCard from '$lib/components/album-page/album-card.svelte';
|
||||||
@ -28,6 +24,7 @@
|
|||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||||
import { preventRaceConditionSearchBar } from '$lib/stores/search.store';
|
import { preventRaceConditionSearchBar } from '$lib/stores/search.store';
|
||||||
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
||||||
|
import { mdiArrowLeft, mdiDotsVertical, mdiImageOffOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -109,21 +106,21 @@
|
|||||||
{#if isMultiSelectionMode}
|
{#if isMultiSelectionMode}
|
||||||
<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}>
|
<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<CircleIconButton title="Select all" logo={SelectAll} on:click={handleSelectAll} />
|
<CircleIconButton title="Select all" icon={mdiSelectAll} on:click={handleSelectAll} />
|
||||||
<AssetSelectContextMenu icon={Plus} title="Add">
|
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
<AddToAlbum shared />
|
<AddToAlbum shared />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
<DeleteAssets {onAssetDelete} />
|
<DeleteAssets {onAssetDelete} />
|
||||||
|
|
||||||
<AssetSelectContextMenu icon={DotsVertical} title="Add">
|
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
|
||||||
<DownloadAction menuItem />
|
<DownloadAction menuItem />
|
||||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||||
<ArchiveAction menuItem unarchive={isAllArchived} />
|
<ArchiveAction menuItem unarchive={isAllArchived} />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
</AssetSelectControlBar>
|
</AssetSelectControlBar>
|
||||||
{:else}
|
{: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">
|
<div class="w-full flex-1 pl-4">
|
||||||
<SearchBar grayTheme={false} value={term} />
|
<SearchBar grayTheme={false} value={term} />
|
||||||
</div>
|
</div>
|
||||||
@ -155,7 +152,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white">
|
<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">
|
<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="mt-5 text-3xl font-medium">No results</p>
|
||||||
<p class="text-base font-normal">Try a synonym or more general keyword</p>
|
<p class="text-base font-normal">Try a synonym or more general keyword</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import { api } from '@api';
|
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 { flip } from 'svelte/animate';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import { mdiLink, mdiPlusBoxOutline } from '@mdi/js';
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -43,14 +43,14 @@
|
|||||||
<div class="flex" slot="buttons">
|
<div class="flex" slot="buttons">
|
||||||
<LinkButton on:click={createSharedAlbum}>
|
<LinkButton on:click={createSharedAlbum}>
|
||||||
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
|
<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>
|
<span class="leading-none max-sm:text-xs">Create shared album</span>
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
|
|
||||||
<LinkButton on:click={() => goto(AppRoute.SHARED_LINKS)}>
|
<LinkButton on:click={() => goto(AppRoute.SHARED_LINKS)}>
|
||||||
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
|
<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>
|
<span class="leading-none max-sm:text-xs">Shared links</span>
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
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 { api, copyToClipboard, SharedLinkResponseDto } from '@api';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import SharedLinkCard from '$lib/components/sharedlinks-page/shared-link-card.svelte';
|
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 ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
|
import { mdiArrowLeft } from '@mdi/js';
|
||||||
|
|
||||||
let sharedLinks: SharedLinkResponseDto[] = [];
|
let sharedLinks: SharedLinkResponseDto[] = [];
|
||||||
let editSharedLink: SharedLinkResponseDto | null = null;
|
let editSharedLink: SharedLinkResponseDto | null = null;
|
||||||
@ -53,7 +53,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</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>
|
<svelte:fragment slot="leading">Shared links</svelte:fragment>
|
||||||
</ControlAppBar>
|
</ControlAppBar>
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
|
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
|
||||||
import { AssetStore } from '$lib/stores/assets.store';
|
import { AssetStore } from '$lib/stores/assets.store';
|
||||||
import { api, TimeBucketSize } from '@api';
|
import { api, TimeBucketSize } from '@api';
|
||||||
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import HistoryOutline from 'svelte-material-icons/History.svelte';
|
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
|
import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import empty3Url from '$lib/assets/empty-3.svg';
|
import empty3Url from '$lib/assets/empty-3.svg';
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||||
|
import { mdiDeleteOutline, mdiHistory } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -74,13 +74,13 @@
|
|||||||
<div class="flex place-items-center gap-2" slot="buttons">
|
<div class="flex place-items-center gap-2" slot="buttons">
|
||||||
<LinkButton on:click={handleRestoreTrash}>
|
<LinkButton on:click={handleRestoreTrash}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<HistoryOutline size="18" />
|
<Icon path={mdiHistory} size="18" />
|
||||||
Restore All
|
Restore All
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
<LinkButton on:click={() => (isShowEmptyConfirmation = true)}>
|
<LinkButton on:click={() => (isShowEmptyConfirmation = true)}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<DeleteOutline size="18" />
|
<Icon path={mdiDeleteOutline} size="18" />
|
||||||
Empty Trash
|
Empty Trash
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
||||||
import CodeTags from 'svelte-material-icons/CodeTags.svelte';
|
import { mdiCodeTags, mdiContentCopy, mdiMessage, mdiPartyPopper } from '@mdi/js';
|
||||||
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 { copyToClipboard } from '../api/utils';
|
import { copyToClipboard } from '../api/utils';
|
||||||
|
|
||||||
const handleCopy = async () => {
|
const handleCopy = async () => {
|
||||||
@ -43,7 +41,7 @@
|
|||||||
on:click={() => handleCopy()}
|
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"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -71,7 +69,7 @@
|
|||||||
class="flex grow basis-0 justify-center p-4"
|
class="flex grow basis-0 justify-center p-4"
|
||||||
>
|
>
|
||||||
<button class="flex flex-col place-content-center place-items-center gap-2">
|
<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>
|
<p class="text-sm">Get Help</p>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
@ -83,7 +81,7 @@
|
|||||||
class="flex grow basis-0 justify-center p-4"
|
class="flex grow basis-0 justify-center p-4"
|
||||||
>
|
>
|
||||||
<button class="flex flex-col place-content-center place-items-center gap-2">
|
<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>
|
<p class="text-sm">Read Changelog</p>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
@ -95,7 +93,7 @@
|
|||||||
class="flex grow basis-0 justify-center p-4"
|
class="flex grow basis-0 justify-center p-4"
|
||||||
>
|
>
|
||||||
<button class="flex flex-col place-content-center place-items-center gap-2">
|
<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>
|
<p class="text-sm">Check Logs</p>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import { AllJobStatusResponseDto, api } from '@api';
|
import { AllJobStatusResponseDto, api } from '@api';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
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 type { PageData } from './$types';
|
||||||
|
import { mdiCog } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -34,7 +35,7 @@
|
|||||||
<a href="{AppRoute.ADMIN_SETTINGS}?open=job-settings">
|
<a href="{AppRoute.ADMIN_SETTINGS}?open=job-settings">
|
||||||
<LinkButton>
|
<LinkButton>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<CogIcon size="18" />
|
<Icon path={mdiCog} size="18" />
|
||||||
Manage Concurrency
|
Manage Concurrency
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
|
@ -12,12 +12,9 @@
|
|||||||
import { downloadBlob } from '$lib/utils/asset-utils';
|
import { downloadBlob } from '$lib/utils/asset-utils';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { FileReportItemDto, api, copyToClipboard } from '@api';
|
import { FileReportItemDto, api, copyToClipboard } from '@api';
|
||||||
import CheckAll from 'svelte-material-icons/CheckAll.svelte';
|
import Icon from '$lib/components/elements/icon.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 type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import { mdiWrench, mdiCheckAll, mdiDownload, mdiRefresh, mdiContentCopy } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -178,25 +175,25 @@
|
|||||||
<div class="flex justify-end gap-2" slot="buttons">
|
<div class="flex justify-end gap-2" slot="buttons">
|
||||||
<LinkButton on:click={() => handleRepair()} disabled={matches.length === 0 || repairing}>
|
<LinkButton on:click={() => handleRepair()} disabled={matches.length === 0 || repairing}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<Wrench size="18" />
|
<Icon path={mdiWrench} size="18" />
|
||||||
Repair All
|
Repair All
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
<LinkButton on:click={() => handleCheckAll()} disabled={extras.length === 0 || checking}>
|
<LinkButton on:click={() => handleCheckAll()} disabled={extras.length === 0 || checking}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<CheckAll size="18" />
|
<Icon path={mdiCheckAll} size="18" />
|
||||||
Check All
|
Check All
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
<LinkButton on:click={() => handleDownload()} disabled={extras.length + orphans.length === 0}>
|
<LinkButton on:click={() => handleDownload()} disabled={extras.length + orphans.length === 0}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<Download size="18" />
|
<Icon path={mdiDownload} size="18" />
|
||||||
Export
|
Export
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
<LinkButton on:click={() => handleRefresh()}>
|
<LinkButton on:click={() => handleRefresh()}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<Refresh size="18" />
|
<Icon path={mdiRefresh} size="18" />
|
||||||
Refresh
|
Refresh
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
@ -273,7 +270,7 @@
|
|||||||
title={orphan.pathValue}
|
title={orphan.pathValue}
|
||||||
>
|
>
|
||||||
<td on:click={() => copyToClipboard(orphan.pathValue)}>
|
<td on:click={() => copyToClipboard(orphan.pathValue)}>
|
||||||
<CircleIconButton logo={ContentCopy} size="18" />
|
<CircleIconButton icon={mdiContentCopy} size="18" />
|
||||||
</td>
|
</td>
|
||||||
<td class="truncate text-sm font-mono text-left" title={orphan.pathValue}>
|
<td class="truncate text-sm font-mono text-left" title={orphan.pathValue}>
|
||||||
{orphan.pathValue}
|
{orphan.pathValue}
|
||||||
@ -313,7 +310,7 @@
|
|||||||
title={extra.filename}
|
title={extra.filename}
|
||||||
>
|
>
|
||||||
<td on:click={() => copyToClipboard(extra.filename)}>
|
<td on:click={() => copyToClipboard(extra.filename)}>
|
||||||
<CircleIconButton logo={ContentCopy} size="18" />
|
<CircleIconButton icon={mdiContentCopy} size="18" />
|
||||||
</td>
|
</td>
|
||||||
<td class="w-full text-md text-ellipsis flex justify-between pr-5">
|
<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}
|
<span class="text-ellipsis grow truncate font-mono text-sm pr-5" title={extra.filename}
|
||||||
|
@ -17,11 +17,10 @@
|
|||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
import { downloadBlob } from '$lib/utils/asset-utils';
|
import { downloadBlob } from '$lib/utils/asset-utils';
|
||||||
import { copyToClipboard } from '@api';
|
import { copyToClipboard } from '@api';
|
||||||
import Alert from 'svelte-material-icons/Alert.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
|
|
||||||
import Download from 'svelte-material-icons/Download.svelte';
|
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import NewVersionCheckSettings from '$lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte';
|
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;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -39,7 +38,7 @@
|
|||||||
|
|
||||||
{#if $featureFlags.configFile}
|
{#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">
|
<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>
|
<h2 class="text-md text-immich-primary dark:text-immich-dark-primary">Config is currently set by a config file</h2>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -48,13 +47,13 @@
|
|||||||
<div class="flex justify-end gap-2" slot="buttons">
|
<div class="flex justify-end gap-2" slot="buttons">
|
||||||
<LinkButton on:click={() => copyToClipboard(JSON.stringify(configs, null, 2))}>
|
<LinkButton on:click={() => copyToClipboard(JSON.stringify(configs, null, 2))}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<ContentCopy size="18" />
|
<Icon path={mdiContentCopy} size="18" />
|
||||||
Copy to Clipboard
|
Copy to Clipboard
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
<LinkButton on:click={() => downloadConfig()}>
|
<LinkButton on:click={() => downloadConfig()}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<Download size="18" />
|
<Icon path={mdiDownload} size="18" />
|
||||||
Export as JSON
|
Export as JSON
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { api, UserResponseDto } from '@api';
|
import { api, UserResponseDto } from '@api';
|
||||||
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import PencilOutline from 'svelte-material-icons/PencilOutline.svelte';
|
import Icon from '$lib/components/elements/icon.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 FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
import CreateUserForm from '$lib/components/forms/create-user-form.svelte';
|
import CreateUserForm from '$lib/components/forms/create-user-form.svelte';
|
||||||
import EditUserForm from '$lib/components/forms/edit-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 Button from '$lib/components/elements/buttons/button.svelte';
|
||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import { mdiCheck, mdiClose, mdiDeleteRestore, mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@ -196,9 +192,9 @@
|
|||||||
<td class="w-2/12 text-ellipsis break-all px-2 text-sm">
|
<td class="w-2/12 text-ellipsis break-all px-2 text-sm">
|
||||||
<div class="container mx-auto flex flex-wrap justify-center">
|
<div class="container mx-auto flex flex-wrap justify-center">
|
||||||
{#if user.externalPath}
|
{#if user.externalPath}
|
||||||
<Check size="16" />
|
<Icon path={mdiCheck} size="16" />
|
||||||
{:else}
|
{:else}
|
||||||
<Close size="16" />
|
<Icon path={mdiClose} size="16" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -208,14 +204,14 @@
|
|||||||
on:click={() => editUserHandler(user)}
|
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"
|
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>
|
||||||
{#if user.id !== data.user.id}
|
{#if user.id !== data.user.id}
|
||||||
<button
|
<button
|
||||||
on:click={() => deleteUserHandler(user)}
|
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"
|
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>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{/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"
|
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)}`}
|
title={`scheduled removal on ${getDeleteDate(user)}`}
|
||||||
>
|
>
|
||||||
<DeleteRestore size="16" />
|
<Icon path={mdiDeleteRestore} size="16" />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
@ -265,13 +261,13 @@
|
|||||||
on:click={() => editUserHandler(user)}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
on:click={() => deleteUserHandler(user)}
|
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"
|
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>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{#if isDeleted(user)}
|
{#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"
|
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)}`}
|
title={`scheduled removal on ${getDeleteDate(user)}`}
|
||||||
>
|
>
|
||||||
<DeleteRestore size="16" />
|
<Icon path={mdiDeleteRestore} size="16" />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user