refactor: replace link-button component with immich-ui buttons (#15374)

* refactor: replace link-button component with immich-ui buttons

* minor styling tweak

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
Jason Rasmussen
2025-01-16 11:03:04 -05:00
committed by GitHub
parent 378bd3c993
commit 3a2bf91889
16 changed files with 385 additions and 383 deletions
+8 -11
View File
@@ -3,8 +3,6 @@
import { page } from '$app/stores';
import { focusTrap } from '$lib/actions/focus-trap';
import { scrollMemory } from '$lib/actions/scroll-memory';
import Button from '$lib/components/elements/buttons/button.svelte';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import ManagePeopleVisibility from '$lib/components/faces-page/manage-people-visibility.svelte';
import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte';
@@ -32,6 +30,7 @@
updatePerson,
type PersonResponseDto,
} from '@immich/sdk';
import { Button, Text } from '@immich/ui';
import { mdiAccountOff, mdiEyeOutline } from '@mdi/js';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
@@ -393,12 +392,10 @@
/>
</div>
</div>
<LinkButton onclick={() => (selectHidden = !selectHidden)}>
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
<Icon path={mdiEyeOutline} size="18" />
<p class="ml-2">{$t('show_and_hide_people')}</p>
</div>
</LinkButton>
<Button onclick={() => (selectHidden = !selectHidden)} size="small" variant="ghost" color="secondary">
<Icon path={mdiEyeOutline} />
<Text>{$t('show_and_hide_people')}</Text>
</Button>
</div>
{/if}
{/snippet}
@@ -445,13 +442,13 @@
{#snippet stickyBottom()}
<Button
color="gray"
fullwidth
color="secondary"
fullWidth
onclick={() => {
showChangeNameModal = false;
}}>{$t('cancel')}</Button
>
<Button type="submit" fullwidth form="change-name-form">{$t('ok')}</Button>
<Button type="submit" fullWidth form="change-name-form">{$t('ok')}</Button>
{/snippet}
</FullScreenModal>
{/if}
+15 -19
View File
@@ -1,14 +1,11 @@
<script lang="ts">
import empty2Url from '$lib/assets/empty-2.svg';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import Albums from '$lib/components/album-page/albums-list.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
import { AppRoute } from '$lib/constants';
import { mdiLink, mdiPlusBoxOutline } from '@mdi/js';
import type { PageData } from './$types';
import { createAlbumAndRedirect } from '$lib/utils/album-utils';
import {
AlbumFilter,
AlbumGroupBy,
@@ -17,8 +14,11 @@
SortOrder,
type AlbumViewSettings,
} from '$lib/stores/preferences.store';
import Albums from '$lib/components/album-page/albums-list.svelte';
import { createAlbumAndRedirect } from '$lib/utils/album-utils';
import { Button, HStack } from '@immich/ui';
import { mdiLink, mdiPlusBoxOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
interface Props {
data: PageData;
@@ -39,21 +39,17 @@
<UserPageLayout title={data.meta.title}>
{#snippet buttons()}
<div class="flex">
<LinkButton onclick={() => createAlbumAndRedirect()}>
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
<Icon path={mdiPlusBoxOutline} size="18" class="shrink-0" />
<span class="leading-none max-sm:text-xs">{$t('create_album')}</span>
</div>
</LinkButton>
<HStack gap={0}>
<Button onclick={() => createAlbumAndRedirect()} size="small" variant="ghost" color="secondary">
<Icon path={mdiPlusBoxOutline} class="shrink-0" />
<span class="leading-none max-sm:text-xs">{$t('create_album')}</span>
</Button>
<LinkButton href={AppRoute.SHARED_LINKS}>
<div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm">
<Icon path={mdiLink} size="18" class="shrink-0" />
<span class="leading-none max-sm:text-xs">{$t('shared_links')}</span>
</div>
</LinkButton>
</div>
<Button href={AppRoute.SHARED_LINKS} size="small" variant="ghost" color="secondary">
<Icon path={mdiLink} class="shrink-0" />
<span class="leading-none max-sm:text-xs">{$t('shared_links')}</span>
</Button>
</HStack>
{/snippet}
<div class="flex flex-col">
@@ -1,11 +1,11 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import Button from '$lib/components/elements/buttons/button.svelte';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import SkipLink from '$lib/components/elements/buttons/skip-link.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import UserPageLayout, { headerId } from '$lib/components/layouts/user-page-layout.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
import {
notificationController,
@@ -13,19 +13,18 @@
} from '$lib/components/shared-components/notification/notification';
import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte';
import SideBarSection from '$lib/components/shared-components/side-bar/side-bar-section.svelte';
import Breadcrumbs from '$lib/components/shared-components/tree/breadcrumbs.svelte';
import TreeItemThumbnails from '$lib/components/shared-components/tree/tree-item-thumbnails.svelte';
import TreeItems from '$lib/components/shared-components/tree/tree-items.svelte';
import { AppRoute, AssetAction, QueryParameter, SettingInputFieldType } from '$lib/constants';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetStore } from '$lib/stores/assets.store';
import { buildTree, normalizeTreePath } from '$lib/utils/tree-utils';
import { deleteTag, getAllTags, updateTag, upsertTags, type TagResponseDto } from '@immich/sdk';
import { Button, HStack, Text } from '@immich/ui';
import { mdiPencil, mdiPlus, mdiTag, mdiTagMultiple, mdiTrashCanOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
import Breadcrumbs from '$lib/components/shared-components/tree/breadcrumbs.svelte';
import SkipLink from '$lib/components/elements/buttons/skip-link.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
interface Props {
data: PageData;
@@ -169,29 +168,23 @@
{/snippet}
{#snippet buttons()}
<section>
<LinkButton onclick={handleCreate}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiPlus} size="18" />
<p class="hidden md:block">{$t('create_tag')}</p>
</div>
</LinkButton>
<HStack>
<Button onclick={handleCreate} size="small" variant="ghost" color="secondary">
<Icon path={mdiPlus} />
<p class="hidden md:block">{$t('create_tag')}</p>
</Button>
{#if pathSegments.length > 0 && tag}
<LinkButton onclick={handleEdit}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiPencil} size="18" />
<p class="hidden md:block">{$t('edit_tag')}</p>
</div>
</LinkButton>
<LinkButton onclick={handleDelete}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiTrashCanOutline} size="18" />
<p class="hidden md:block">{$t('delete_tag')}</p>
</div>
</LinkButton>
<Button onclick={handleEdit} size="small" variant="ghost" color="secondary">
<Icon path={mdiPencil} size="18" />
<Text class="hidden md:block">{$t('edit_tag')}</Text>
</Button>
<Button onclick={handleDelete} size="small" variant="ghost" color="secondary">
<Icon path={mdiTrashCanOutline} />
<Text class="hidden md:block">{$t('delete_tag')}</Text>
</Button>
{/if}
</section>
</HStack>
{/snippet}
<Breadcrumbs {pathSegments} icon={mdiTagMultiple} title={$t('tags')} {getLink} />
@@ -230,8 +223,8 @@
</form>
{#snippet stickyBottom()}
<Button color="gray" fullwidth onclick={() => handleCancel()}>{$t('cancel')}</Button>
<Button type="submit" fullwidth form="create-tag-form">{$t('create')}</Button>
<Button color="secondary" fullWidth shape="round" onclick={() => handleCancel()}>{$t('cancel')}</Button>
<Button type="submit" fullWidth shape="round" form="create-tag-form">{$t('create')}</Button>
{/snippet}
</FullScreenModal>
{/if}
@@ -249,8 +242,8 @@
</form>
{#snippet stickyBottom()}
<Button color="gray" fullwidth onclick={() => handleCancel()}>{$t('cancel')}</Button>
<Button type="submit" fullwidth form="edit-tag-form">{$t('save')}</Button>
<Button color="secondary" fullWidth shape="round" onclick={() => handleCancel()}>{$t('cancel')}</Button>
<Button type="submit" fullWidth shape="round" form="edit-tag-form">{$t('save')}</Button>
{/snippet}
</FullScreenModal>
{/if}
@@ -1,7 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import empty3Url from '$lib/assets/empty-3.svg';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
@@ -9,23 +8,24 @@
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import {
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { AppRoute } from '$lib/constants';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetStore } from '$lib/stores/assets.store';
import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
import { handlePromiseError } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { emptyTrash, restoreTrash } from '@immich/sdk';
import { Button, HStack } from '@immich/ui';
import { mdiDeleteForeverOutline, mdiHistory } from '@mdi/js';
import type { PageData } from './$types';
import { handlePromiseError } from '$lib/utils';
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
import { t } from 'svelte-i18n';
import { onDestroy } from 'svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
interface Props {
data: PageData;
@@ -113,20 +113,28 @@
{#if $featureFlags.loaded && $featureFlags.trash}
<UserPageLayout hideNavbar={assetInteraction.selectionActive} title={data.meta.title} scrollbar={false}>
{#snippet buttons()}
<div class="flex place-items-center gap-2">
<LinkButton onclick={handleRestoreTrash} disabled={assetInteraction.selectionActive}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiHistory} size="18" />
{$t('restore_all')}
</div>
</LinkButton>
<LinkButton onclick={() => handleEmptyTrash()} disabled={assetInteraction.selectionActive}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiDeleteForeverOutline} size="18" />
{$t('empty_trash')}
</div>
</LinkButton>
</div>
<HStack gap={0}>
<Button
onclick={handleRestoreTrash}
disabled={assetInteraction.selectionActive}
variant="ghost"
color="secondary"
size="small"
>
<Icon path={mdiHistory} />
{$t('restore_all')}
</Button>
<Button
onclick={() => handleEmptyTrash()}
disabled={assetInteraction.selectionActive}
variant="ghost"
color="secondary"
size="small"
>
<Icon path={mdiDeleteForeverOutline} />
{$t('empty_trash')}
</Button>
</HStack>
{/snippet}
<AssetGrid enableRouting={true} {assetStore} {assetInteraction} onEscape={handleEscape}>
@@ -1,27 +1,26 @@
<script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
import DuplicatesModal from '$lib/components/shared-components/duplicates-modal.svelte';
import {
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import ShowShortcuts from '$lib/components/shared-components/show-shortcuts.svelte';
import DuplicatesCompareControl from '$lib/components/utilities-page/duplicates/duplicates-compare-control.svelte';
import type { AssetResponseDto } from '@immich/sdk';
import { locale } from '$lib/stores/preferences.store';
import { featureFlags } from '$lib/stores/server-config.store';
import { stackAssets } from '$lib/utils/asset-utils';
import { suggestDuplicate } from '$lib/utils/duplicate-utils';
import { handleError } from '$lib/utils/handle-error';
import type { AssetResponseDto } from '@immich/sdk';
import { deleteAssets, updateAssets } from '@immich/sdk';
import { Button, HStack, IconButton } from '@immich/ui';
import { mdiCheckOutline, mdiInformationOutline, mdiKeyboard, mdiTrashCanOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
import { suggestDuplicate } from '$lib/utils/duplicate-utils';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import { mdiCheckOutline, mdiInformationOutline, mdiTrashCanOutline } from '@mdi/js';
import { stackAssets } from '$lib/utils/asset-utils';
import ShowShortcuts from '$lib/components/shared-components/show-shortcuts.svelte';
import DuplicatesModal from '$lib/components/shared-components/duplicates-modal.svelte';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { mdiKeyboard } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import { locale } from '$lib/stores/preferences.store';
interface Props {
data: PageData;
@@ -163,25 +162,31 @@
<UserPageLayout title={data.meta.title + ` (${duplicates.length.toLocaleString($locale)})`} scrollbar={true}>
{#snippet buttons()}
<div class="flex place-items-center gap-2">
<LinkButton onclick={() => handleDeduplicateAll()} disabled={!hasDuplicates}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiTrashCanOutline} size="18" />
{$t('deduplicate_all')}
</div>
</LinkButton>
<LinkButton onclick={() => handleKeepAll()} disabled={!hasDuplicates}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiCheckOutline} size="18" />
{$t('keep_all')}
</div>
</LinkButton>
<CircleIconButton
<HStack gap={0}>
<Button
onclick={() => handleDeduplicateAll()}
disabled={!hasDuplicates}
size="small"
variant="ghost"
color="secondary"
>
<Icon path={mdiTrashCanOutline} />
{$t('deduplicate_all')}
</Button>
<Button onclick={() => handleKeepAll()} disabled={!hasDuplicates} size="small" variant="ghost" color="secondary">
<Icon path={mdiCheckOutline} />
{$t('keep_all')}
</Button>
<IconButton
shape="round"
variant="ghost"
color="secondary"
size="large"
icon={mdiKeyboard}
title={$t('show_keyboard_shortcuts')}
onclick={() => (isShowKeyboardShortcut = !isShowKeyboardShortcut)}
/>
</div>
</HStack>
{/snippet}
<div class="">
+11 -15
View File
@@ -1,6 +1,5 @@
<script lang="ts">
import JobsPanel from '$lib/components/admin-page/jobs/jobs-panel.svelte';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
@@ -13,6 +12,7 @@
import { asyncTimeout } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { createJob, getAllJobsStatus, ManualJobName, type AllJobStatusResponseDto } from '@immich/sdk';
import { Button, HStack } from '@immich/ui';
import { mdiCog, mdiPlus } from '@mdi/js';
import { onDestroy, onMount } from 'svelte';
import { t } from 'svelte-i18n';
@@ -71,20 +71,16 @@
<UserPageLayout title={data.meta.title} admin>
{#snippet buttons()}
<div class="flex justify-end">
<LinkButton onclick={() => (isOpen = true)}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiPlus} size="18" />
{$t('admin.create_job')}
</div>
</LinkButton>
<LinkButton href="{AppRoute.ADMIN_SETTINGS}?isOpen=job">
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiCog} size="18" />
{$t('admin.manage_concurrency')}
</div>
</LinkButton>
</div>
<HStack gap={0}>
<Button onclick={() => (isOpen = true)} size="small" variant="ghost" color="secondary">
<Icon path={mdiPlus} size="18" />
{$t('admin.create_job')}
</Button>
<Button href="{AppRoute.ADMIN_SETTINGS}?isOpen=job" size="small" variant="ghost" color="secondary">
<Icon path={mdiCog} size="18" />
{$t('admin.manage_concurrency')}
</Button>
</HStack>
{/snippet}
<section id="setting-content" class="flex place-content-center sm:mx-4">
<section class="w-full pb-28 sm:w-5/6 md:w-[850px]">
@@ -1,17 +1,20 @@
<script lang="ts">
import Icon from '$lib/components/elements/icon.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import LibraryImportPathsForm from '$lib/components/forms/library-import-paths-form.svelte';
import LibraryRenameForm from '$lib/components/forms/library-rename-form.svelte';
import LibraryScanSettingsForm from '$lib/components/forms/library-scan-settings-form.svelte';
import LibraryUserPickerForm from '$lib/components/forms/library-user-picker-form.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import {
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import { locale } from '$lib/stores/preferences.store';
import { ByteUnit, getBytesWithUnit } from '$lib/utils/byte-units';
import { handleError } from '$lib/utils/handle-error';
import {
@@ -26,15 +29,12 @@
type LibraryStatsResponseDto,
type UserResponseDto,
} from '@immich/sdk';
import { Button } from '@immich/ui';
import { mdiDatabase, mdiDotsVertical, mdiPlusBoxOutline, mdiSync } from '@mdi/js';
import { onMount } from 'svelte';
import { fade, slide } from 'svelte/transition';
import LinkButton from '../../../lib/components/elements/buttons/link-button.svelte';
import type { PageData } from './$types';
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
import { t } from 'svelte-i18n';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import { locale } from '$lib/stores/preferences.store';
import { fade, slide } from 'svelte/transition';
import type { PageData } from './$types';
interface Props {
data: PageData;
@@ -220,19 +220,19 @@
{#snippet buttons()}
<div class="flex justify-end gap-2">
{#if libraries.length > 0}
<LinkButton onclick={() => handleScanAll()}>
<Button onclick={handleScanAll} size="small" variant="ghost" color="secondary">
<div class="flex gap-1 text-sm">
<Icon path={mdiSync} size="18" />
<span>{$t('scan_all_libraries')}</span>
</div>
</LinkButton>
</Button>
{/if}
<LinkButton onclick={() => (toCreateLibrary = true)}>
<Button onclick={() => (toCreateLibrary = true)} size="small" variant="ghost" color="secondary">
<div class="flex gap-1 text-sm">
<Icon path={mdiPlusBoxOutline} size="18" />
<span>{$t('create_library')}</span>
</div>
</LinkButton>
</Button>
</div>
{/snippet}
<section class="my-4">
+39 -29
View File
@@ -1,7 +1,6 @@
<script lang="ts">
import empty4Url from '$lib/assets/empty-4.svg';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
@@ -10,14 +9,15 @@
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { downloadManager } from '$lib/stores/download';
import { locale } from '$lib/stores/preferences.store';
import { copyToClipboard } from '$lib/utils';
import { downloadBlob } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
import { fixAuditFiles, getAuditFiles, getFileChecksums, type FileReportItemDto } from '@immich/sdk';
import { Button, HStack } from '@immich/ui';
import { mdiCheckAll, mdiContentCopy, mdiDownload, mdiRefresh, mdiWrench } from '@mdi/js';
import type { PageData } from './$types';
import { t } from 'svelte-i18n';
import { locale } from '$lib/stores/preferences.store';
import type { PageData } from './$types';
interface Props {
data: PageData;
@@ -185,32 +185,42 @@
<UserPageLayout title={data.meta.title} admin>
{#snippet buttons()}
<div class="flex justify-end gap-2">
<LinkButton onclick={() => handleRepair()} disabled={matches.length === 0 || repairing}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiWrench} size="18" />
{$t('admin.repair_all')}
</div>
</LinkButton>
<LinkButton onclick={() => handleCheckAll()} disabled={extras.length === 0 || checking}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiCheckAll} size="18" />
{$t('admin.check_all')}
</div>
</LinkButton>
<LinkButton onclick={() => handleDownload()} disabled={extras.length + orphans.length === 0}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiDownload} size="18" />
{$t('export')}
</div>
</LinkButton>
<LinkButton onclick={() => handleRefresh()}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiRefresh} size="18" />
{$t('refresh')}
</div>
</LinkButton>
</div>
<HStack gap={0}>
<Button
onclick={() => handleRepair()}
disabled={matches.length === 0 || repairing}
size="small"
variant="ghost"
color="secondary"
>
<Icon path={mdiWrench} />
{$t('admin.repair_all')}
</Button>
<Button
onclick={() => handleCheckAll()}
disabled={extras.length === 0 || checking}
size="small"
variant="ghost"
color="secondary"
>
<Icon path={mdiCheckAll} />
{$t('admin.check_all')}
</Button>
<Button
onclick={() => handleDownload()}
disabled={extras.length + orphans.length === 0}
size="small"
variant="ghost"
color="secondary"
>
<Icon path={mdiDownload} />
{$t('export')}
</Button>
<Button onclick={() => handleRefresh()} size="small" variant="ghost" color="secondary">
<Icon path={mdiRefresh} />
{$t('refresh')}
</Button>
</HStack>
{/snippet}
<section id="setting-content" class="flex place-content-center sm:mx-4">
<section class="w-full pb-28 sm:w-5/6 md:w-[850px]">
@@ -17,7 +17,7 @@
import ThemeSettings from '$lib/components/admin-page/settings/theme/theme-settings.svelte';
import TrashSettings from '$lib/components/admin-page/settings/trash-settings/trash-settings.svelte';
import UserSettings from '$lib/components/admin-page/settings/user-settings/user-settings.svelte';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
import { Button, HStack } from '@immich/ui';
import Icon from '$lib/components/elements/icon.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import SettingAccordionState from '$lib/components/shared-components/settings/setting-accordion-state.svelte';
@@ -255,31 +255,30 @@
<UserPageLayout title={data.meta.title} admin>
{#snippet buttons()}
<div class="flex justify-end gap-2">
<HStack gap={1}>
<div class="hidden lg:block">
<SearchBar placeholder={$t('search_settings')} bind:name={searchQuery} showLoadingSpinner={false} />
</div>
<LinkButton onclick={() => copyToClipboard(JSON.stringify(config, jsonReplacer, 2))}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiContentCopy} size="18" />
{$t('copy_to_clipboard')}
</div>
</LinkButton>
<LinkButton onclick={() => downloadConfig()}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiDownload} size="18" />
{$t('export_as_json')}
</div>
</LinkButton>
<Button
onclick={() => copyToClipboard(JSON.stringify(config, jsonReplacer, 2))}
size="small"
variant="ghost"
color="secondary"
>
<Icon path={mdiContentCopy} />
{$t('copy_to_clipboard')}
</Button>
<Button onclick={() => downloadConfig()} size="small" variant="ghost" color="secondary">
<Icon path={mdiDownload} />
{$t('export_as_json')}
</Button>
{#if !$featureFlags.configFile}
<LinkButton onclick={() => inputElement?.click()}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiUpload} size="18" />
{$t('import_from_json')}
</div>
</LinkButton>
<Button onclick={() => inputElement?.click()} size="small" variant="ghost" color="secondary">
<Icon path={mdiUpload} />
{$t('import_from_json')}
</Button>
{/if}
</div>
</HStack>
{/snippet}
<AdminSettings bind:config bind:this={adminSettingElement}>