refactor(web): co-locate single-use components in /routes (#27921)

* co-locate single use components to /routes

* revert accidentally changed paths

* fix mangled path

* fmt

* fix accidentally moved multi-use components
This commit is contained in:
Freddie Floydd
2026-04-18 02:21:36 +01:00
committed by GitHub
parent b0e4850d76
commit 03af669856
128 changed files with 108 additions and 108 deletions
+9 -9
View File
@@ -1,15 +1,15 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/state';
import OnboardingBackup from '$lib/components/onboarding-page/onboarding-backup.svelte';
import OnboardingCard from '$lib/components/onboarding-page/onboarding-card.svelte';
import OnboardingHello from '$lib/components/onboarding-page/onboarding-hello.svelte';
import OnboardingLocale from '$lib/components/onboarding-page/onboarding-language.svelte';
import OnboardingMobileApp from '$lib/components/onboarding-page/onboarding-mobile-app.svelte';
import OnboardingServerPrivacy from '$lib/components/onboarding-page/onboarding-server-privacy.svelte';
import OnboardingStorageTemplate from '$lib/components/onboarding-page/onboarding-storage-template.svelte';
import OnboardingTheme from '$lib/components/onboarding-page/onboarding-theme.svelte';
import OnboardingUserPrivacy from '$lib/components/onboarding-page/onboarding-user-privacy.svelte';
import OnboardingBackup from './onboarding-backup.svelte';
import OnboardingCard from './onboarding-card.svelte';
import OnboardingHello from './onboarding-hello.svelte';
import OnboardingLocale from './onboarding-language.svelte';
import OnboardingMobileApp from './onboarding-mobile-app.svelte';
import OnboardingServerPrivacy from './onboarding-server-privacy.svelte';
import OnboardingStorageTemplate from './onboarding-storage-template.svelte';
import OnboardingTheme from './onboarding-theme.svelte';
import OnboardingUserPrivacy from './onboarding-user-privacy.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
import { systemConfigManager } from '$lib/managers/system-config-manager.svelte';
@@ -0,0 +1,56 @@
<script lang="ts">
import FormatMessage from '$lib/elements/FormatMessage.svelte';
import { Icon, Link, Stack } from '@immich/ui';
import { mdiAlertCircleOutline } from '@mdi/js';
import type { Translations } from 'svelte-i18n';
const messageKeys = [
'admin.backup_onboarding_3_description',
'admin.backup_onboarding_2_description',
'admin.backup_onboarding_1_description',
];
</script>
<div class="flex flex-col">
<Stack gap={2}>
<div class="flex items-start gap-4 p-6 my-10 bg-gray-100 dark:bg-gray-800/40 rounded-xl border border-gray-700/50">
<Icon icon={mdiAlertCircleOutline} size="36" class="text-warning shrink-0 mt-0.5" />
<div class="text-gray-800 dark:text-gray-300 leading-relaxed">
<FormatMessage key="admin.backup_onboarding_description">
{#snippet children({ message })}
<Link href="https://www.backblaze.com/blog/the-3-2-1-backup-strategy/">
{message}
</Link>
{/snippet}
</FormatMessage>
</div>
</div>
<div class="space-y-1">
<h2 class="mb-6"><FormatMessage key="admin.backup_onboarding_parts_title" /></h2>
<div class="space-y-6">
{#each messageKeys as keyString, index (index)}
<div class="flex items-start gap-6">
<div class="shrink-0 w-12 h-12 rounded-full bg-primary/90 flex items-center justify-center">
<span class="text-light text-xl font-semibold">{3 - index}</span>
</div>
<div class="leading-relaxed pt-2">
<FormatMessage key={keyString as Translations} />
</div>
</div>
{/each}
</div>
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 leading-relaxed mt-4">
<p>
<FormatMessage key="admin.backup_onboarding_footer">
{#snippet children({ message })}
<Link href="https://docs.immich.app/administration/backup-and-restore/">{message}</Link>
{/snippet}
</FormatMessage>
</p>
</div>
</Stack>
</div>
@@ -0,0 +1,82 @@
<script lang="ts">
import { Button, Icon } from '@immich/ui';
import { mdiArrowLeft, mdiArrowRight, mdiCheck } from '@mdi/js';
import type { Snippet } from 'svelte';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
interface Props {
title?: string | undefined;
icon?: string | undefined;
children?: Snippet;
previousTitle?: string | undefined;
nextTitle?: string | undefined;
onNext?: () => void;
onPrevious?: () => void;
onLeave?: () => void;
}
let {
title = undefined,
icon = undefined,
children,
previousTitle,
nextTitle,
onLeave,
onNext,
onPrevious,
}: Props = $props();
</script>
<div
id="onboarding-card"
class="flex w-full max-w-4xl flex-col gap-4 rounded-3xl border-2 border-gray-500 px-8 py-8 dark:border-gray-700 dark:bg-immich-dark-gray text-black dark:text-immich-dark-fg bg-gray-50"
in:fade={{ duration: 250 }}
>
{#if title || icon}
<div class="flex gap-2 items-center justify-center w-fit">
{#if icon}
<Icon {icon} size="30" class="text-primary" />
{/if}
{#if title}
<p class="text-xl text-primary font-medium">
{title}
</p>
{/if}
</div>
{/if}
{@render children?.()}
<div class="flex pt-4">
{#if previousTitle}
<div class="w-full flex place-content-start">
<Button
shape="round"
leadingIcon={mdiArrowLeft}
class="flex gap-2 place-content-center"
onclick={() => {
onLeave?.();
onPrevious?.();
}}
>
<p>{previousTitle}</p>
</Button>
</div>
{/if}
<div class="flex w-full place-content-end">
<Button
shape="round"
trailingIcon={nextTitle ? mdiArrowRight : mdiCheck}
onclick={() => {
onLeave?.();
onNext?.();
}}
>
<span class="flex place-content-center place-items-center gap-2">
{nextTitle ?? $t('done')}
</span>
</Button>
</div>
</div>
</div>
@@ -0,0 +1,23 @@
<script lang="ts">
import { authManager } from '$lib/managers/auth-manager.svelte';
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
import { OnboardingRole } from '$lib/types';
import { Logo } from '@immich/ui';
import { t } from 'svelte-i18n';
let userRole = $derived(
authManager.user.isAdmin && !serverConfigManager.value.isOnboarded ? OnboardingRole.SERVER : OnboardingRole.USER,
);
</script>
<div class="gap-4">
<Logo variant="icon" size="giant" class="mb-2" />
<p class="font-medium mb-6 text-6xl text-primary">
{$t('onboarding_welcome_user', { values: { user: authManager.user.name } })}
</p>
<p class="text-3xl pb-6 font-light">
{userRole == OnboardingRole.SERVER
? $t('onboarding_server_welcome_description')
: $t('onboarding_user_welcome_description')}
</p>
</div>
@@ -0,0 +1,12 @@
<script lang="ts">
import SettingsLanguageSelector from '$lib/components/shared-components/settings/settings-language-selector.svelte';
import { t } from 'svelte-i18n';
</script>
<div class="flex flex-col gap-4">
<p>
{$t('onboarding_locale_description')}
</p>
<SettingsLanguageSelector />
</div>
@@ -0,0 +1,31 @@
<script lang="ts">
import AppDownloadModal from '$lib/modals/AppDownloadModal.svelte';
import ObtainiumConfigModal from '$lib/modals/ObtainiumConfigModal.svelte';
import { Button, HStack, modalManager } from '@immich/ui';
import { mdiCellphoneArrowDownVariant, mdiLinkEdit } from '@mdi/js';
import { t } from 'svelte-i18n';
</script>
<p>{$t('mobile_app_download_onboarding_note')}</p>
<HStack>
<Button
size="medium"
shape="semi-round"
fullWidth
onclick={() => modalManager.show(AppDownloadModal, {})}
leadingIcon={mdiCellphoneArrowDownVariant}
>
{$t('app_stores')}
</Button>
<Button
size="medium"
shape="semi-round"
fullWidth
onclick={() => modalManager.show(ObtainiumConfigModal, {})}
leadingIcon={mdiLinkEdit}
>
{$t('obtainium_configurator')}
</Button>
</HStack>
@@ -0,0 +1,30 @@
<script lang="ts">
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
import { systemConfigManager } from '$lib/managers/system-config-manager.svelte';
import { handleSystemConfigSave } from '$lib/services/system-config.service';
import { onDestroy } from 'svelte';
import { t } from 'svelte-i18n';
const configToEdit = $state(systemConfigManager.cloneValue());
onDestroy(async () => {
await handleSystemConfigSave({ map: configToEdit.map, newVersionCheck: configToEdit.newVersionCheck });
});
</script>
<div class="flex flex-col gap-4">
<p>
{$t('onboarding_privacy_description')}
</p>
<SettingSwitch
title={$t('admin.map_settings')}
subtitle={$t('admin.map_implications')}
bind:checked={configToEdit.map.enabled}
/>
<SettingSwitch
title={$t('admin.version_check_settings')}
subtitle={$t('admin.version_check_implications', { values: { server: 'version.immich.cloud' } })}
bind:checked={configToEdit.newVersionCheck.enabled}
/>
</div>
@@ -0,0 +1,20 @@
<script lang="ts">
import StorageTemplateSettings from '$lib/components/admin-settings/StorageTemplateSettings.svelte';
import FormatMessage from '$lib/elements/FormatMessage.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { Link } from '@immich/ui';
</script>
<div class="flex flex-col">
<p>
<FormatMessage key="admin.storage_template_onboarding_description_v2">
{#snippet children({ message })}
<Link href="https://docs.immich.app/administration/storage-template">{message}</Link>
{/snippet}
</FormatMessage>
</p>
{#if authManager.authenticated}
<StorageTemplateSettings minified duration={0} saveOnClose />
{/if}
</div>
@@ -0,0 +1,36 @@
<script lang="ts">
import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths';
import { Icon, themeManager, ThemePreference } from '@immich/ui';
import { t } from 'svelte-i18n';
</script>
<div class="flex flex-col gap-4">
<p>{$t('onboarding_theme_description')}</p>
<div class="flex gap-4">
<button
type="button"
class="w-1/2 aspect-square bg-light dark:bg-dark rounded-3xl transition-all shadow-sm hover:shadow-xl border-[3px] border-immich-primary dark:border dark:border-transparent"
onclick={() => themeManager.setPreference(ThemePreference.Light)}
>
<div
class="flex flex-col place-items-center place-content-center justify-around h-full w-full text-immich-primary"
>
<Icon icon={sunPath} viewBox={sunViewBox} size="96" />
<p class="font-semibold text-4xl">{$t('light')}</p>
</div>
</button>
<button
type="button"
class="w-1/2 aspect-square bg-dark dark:bg-light rounded-3xl transition-all shadow-sm hover:shadow-xl dark:border-[3px] dark:border-immich-dark-primary border border-transparent"
onclick={() => themeManager.setPreference(ThemePreference.Dark)}
>
<div
class="flex flex-col place-items-center place-content-center justify-around h-full w-full text-immich-dark-primary"
>
<Icon icon={moonPath} viewBox={moonViewBox} size="96" />
<p class="font-semibold text-4xl">{$t('dark')}</p>
</div>
</button>
</div>
</div>
@@ -0,0 +1,27 @@
<script lang="ts">
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { handleError } from '$lib/utils/handle-error';
import { updateMyPreferences } from '@immich/sdk';
import { onDestroy } from 'svelte';
import { t } from 'svelte-i18n';
let gCastEnabled = $state(authManager.authenticated ? authManager.preferences.cast.gCastEnabled : false);
onDestroy(async () => {
try {
const response = await updateMyPreferences({ userPreferencesUpdateDto: { cast: { gCastEnabled } } });
authManager.setPreferences(response);
} catch (error) {
handleError(error, $t('errors.unable_to_update_settings'));
}
});
</script>
<div class="flex flex-col gap-4">
<p>
{$t('onboarding_privacy_description')}
</p>
<SettingSwitch title={$t('gcast_enabled')} subtitle={$t('gcast_enabled_description')} bind:checked={gCastEnabled} />
</div>