refactor: css variables (#19146)

This commit is contained in:
Jason Rasmussen 2025-06-12 19:06:38 -04:00 committed by GitHub
parent 2f3d4e15d2
commit 8923d5b0a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 63 additions and 101 deletions

10
web/package-lock.json generated
View File

@ -11,7 +11,7 @@
"dependencies": {
"@formatjs/icu-messageformat-parser": "^2.9.8",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@immich/ui": "^0.22.4",
"@immich/ui": "^0.22.7",
"@mapbox/mapbox-gl-rtl-text": "0.2.3",
"@mdi/js": "^7.4.47",
"@photo-sphere-viewer/core": "^5.11.5",
@ -90,7 +90,7 @@
"@oazapfts/runtime": "^1.0.2"
},
"devDependencies": {
"@types/node": "^22.15.21",
"@types/node": "^22.15.29",
"typescript": "^5.3.3"
}
},
@ -1330,9 +1330,9 @@
"link": true
},
"node_modules/@immich/ui": {
"version": "0.22.4",
"resolved": "https://registry.npmjs.org/@immich/ui/-/ui-0.22.4.tgz",
"integrity": "sha512-l0H8G8XZ3YaP/pA8NsLhGsNZpTAwcOyEFmF88D5HZkK3nFTZOQFxvzcMfyOeMS6Nevv0CHdvJp3ns0zajfvNzw==",
"version": "0.22.7",
"resolved": "https://registry.npmjs.org/@immich/ui/-/ui-0.22.7.tgz",
"integrity": "sha512-FdA0RDSOO1IDSTQmCbW9u5yXFl59EHu++tYonDR/FEZUKrMwfmQEanePSW5g5KofdumKEuxBN1fWFym3NbB0jQ==",
"license": "GNU Affero General Public License version 3",
"dependencies": {
"@mdi/js": "^7.4.47",

View File

@ -28,7 +28,7 @@
"dependencies": {
"@formatjs/icu-messageformat-parser": "^2.9.8",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@immich/ui": "^0.22.4",
"@immich/ui": "^0.22.7",
"@mapbox/mapbox-gl-rtl-text": "0.2.3",
"@mdi/js": "^7.4.47",
"@photo-sphere-viewer/core": "^5.11.5",

View File

@ -41,17 +41,11 @@
--color-immich-bg: rgb(var(--immich-bg));
--color-immich-fg: rgb(var(--immich-fg));
--color-immich-gray: rgb(var(--immich-gray));
--color-immich-error: rgb(var(--immich-error));
--color-immich-success: rgb(var(--immich-success));
--color-immich-warning: rgb(var(--immich-warning));
--color-immich-dark-primary: rgb(var(--immich-dark-primary));
--color-immich-dark-bg: rgb(var(--immich-dark-bg));
--color-immich-dark-fg: rgb(var(--immich-dark-fg));
--color-immich-dark-gray: rgb(var(--immich-dark-gray));
--color-immich-dark-error: rgb(var(--immich-dark-error));
--color-immich-dark-success: rgb(var(--immich-dark-success));
--color-immich-dark-warning: rgb(var(--immich-dark-warning));
}
@theme {
@ -74,18 +68,12 @@
--immich-primary: 66 80 175;
--immich-bg: 255 255 255;
--immich-fg: 0 0 0;
--immich-error: 229 115 115;
--immich-success: 129 199 132;
--immich-warning: 255 183 77;
/* dark */
--immich-dark-primary: 172 203 250;
--immich-dark-bg: 10 10 10;
--immich-dark-fg: 229 231 235;
--immich-dark-gray: 33 33 33;
--immich-dark-error: 211 47 47;
--immich-dark-success: 56 142 60;
--immich-dark-warning: 245 124 0;
}
*,

View File

@ -3,6 +3,7 @@
import Icon from '$lib/components/elements/icon.svelte';
import { locale } from '$lib/stores/preferences.store';
import { JobCommand, type JobCommandDto, type JobCountsDto, type QueueStatusDto } from '@immich/sdk';
import { IconButton } from '@immich/ui';
import {
mdiAlertCircle,
mdiAllInclusive,
@ -17,7 +18,6 @@
import { t } from 'svelte-i18n';
import JobTileButton from './job-tile-button.svelte';
import JobTileStatus from './job-tile-status.svelte';
import { IconButton } from '@immich/ui';
interface Props {
title: string;
@ -71,7 +71,7 @@
</span>
<div class="flex gap-2">
{#if jobCounts.failed > 0}
<Badge color="primary">
<Badge>
<div class="flex flex-row gap-1">
<span class="text-sm">
{$t('admin.jobs_failed', { values: { jobCount: jobCounts.failed.toLocaleString($locale) } })}
@ -88,7 +88,7 @@
</Badge>
{/if}
{#if jobCounts.delayed > 0}
<Badge color="secondary">
<Badge>
<span class="text-sm">
{$t('admin.jobs_delayed', { values: { jobCount: jobCounts.delayed.toLocaleString($locale) } })}
</span>

View File

@ -46,7 +46,7 @@
{#each tags as tag (tag.id)}
<div class="flex group transition-all">
<a
class="inline-block h-min whitespace-nowrap ps-3 pe-1 group-hover:ps-3 py-1 text-center align-baseline leading-none text-gray-100 dark:text-immich-dark-gray bg-immich-primary dark:bg-immich-dark-primary rounded-s-full hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all"
class="inline-block h-min whitespace-nowrap ps-3 pe-1 group-hover:ps-3 py-1 text-center align-baseline leading-none text-gray-100 dark:text-immich-dark-gray bg-primary rounded-s-full hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all"
href={encodeURI(`${AppRoute.TAGS}/?path=${tag.value}`)}
>
<p class="text-sm">

View File

@ -1,29 +1,16 @@
<script lang="ts" module>
export type Color = 'primary' | 'secondary';
export type Rounded = false | true | 'full';
</script>
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
color?: Color;
rounded?: Rounded;
rounded?: boolean | 'full';
children?: Snippet;
}
let { color = 'primary', rounded = true, children }: Props = $props();
const colorClasses: Record<Color, string> = {
primary: 'text-gray-100 dark:text-immich-dark-gray bg-immich-primary dark:bg-immich-dark-primary',
secondary: 'text-immich-dark-bg dark:text-immich-gray dark:bg-gray-600 bg-gray-300 dark:text-immich-gray',
};
let { rounded = true, children }: Props = $props();
</script>
<span
class="inline-block h-min whitespace-nowrap px-3 py-1 text-center align-baseline text-xs leading-none {colorClasses[
color
]}"
class="bg-primary text-subtle inline-block h-min whitespace-nowrap px-3 py-1 text-center align-baseline text-xs leading-none"
class:rounded-md={rounded === true}
class:rounded-full={rounded === 'full'}
>

View File

@ -169,19 +169,9 @@
>
<td class="w-1/8 text-ellipsis ps-8 text-sm">
{#if validatedPath.isValid}
<Icon
path={mdiCheckCircleOutline}
size="24"
title={validatedPath.message}
class="text-immich-success dark:text-immich-dark-success"
/>
<Icon path={mdiCheckCircleOutline} size="24" title={validatedPath.message} class="text-success" />
{:else}
<Icon
path={mdiAlertOutline}
size="24"
title={validatedPath.message}
class="text-immich-warning dark:text-immich-dark-warning"
/>
<Icon path={mdiAlertOutline} size="24" title={validatedPath.message} class="text-warning" />
{/if}
</td>

View File

@ -7,7 +7,7 @@
type ComponentNotification,
type Notification,
} from '$lib/components/shared-components/notification/notification';
import { IconButton } from '@immich/ui';
import { Button, IconButton, type Color } from '@immich/ui';
import { mdiCloseCircleOutline, mdiInformationOutline, mdiWindowClose } from '@mdi/js';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
@ -40,10 +40,10 @@
[NotificationType.Warning]: '#D08613',
};
const buttonStyle: Record<NotificationType, string> = {
[NotificationType.Info]: 'text-white bg-immich-primary hover:bg-immich-primary/75',
[NotificationType.Error]: 'text-white bg-immich-error hover:bg-immich-error/75',
[NotificationType.Warning]: 'text-white bg-immich-warning hover:bg-immich-warning/75',
const colors: Record<NotificationType, Color> = {
[NotificationType.Info]: 'primary',
[NotificationType.Error]: 'danger',
[NotificationType.Warning]: 'warning',
};
onMount(() => {
@ -111,16 +111,16 @@
</p>
{#if notification.button}
<p class="ps-[28px] mt-2.5 text-sm">
<button
type="button"
class="{buttonStyle[notification.type]} rounded px-3 pt-1.5 pb-1 transition-all duration-200"
<p class="ps-[28px] mt-2.5 light text-light">
<Button
size="small"
color={colors[notification.type]}
onclick={handleButtonClick}
aria-hidden="true"
tabindex={-1}
>
{notification.button.text}
</button>
</Button>
</p>
{/if}
</div>

View File

@ -505,10 +505,7 @@
{/if}
<!-- Scroll Position Indicator Line -->
{#if !usingMobileDevice && !isDragging}
<div
class="absolute end-0 h-[2px] w-10 bg-immich-primary dark:bg-immich-dark-primary"
style:top="{scrollY + PADDING_TOP - 2}px"
>
<div class="absolute end-0 h-[2px] w-10 bg-primary" style:top="{scrollY + PADDING_TOP - 2}px">
{#if timelineManager.scrolling && scrollHoverLabel && !isHover}
<p
transition:fade={{ duration: 200 }}

View File

@ -1,12 +1,12 @@
<script lang="ts">
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
import { getAllTags, type TagResponseDto } from '@immich/sdk';
import { t } from 'svelte-i18n';
import { onMount } from 'svelte';
import { SvelteSet } from 'svelte/reactivity';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiClose } from '@mdi/js';
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
import { preferences } from '$lib/stores/user.store';
import { getAllTags, type TagResponseDto } from '@immich/sdk';
import { mdiClose } from '@mdi/js';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
import { SvelteSet } from 'svelte/reactivity';
interface Props {
selectedTags: SvelteSet<string>;
@ -57,7 +57,7 @@
{#if tag}
<div class="flex group transition-all">
<span
class="inline-block h-min whitespace-nowrap ps-3 pe-1 group-hover:ps-3 py-1 text-center align-baseline leading-none text-gray-100 dark:text-immich-dark-gray bg-immich-primary dark:bg-immich-dark-primary roudned-s-full hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all"
class="inline-block h-min whitespace-nowrap ps-3 pe-1 group-hover:ps-3 py-1 text-center align-baseline leading-none text-gray-100 dark:text-immich-dark-gray bg-primary roudned-s-full hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all"
>
<p class="text-sm">
{tag.value}

View File

@ -1,12 +1,12 @@
<script lang="ts">
import { locale } from '$lib/stores/preferences.store';
import { user } from '$lib/stores/user.store';
import { userInteraction } from '$lib/stores/user.svelte';
import { requestServerInfo } from '$lib/utils/auth';
import { getByteUnitString } from '$lib/utils/byte-units';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
import { getByteUnitString } from '$lib/utils/byte-units';
import LoadingSpinner from '../loading-spinner.svelte';
import { userInteraction } from '$lib/stores/user.svelte';
let usageClasses = $state('');
@ -28,7 +28,7 @@
return 'bg-yellow-500';
}
return 'bg-immich-primary dark:bg-immich-dark-primary';
return 'bg-primary';
};
$effect(() => {

View File

@ -44,19 +44,19 @@
<div class="flex items-center gap-2">
<div class="flex items-center justify-center">
{#if uploadAsset.state === UploadState.PENDING}
<Icon path={mdiCircleOutline} size="24" class="text-immich-primary" title={$t('pending')} />
<Icon path={mdiCircleOutline} size="24" class="text-primary" title={$t('pending')} />
{:else if uploadAsset.state === UploadState.STARTED}
<Icon path={mdiLoading} size="24" spin class="text-immich-primary" title={$t('asset_skipped')} />
<Icon path={mdiLoading} size="24" spin class="text-primary" title={$t('asset_skipped')} />
{:else if uploadAsset.state === UploadState.ERROR}
<Icon path={mdiAlertCircle} size="24" class="text-immich-error" title={$t('error')} />
<Icon path={mdiAlertCircle} size="24" class="text-danger" title={$t('error')} />
{:else if uploadAsset.state === UploadState.DUPLICATED}
{#if uploadAsset.isTrashed}
<Icon path={mdiTrashCan} size="24" class="text-gray-500" title={$t('asset_skipped_in_trash')} />
{:else}
<Icon path={mdiAlertCircle} size="24" class="text-immich-warning" title={$t('asset_skipped')} />
<Icon path={mdiAlertCircle} size="24" class="text-warning" title={$t('asset_skipped')} />
{/if}
{:else if uploadAsset.state === UploadState.DONE}
<Icon path={mdiCheckCircle} size="24" class="text-immich-success" title={$t('asset_uploaded')} />
<Icon path={mdiCheckCircle} size="24" class="text-success" title={$t('asset_uploaded')} />
{/if}
</div>
<!-- <span>[{getByteUnitString(uploadAsset.file.size, $locale)}]</span> -->
@ -105,7 +105,7 @@
{#if uploadAsset.state === UploadState.ERROR}
<div class="flex flex-row justify-between">
<p class="w-full rounded-md text-justify text-immich-error">
<p class="w-full rounded-md text-justify text-danger">
{uploadAsset.error}
</p>
</div>

View File

@ -68,13 +68,13 @@
</p>
<p class="immich-form-label text-xs">
{$t('upload_status_uploaded')}
<span class="text-immich-success">{$stats.success.toLocaleString($locale)}</span>
<span class="text-success">{$stats.success.toLocaleString($locale)}</span>
-
{$t('upload_status_errors')}
<span class="text-immich-error">{$stats.errors.toLocaleString($locale)}</span>
<span class="text-danger">{$stats.errors.toLocaleString($locale)}</span>
-
{$t('upload_status_duplicates')}
<span class="text-immich-warning">{$stats.duplicates.toLocaleString($locale)}</span>
<span class="text-warning">{$stats.duplicates.toLocaleString($locale)}</span>
</p>
</div>
<div class="flex flex-col items-end">
@ -142,7 +142,7 @@
type="button"
in:scale={{ duration: 250, easing: quartInOut }}
onclick={() => (showDetail = true)}
class="absolute -start-4 -top-4 flex h-10 w-10 place-content-center place-items-center rounded-full bg-immich-primary p-5 text-xs text-gray-200"
class="absolute -start-4 -top-4 flex h-10 w-10 place-content-center place-items-center rounded-full bg-primary p-5 text-xs text-gray-200"
>
{$remainingUploads.toLocaleString($locale)}
</button>
@ -151,7 +151,7 @@
type="button"
in:scale={{ duration: 250, easing: quartInOut }}
onclick={() => (showDetail = true)}
class="absolute -end-4 -top-4 flex h-10 w-10 place-content-center place-items-center rounded-full bg-immich-error p-5 text-xs text-gray-200"
class="absolute -end-4 -top-4 flex h-10 w-10 place-content-center place-items-center rounded-full bg-danger p-5 text-xs text-gray-200"
>
{$stats.errors.toLocaleString($locale)}
</button>
@ -160,7 +160,7 @@
type="button"
in:scale={{ duration: 250, easing: quartInOut }}
onclick={() => (showDetail = true)}
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-subtle p-5 text-sm text-primary shadow-lg"
>
<div class="animate-pulse">
<Icon path={mdiCloudUploadOutline} size="30" />

View File

@ -39,16 +39,16 @@
};
const colorClasses: Record<UserAvatarColor, string> = {
primary: 'bg-immich-primary dark:bg-immich-dark-primary text-immich-dark-fg dark:text-immich-fg',
pink: 'bg-pink-400 text-immich-bg',
red: 'bg-red-500 text-immich-bg',
yellow: 'bg-yellow-500 text-immich-bg',
blue: 'bg-blue-500 text-immich-bg',
green: 'bg-green-600 text-immich-bg',
purple: 'bg-purple-600 text-immich-bg',
orange: 'bg-orange-600 text-immich-bg',
gray: 'bg-gray-600 text-immich-bg',
amber: 'bg-amber-600 text-immich-bg',
primary: 'bg-primary text-light dark:text-light',
pink: 'bg-pink-400 text-light dark:text-dark',
red: 'bg-red-500 text-light dark:text-dark',
yellow: 'bg-yellow-500 text-light dark:text-dark',
blue: 'bg-blue-500 text-light dark:text-dark',
green: 'bg-green-600 text-light dark:text-dark',
purple: 'bg-purple-600 text-light dark:text-dark',
orange: 'bg-orange-600 text-light dark:text-dark',
gray: 'bg-gray-600 text-light dark:text-dark',
amber: 'bg-amber-600 text-light dark:text-dark',
};
const sizeClasses: Record<Size, string> = {

View File

@ -85,7 +85,7 @@
{#key user.id}
<div class="flex place-items-center gap-4 p-4">
<div
class="flex h-10 w-10 items-center justify-center rounded-full border bg-immich-dark-success text-3xl text-white dark:border-immich-dark-gray dark:bg-immich-dark-success"
class="flex h-10 w-10 items-center justify-center rounded-full border bg-green-600 text-3xl text-white"
>
<Icon path={mdiCheck} size={24} />
</div>

View File

@ -77,7 +77,7 @@
{#if tag}
<div class="flex group transition-all">
<span
class="inline-block h-min whitespace-nowrap ps-3 pe-1 group-hover:ps-3 py-1 text-center align-baseline leading-none text-gray-100 dark:text-immich-dark-gray bg-immich-primary dark:bg-immich-dark-primary roudned-s-full hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all"
class="inline-block h-min whitespace-nowrap ps-3 pe-1 group-hover:ps-3 py-1 text-center align-baseline leading-none text-gray-100 dark:text-immich-dark-gray bg-primary roudned-s-full hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all"
>
<p class="text-sm">
{tag.value}

View File

@ -77,7 +77,7 @@
</div>
{#if forceDelete}
<p class="text-immich-error">{$t('admin.force_delete_user_warning')}</p>
<p class="text-danger">{$t('admin.force_delete_user_warning')}</p>
<p class="immich-form-label text-sm" id="confirm-user-desc">
{$t('admin.confirm_email_below', { values: { email: user.email } })}

View File

@ -101,7 +101,7 @@
return 'bg-yellow-500';
}
return 'bg-immich-primary dark:bg-immich-dark-primary';
return 'bg-primary';
};
const handleResetPassword = async () => {

View File

@ -139,7 +139,7 @@
<div class="flex flex-col w-full">
<div class=" bg-gray-300 dark:bg-gray-600 rounded-md h-2">
<div
class="progress-bar bg-immich-primary dark:bg-immich-dark-primary h-2 rounded-md transition-all duration-200 ease-out"
class="progress-bar bg-primary h-2 rounded-md transition-all duration-200 ease-out"
style="width: {(onboardingProgress / onboardingStepCount) * 100}%"
></div>
</div>