fix(web): user settings styling (#25775)

This commit is contained in:
Mees Frensel 2026-02-02 14:47:28 +01:00 committed by GitHub
parent 1436e2a75f
commit 0273dcb0cf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 71 additions and 69 deletions

View file

@ -5,7 +5,6 @@
import { changePinCode } from '@immich/sdk'; import { changePinCode } from '@immich/sdk';
import { Button, Heading, modalManager, Text, toastManager } from '@immich/ui'; import { Button, Heading, modalManager, Text, toastManager } from '@immich/ui';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
let currentPinCode = $state(''); let currentPinCode = $state('');
let newPinCode = $state(''); let newPinCode = $state('');
@ -38,27 +37,23 @@
}; };
</script> </script>
<section class="my-4"> <form autocomplete="off" onsubmit={handleSubmit}>
<div in:fade={{ duration: 200 }}> <div class="flex flex-col gap-6 place-items-center place-content-center">
<form autocomplete="off" onsubmit={handleSubmit} class="mt-6"> <Heading>{$t('change_pin_code')}</Heading>
<div class="flex flex-col gap-6 place-items-center place-content-center"> <PinCodeInput label={$t('current_pin_code')} bind:value={currentPinCode} tabindexStart={1} pinLength={6} />
<Heading>{$t('change_pin_code')}</Heading> <PinCodeInput label={$t('new_pin_code')} bind:value={newPinCode} tabindexStart={7} pinLength={6} />
<PinCodeInput label={$t('current_pin_code')} bind:value={currentPinCode} tabindexStart={1} pinLength={6} /> <PinCodeInput label={$t('confirm_new_pin_code')} bind:value={confirmPinCode} tabindexStart={13} pinLength={6} />
<PinCodeInput label={$t('new_pin_code')} bind:value={newPinCode} tabindexStart={7} pinLength={6} /> <button type="button" onclick={() => modalManager.show(PinCodeResetModal, {})}>
<PinCodeInput label={$t('confirm_new_pin_code')} bind:value={confirmPinCode} tabindexStart={13} pinLength={6} /> <Text color="muted" class="underline" size="small">{$t('forgot_pin_code_question')}</Text>
<button type="button" onclick={() => modalManager.show(PinCodeResetModal, {})}> </button>
<Text color="muted" class="underline" size="small">{$t('forgot_pin_code_question')}</Text>
</button>
</div>
<div class="flex justify-end gap-2 mt-4">
<Button shape="round" color="secondary" type="button" size="small" onclick={resetForm}>
{$t('clear')}
</Button>
<Button shape="round" type="submit" size="small" loading={isLoading} disabled={!canSubmit}>
{$t('save')}
</Button>
</div>
</form>
</div> </div>
</section>
<div class="flex justify-end gap-2 mt-4">
<Button shape="round" color="secondary" type="button" size="small" onclick={resetForm}>
{$t('clear')}
</Button>
<Button shape="round" type="submit" size="small" loading={isLoading} disabled={!canSubmit}>
{$t('save')}
</Button>
</div>
</form>

View file

@ -20,7 +20,7 @@
<OnEvents {onUserPinCodeReset} /> <OnEvents {onUserPinCodeReset} />
<section> <section class="my-4 sm:ms-8">
{#if hasPinCode} {#if hasPinCode}
<div in:fade={{ duration: 200 }}> <div in:fade={{ duration: 200 }}>
<PinCodeChangeForm /> <PinCodeChangeForm />

View file

@ -59,7 +59,7 @@
<section class="my-4"> <section class="my-4">
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<div class="ms-8 mt-4 flex flex-col gap-6"> <div class="sm:ms-8 flex flex-col gap-6">
<Field label={$t('theme_selection')} description={$t('theme_selection_description')}> <Field label={$t('theme_selection')} description={$t('theme_selection_description')}>
<Switch checked={themeManager.theme.system} onCheckedChange={(checked) => themeManager.setSystem(checked)} /> <Switch checked={themeManager.theme.system} onCheckedChange={(checked) => themeManager.setSystem(checked)} />
</Field> </Field>

View file

@ -23,7 +23,7 @@
<section class="my-4"> <section class="my-4">
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<form autocomplete="off" {onsubmit}> <form autocomplete="off" {onsubmit}>
<div class="ms-4 mt-4 flex flex-col gap-4"> <div class="sm:ms-8 flex flex-col gap-4">
<Field label={$t('password')} required> <Field label={$t('password')} required>
<PasswordInput bind:value={password} autocomplete="current-password" /> <PasswordInput bind:value={password} autocomplete="current-password" />
</Field> </Field>

View file

@ -3,6 +3,7 @@
import { deleteAllSessions, deleteSession, getSessions, type SessionResponseDto } from '@immich/sdk'; import { deleteAllSessions, deleteSession, getSessions, type SessionResponseDto } from '@immich/sdk';
import { Button, modalManager, Text, toastManager } from '@immich/ui'; import { Button, modalManager, Text, toastManager } from '@immich/ui';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
import DeviceCard from './device-card.svelte'; import DeviceCard from './device-card.svelte';
interface Props { interface Props {
@ -50,33 +51,39 @@
</script> </script>
<section class="my-4"> <section class="my-4">
{#if currentSession} <div in:fade={{ duration: 500 }}>
<div class="mb-6"> <div class="sm:ms-8 flex flex-col gap-4">
<Text class="mb-2" fontWeight="medium" size="tiny" color="primary"> {#if currentSession}
{$t('current_device')} <div class="mb-6">
</Text> <Text class="mb-2" fontWeight="medium" size="tiny" color="primary">
<DeviceCard session={currentSession} /> {$t('current_device')}
</div> </Text>
{/if} <DeviceCard session={currentSession} />
{#if otherSessions.length > 0} </div>
<div class="mb-6"> {/if}
<Text class="mb-2" fontWeight="medium" size="tiny" color="primary"> {#if otherSessions.length > 0}
{$t('other_devices')} <div class="mb-6">
</Text> <Text class="mb-2" fontWeight="medium" size="tiny" color="primary">
{#each otherSessions as session, index (session.id)} {$t('other_devices')}
<DeviceCard {session} onDelete={() => handleDelete(session)} /> </Text>
{#if index !== otherSessions.length - 1} {#each otherSessions as session, index (session.id)}
<hr class="my-3" /> <DeviceCard {session} onDelete={() => handleDelete(session)} />
{/if} {#if index !== otherSessions.length - 1}
{/each} <hr class="my-3" />
</div> {/if}
{/each}
</div>
<div class="my-3"> <div class="my-3">
<hr /> <hr />
</div> </div>
<div class="flex justify-end"> <div class="flex justify-end">
<Button shape="round" color="danger" size="small" onclick={handleDeleteAll}>{$t('log_out_all_devices')}</Button> <Button shape="round" color="danger" size="small" onclick={handleDeleteAll}
>{$t('log_out_all_devices')}</Button
>
</div>
{/if}
</div> </div>
{/if} </div>
</section> </section>

View file

@ -39,7 +39,7 @@
<section class="my-4"> <section class="my-4">
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<form autocomplete="off" {onsubmit}> <form autocomplete="off" {onsubmit}>
<div class="ms-4 mt-4 flex flex-col gap-4"> <div class="sm:ms-8 flex flex-col gap-4">
<SettingInputField <SettingInputField
inputType={SettingInputFieldType.NUMBER} inputType={SettingInputFieldType.NUMBER}
label={$t('archive_size')} label={$t('archive_size')}

View file

@ -67,9 +67,9 @@
<section class="my-4"> <section class="my-4">
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<form autocomplete="off" {onsubmit}> <form autocomplete="off" {onsubmit}>
<div class="ms-4 mt-4 flex flex-col"> <div class="sm:ms-4 md:ms-8 flex flex-col">
<SettingAccordion key="albums" title={$t('albums')} subtitle={$t('albums_feature_description')}> <SettingAccordion key="albums" title={$t('albums')} subtitle={$t('albums_feature_description')}>
<div class="ms-4 mt-6 flex flex-col gap-4"> <div class="sm:ms-4 mt-4 flex flex-col gap-4">
<Field label={$t('albums_default_sort_order')} description={$t('albums_default_sort_order_description')}> <Field label={$t('albums_default_sort_order')} description={$t('albums_default_sort_order_description')}>
<Select <Select
options={[ options={[
@ -83,7 +83,7 @@
</SettingAccordion> </SettingAccordion>
<SettingAccordion key="folders" title={$t('folders')} subtitle={$t('folders_feature_description')}> <SettingAccordion key="folders" title={$t('folders')} subtitle={$t('folders_feature_description')}>
<div class="ms-4 mt-6 flex flex-col gap-4"> <div class="sm:ms-4 mt-4 flex flex-col gap-4">
<Field label={$t('enable')}> <Field label={$t('enable')}>
<Switch bind:checked={foldersEnabled} /> <Switch bind:checked={foldersEnabled} />
</Field> </Field>
@ -97,7 +97,7 @@
</SettingAccordion> </SettingAccordion>
<SettingAccordion key="memories" title={$t('time_based_memories')} subtitle={$t('photos_from_previous_years')}> <SettingAccordion key="memories" title={$t('time_based_memories')} subtitle={$t('photos_from_previous_years')}>
<div class="ms-4 mt-6 flex flex-col gap-4"> <div class="sm:ms-4 mt-4 flex flex-col gap-4">
<Field label={$t('enable')}> <Field label={$t('enable')}>
<Switch bind:checked={memoriesEnabled} /> <Switch bind:checked={memoriesEnabled} />
</Field> </Field>
@ -109,7 +109,7 @@
</SettingAccordion> </SettingAccordion>
<SettingAccordion key="people" title={$t('people')} subtitle={$t('people_feature_description')}> <SettingAccordion key="people" title={$t('people')} subtitle={$t('people_feature_description')}>
<div class="ms-4 mt-6 flex flex-col gap-4"> <div class="sm:ms-4 mt-4 flex flex-col gap-4">
<Field label={$t('enable')}> <Field label={$t('enable')}>
<Switch bind:checked={peopleEnabled} /> <Switch bind:checked={peopleEnabled} />
</Field> </Field>
@ -123,7 +123,7 @@
</SettingAccordion> </SettingAccordion>
<SettingAccordion key="rating" title={$t('rating')} subtitle={$t('rating_description')}> <SettingAccordion key="rating" title={$t('rating')} subtitle={$t('rating_description')}>
<div class="ms-4 mt-6 flex flex-col gap-4"> <div class="sm:ms-4 mt-4 flex flex-col gap-4">
<Field label={$t('enable')}> <Field label={$t('enable')}>
<Switch bind:checked={ratingsEnabled} /> <Switch bind:checked={ratingsEnabled} />
</Field> </Field>
@ -131,7 +131,7 @@
</SettingAccordion> </SettingAccordion>
<SettingAccordion key="shared-links" title={$t('shared_links')} subtitle={$t('shared_links_description')}> <SettingAccordion key="shared-links" title={$t('shared_links')} subtitle={$t('shared_links_description')}>
<div class="ms-4 mt-6 flex flex-col gap-4"> <div class="sm:ms-4 mt-4 flex flex-col gap-4">
<Field label={$t('enable')}> <Field label={$t('enable')}>
<Switch bind:checked={sharedLinksEnabled} /> <Switch bind:checked={sharedLinksEnabled} />
</Field> </Field>
@ -145,7 +145,7 @@
</SettingAccordion> </SettingAccordion>
<SettingAccordion key="tags" title={$t('tags')} subtitle={$t('tag_feature_description')}> <SettingAccordion key="tags" title={$t('tags')} subtitle={$t('tag_feature_description')}>
<div class="ms-4 mt-6 flex flex-col gap-4"> <div class="sm:ms-4 mt-4 flex flex-col gap-4">
<Field label={$t('enable')}> <Field label={$t('enable')}>
<Switch bind:checked={tagsEnabled} /> <Switch bind:checked={tagsEnabled} />
</Field> </Field>
@ -159,7 +159,7 @@
</SettingAccordion> </SettingAccordion>
<SettingAccordion key="cast" title={$t('cast')} subtitle={$t('cast_description')}> <SettingAccordion key="cast" title={$t('cast')} subtitle={$t('cast_description')}>
<div class="ms-4 mt-6 flex flex-col gap-4"> <div class="sm:ms-4 mt-4 flex flex-col gap-4">
<Field label={$t('gcast_enabled')} description={$t('gcast_enabled_description')}> <Field label={$t('gcast_enabled')} description={$t('gcast_enabled_description')}>
<Switch bind:checked={gCastEnabled} /> <Switch bind:checked={gCastEnabled} />
</Field> </Field>

View file

@ -42,7 +42,7 @@
<section class="my-4"> <section class="my-4">
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<form autocomplete="off" {onsubmit}> <form autocomplete="off" {onsubmit}>
<div class="ms-4 mt-4 flex flex-col gap-6"> <div class="sm:ms-8 flex flex-col gap-6">
<Field label={$t('enable')} description={$t('notification_toggle_setting_description')}> <Field label={$t('enable')} description={$t('notification_toggle_setting_description')}>
<Switch bind:checked={emailNotificationsEnabled} /> <Switch bind:checked={emailNotificationsEnabled} />
</Field> </Field>

View file

@ -45,7 +45,7 @@
<section class="my-4"> <section class="my-4">
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<div class="flex justify-end"> <div class="sm:ms-8 flex justify-end">
{#if loading} {#if loading}
<div class="flex place-content-center place-items-center"> <div class="flex place-content-center place-items-center">
<LoadingSpinner /> <LoadingSpinner />

View file

@ -33,7 +33,7 @@
<OnEvents {onApiKeyCreate} {onApiKeyUpdate} {onApiKeyDelete} /> <OnEvents {onApiKeyCreate} {onApiKeyUpdate} {onApiKeyDelete} />
<section class="my-4"> <section class="my-4">
<div class="flex flex-col gap-2" in:fade={{ duration: 500 }}> <div class="sm:ms-8 flex flex-col gap-2" in:fade={{ duration: 500 }}>
<div class="mb-2 flex justify-end"> <div class="mb-2 flex justify-end">
<Button leadingIcon={Create.icon} shape="round" size="small" onclick={() => Create.onAction(Create)}> <Button leadingIcon={Create.icon} shape="round" size="small" onclick={() => Create.onAction(Create)}>
{Create.title} {Create.title}

View file

@ -33,7 +33,7 @@
<section class="my-4"> <section class="my-4">
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<form autocomplete="off" onsubmit={preventDefault(bubble('submit'))}> <form autocomplete="off" onsubmit={preventDefault(bubble('submit'))}>
<div class="ms-4 mt-4 flex flex-col gap-4"> <div class="sm:ms-8 flex flex-col gap-4">
<Field label={$t('user_id')} disabled> <Field label={$t('user_id')} disabled>
<Input bind:value={editedUser.id} /> <Input bind:value={editedUser.id} />
</Field> </Field>

View file

@ -105,7 +105,7 @@
</script> </script>
<section class="my-4"> <section class="my-4">
<div in:fade={{ duration: 500 }}> <div class="sm:ms-8" in:fade={{ duration: 500 }}>
{#if $isPurchased} {#if $isPurchased}
<!-- BADGE TOGGLE --> <!-- BADGE TOGGLE -->
<div class="mb-4"> <div class="mb-4">

View file

@ -65,7 +65,7 @@
</TableRow> </TableRow>
{/snippet} {/snippet}
<section class="my-6 w-full"> <section class="my-4 w-full">
<Heading size="tiny">{$t('photos_and_videos')}</Heading> <Heading size="tiny">{$t('photos_and_videos')}</Heading>
<Table striped spacing="small" class="mt-4" size="small"> <Table striped spacing="small" class="mt-4" size="small">
<TableHeader> <TableHeader>