chore: lower case text + facelift (#25263)

* chore: lower case text

* wip

* wip

* pr feedback

* pr feedback
This commit is contained in:
Alex
2026-01-21 10:41:09 -06:00
committed by GitHub
parent 0f6606848e
commit b669714bda
36 changed files with 322 additions and 325 deletions

View File

@@ -1555,7 +1555,7 @@
"no_albums_with_name_yet": "It looks like you do not have any albums with this name yet.",
"no_albums_yet": "It looks like you do not have any albums yet.",
"no_archived_assets_message": "Archive photos and videos to hide them from your Photos view",
"no_assets_message": "CLICK TO UPLOAD YOUR FIRST PHOTO",
"no_assets_message": "Click to upload your first photo",
"no_assets_to_show": "No assets to show",
"no_cast_devices_found": "No cast devices found",
"no_checksum_local": "No checksum available - cannot fetch local assets",
@@ -2189,6 +2189,7 @@
"theme_setting_theme_subtitle": "Choose the app's theme setting",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"then": "Then",
"they_will_be_merged_together": "They will be merged together",
"third_party_resources": "Third-Party Resources",
"time": "Time",

View File

@@ -4,7 +4,7 @@
/* @import '/usr/ui/dist/theme/default.css'; */
@utility immich-form-input {
@apply rounded-xl bg-slate-200 px-3 py-3 text-sm focus:border-immich-primary disabled:cursor-not-allowed disabled:bg-gray-400 disabled:text-gray-100 dark:bg-gray-600 dark:text-immich-dark-fg dark:disabled:bg-gray-800 dark:disabled:text-gray-200;
@apply bg-gray-100 ring-1 ring-gray-200 transition outline-none focus-within:ring-1 disabled:cursor-not-allowed dark:bg-gray-800 dark:ring-neutral-900 flex w-full items-center rounded-lg disabled:bg-gray-300 disabled:text-dark dark:disabled:bg-gray-900 dark:disabled:text-gray-200 flex-1 py-2.5 text-base pl-4 pr-4;
}
@utility immich-form-label {

View File

@@ -5,6 +5,7 @@
import { Route } from '$lib/route';
import { asQueueItem } from '$lib/services/queue.service';
import { locale } from '$lib/stores/preferences.store';
import { transformToTitleCase } from '$lib/utils';
import { QueueCommand, type QueueCommandDto, type QueueResponseDto } from '@immich/sdk';
import { Icon, IconButton, Link } from '@immich/ui';
import {
@@ -53,7 +54,7 @@
<div class="flex items-center gap-2 text-xl font-semibold text-primary">
<Link class="flex items-center gap-2 hover:underline" href={Route.viewQueue(queue)} underline={false}>
<Icon {icon} size="1.25em" class="hidden shrink-0 sm:block" />
<span class="uppercase">{title}</span>
<span>{transformToTitleCase(title)}</span>
</Link>
<IconButton
color="primary"
@@ -131,7 +132,7 @@
onClick={() => onCommand({ command: QueueCommand.Start, force: false })}
>
<Icon icon={mdiAlertCircle} size="36" />
<span class="uppercase">{$t('disabled')}</span>
<span>{$t('disabled')}</span>
</QueueCardButton>
{/if}
@@ -139,7 +140,7 @@
{#if waitingCount > 0}
<QueueCardButton color="gray" onClick={() => onCommand({ command: QueueCommand.Empty, force: false })}>
<Icon icon={mdiClose} size="24" />
<span class="uppercase">{$t('clear')}</span>
<span>{$t('clear')}</span>
</QueueCardButton>
{/if}
{#if queue.isPaused}
@@ -147,12 +148,12 @@
<QueueCardButton color="light-gray" onClick={() => onCommand({ command: QueueCommand.Resume, force: false })}>
<!-- size property is not reactive, so have to use width and height -->
<Icon icon={mdiFastForward} {size} />
<span class="uppercase">{$t('resume')}</span>
<span>{$t('resume')}</span>
</QueueCardButton>
{:else}
<QueueCardButton color="light-gray" onClick={() => onCommand({ command: QueueCommand.Pause, force: false })}>
<Icon icon={mdiPause} size="24" />
<span class="uppercase">{$t('pause')}</span>
<span>{$t('pause')}</span>
</QueueCardButton>
{/if}
{/if}
@@ -161,25 +162,25 @@
{#if allText}
<QueueCardButton color="dark-gray" onClick={() => onCommand({ command: QueueCommand.Start, force: true })}>
<Icon icon={mdiAllInclusive} size="24" />
<span class="uppercase">{allText}</span>
<span>{allText}</span>
</QueueCardButton>
{/if}
{#if refreshText}
<QueueCardButton color="gray" onClick={() => onCommand({ command: QueueCommand.Start, force: undefined })}>
<Icon icon={mdiImageRefreshOutline} size="24" />
<span class="uppercase">{refreshText}</span>
<span>{refreshText}</span>
</QueueCardButton>
{/if}
<QueueCardButton color="light-gray" onClick={() => onCommand({ command: QueueCommand.Start, force: false })}>
<Icon icon={mdiSelectionSearch} size="24" />
<span class="uppercase">{missingText}</span>
<span>{missingText}</span>
</QueueCardButton>
{/if}
{#if !disabled && !multipleButtons && isIdle}
<QueueCardButton color="light-gray" onClick={() => onCommand({ command: QueueCommand.Start, force: false })}>
<Icon icon={mdiPlay} size="48" />
<span class="uppercase">{missingText}</span>
<span>{missingText}</span>
</QueueCardButton>
{/if}
</div>

View File

@@ -12,7 +12,7 @@
import { handleSystemConfigSave } from '$lib/services/system-config.service';
import { user } from '$lib/stores/user.store';
import { getStorageTemplateOptions, type SystemConfigTemplateStorageOptionDto } from '@immich/sdk';
import { LoadingSpinner } from '@immich/ui';
import { Heading, LoadingSpinner, Text } from '@immich/ui';
import handlebar from 'handlebars';
import * as luxon from 'luxon';
import { onDestroy } from 'svelte';
@@ -158,7 +158,9 @@
{#if configToEdit.storageTemplate.enabled}
<hr />
<h3 class="text-base font-medium text-primary">{$t('variables')}</h3>
<Heading size="tiny" color="primary">
{$t('variables')}
</Heading>
<section class="support-date">
{#await getSupportDateTimeFormat()}
@@ -174,11 +176,14 @@
<SupportedVariablesPanel />
</section>
<div class="flex flex-col mt-4">
<h3 class="text-base font-medium text-primary">{$t('template')}</h3>
<div class="flex flex-col mt-2">
<!-- <h3 class="text-base font-medium text-primary">{$t('template')}</h3> -->
<Heading size="tiny" color="primary">
{$t('template')}
</Heading>
<div class="my-2 text-sm">
<h4 class="uppercase">{$t('preview')}</h4>
<div class="my-2">
<Text size="small">{$t('preview')}</Text>
</div>
<p class="text-sm">
@@ -249,7 +254,9 @@
{#if !minified}
<div id="migration-info" class="mt-2 text-sm">
<h3 class="text-base font-medium text-primary">{$t('notes')}</h3>
<Heading size="tiny" color="primary">
{$t('notes')}
</Heading>
<section class="flex flex-col gap-2">
<p>
<FormatMessage

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { locale } from '$lib/stores/preferences.store';
import type { SystemConfigTemplateStorageOptionDto } from '@immich/sdk';
import { Card, CardBody, CardHeader, Text } from '@immich/ui';
import { DateTime } from 'luxon';
import { t } from 'svelte-i18n';
@@ -15,78 +16,80 @@
};
</script>
<div class="mt-2 text-sm">
<h4 class="uppercase">{$t('date_and_time')}</h4>
</div>
<Text size="small">{$t('date_and_time')}</Text>
<!-- eslint-disable svelte/no-useless-mustaches -->
<div class="mt-2 rounded-lg bg-gray-200 p-4 text-xs dark:bg-gray-700 dark:text-immich-dark-fg">
<div class="mb-2 text-gray-600 dark:text-immich-dark-fg">
<p>{$t('admin.storage_template_date_time_description')}</p>
<p>{$t('admin.storage_template_date_time_sample', { values: { date: '2022-02-03T20:03:05.250' } })}</p>
</div>
<div class="flex gap-10">
<div>
<p class="uppercase font-medium text-primary">{$t('year')}</p>
<ul>
{#each options.yearOptions as yearFormat, index (index)}
<li>{'{{'}{yearFormat}{'}}'} - {getLuxonExample(yearFormat)}</li>
{/each}
</ul>
</div>
<Card class="mt-2 text-sm bg-light-50 shadow-none">
<CardHeader>
<Text class="mb-1">{$t('admin.storage_template_date_time_description')}</Text>
<Text color="primary"
>{$t('admin.storage_template_date_time_sample', { values: { date: '2022-02-03T20:03:05.250' } })}</Text
>
</CardHeader>
<CardBody>
<div class="grid grid-cols-1 gap-6 sm:grid-cols-3 md:grid-cols-4">
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('year')}</Text>
<ul>
{#each options.yearOptions as yearFormat, index (index)}
<li>{'{{'}{yearFormat}{'}}'} - {getLuxonExample(yearFormat)}</li>
{/each}
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('month')}</p>
<ul>
{#each options.monthOptions as monthFormat, index (index)}
<li>{'{{'}{monthFormat}{'}}'} - {getLuxonExample(monthFormat)}</li>
{/each}
</ul>
</div>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('month')}</Text>
<ul>
{#each options.monthOptions as monthFormat, index (index)}
<li>{'{{'}{monthFormat}{'}}'} - {getLuxonExample(monthFormat)}</li>
{/each}
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('week')}</p>
<ul>
{#each options.weekOptions as weekFormat, index (index)}
<li>{'{{'}{weekFormat}{'}}'} - {getLuxonExample(weekFormat)}</li>
{/each}
</ul>
</div>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('week')}</Text>
<ul>
{#each options.weekOptions as weekFormat, index (index)}
<li>{'{{'}{weekFormat}{'}}'} - {getLuxonExample(weekFormat)}</li>
{/each}
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('day')}</p>
<ul>
{#each options.dayOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
</div>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('day')}</Text>
<ul>
{#each options.dayOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('hour')}</p>
<ul>
{#each options.hourOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
</div>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('hour')}</Text>
<ul>
{#each options.hourOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('minute')}</p>
<ul>
{#each options.minuteOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
</div>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('minute')}</Text>
<ul>
{#each options.minuteOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('second')}</p>
<ul>
{#each options.secondOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('second')}</Text>
<ul>
{#each options.secondOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
</div>
</div>
</div>
</div>
</CardBody>
</Card>

View File

@@ -1,56 +1,59 @@
<script lang="ts">
import { Card, CardBody, Text } from '@immich/ui';
import { t } from 'svelte-i18n';
</script>
<div class="mt-4 text-sm">
<h4 class="uppercase">{$t('other_variables')}</h4>
</div>
<Text size="small">{$t('other_variables')}</Text>
<div class="p-4 mt-2 text-xs bg-gray-200 rounded-lg dark:bg-gray-700 dark:text-immich-dark-fg">
<div class="flex gap-12">
<div>
<p class="uppercase font-medium text-primary">{$t('filename')}</p>
<ul>
<li>{`{{filename}}`} - IMG_123</li>
<li>{`{{ext}}`} - jpg</li>
</ul>
</div>
<Card class="mt-2 text-sm bg-light-50 shadow-none">
<CardBody>
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('filename')}</Text>
<ul>
<li>{`{{filename}}`} - IMG_123</li>
<li>{`{{ext}}`} - jpg</li>
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('filetype')}</p>
<ul>
<li>{`{{filetype}}`} - VID or IMG</li>
<li>{`{{filetypefull}}`} - VIDEO or IMAGE</li>
</ul>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('filetype')}</Text>
<ul>
<li>{`{{filetype}}`} - VID or IMG</li>
<li>{`{{filetypefull}}`} - VIDEO or IMAGE</li>
</ul>
</div>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('camera')}</Text>
<ul>
<li>{`{{make}}`} - FUJIFILM</li>
<li>{`{{model}}`} - X-T50</li>
<li>{`{{lensModel}}`} - XF27mm F2.8 R WR</li>
</ul>
</div>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('album')}</Text>
<ul>
<li>{`{{album}}`} - Album Name</li>
<li>
{`{{album-startDate-x}}`} - Album Start Date and Time (e.g. album-startDate-yy).
{$t('admin.storage_template_date_time_sample', { values: { date: '2021-12-31T05:32:41.750' } })}
</li>
<li>
{`{{album-endDate-x}}`} - Album End Date and Time (e.g. album-endDate-MM).
{$t('admin.storage_template_date_time_sample', { values: { date: '2023-05-06T09:15:17.100' } })}
</li>
</ul>
</div>
<div>
<Text fontWeight="medium" size="tiny" color="primary" class="mb-1">{$t('other')}</Text>
<ul>
<li>{`{{assetId}}`} - Asset ID</li>
<li>{`{{assetIdShort}}`} - Asset ID (last 12 characters)</li>
</ul>
</div>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('album')}</p>
<ul>
<li>{`{{album}}`} - Album Name</li>
<li>
{`{{album-startDate-x}}`} - Album Start Date and Time (e.g. album-startDate-yy).
{$t('admin.storage_template_date_time_sample', { values: { date: '2021-12-31T05:32:41.750' } })}
</li>
<li>
{`{{album-endDate-x}}`} - Album End Date and Time (e.g. album-endDate-MM).
{$t('admin.storage_template_date_time_sample', { values: { date: '2023-05-06T09:15:17.100' } })}
</li>
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('camera')}</p>
<ul>
<li>{`{{make}}`} - FUJIFILM</li>
<li>{`{{model}}`} - X-T50</li>
<li>{`{{lensModel}}`} - XF27mm F2.8 R WR</li>
</ul>
</div>
<div>
<p class="uppercase font-medium text-primary">{$t('other')}</p>
<ul>
<li>{`{{assetId}}`} - Asset ID</li>
<li>{`{{assetIdShort}}`} - Asset ID (last 12 characters)</li>
</ul>
</div>
</div>
</div>
</CardBody>
</Card>

View File

@@ -5,7 +5,7 @@
import { Route } from '$lib/route';
import { removeTag } from '$lib/utils/asset-utils';
import { getAssetInfo, type AssetResponseDto } from '@immich/sdk';
import { Icon, modalManager } from '@immich/ui';
import { Icon, modalManager, Text } from '@immich/ui';
import { mdiClose, mdiPlus } from '@mdi/js';
import { t } from 'svelte-i18n';
@@ -38,7 +38,7 @@
{#if isOwner && !authManager.isSharedLink}
<section class="px-4 mt-4">
<div class="flex h-10 w-full items-center justify-between text-sm">
<h2 class="uppercase">{$t('tags')}</h2>
<Text color="muted">{$t('tags')}</Text>
</div>
<section class="flex flex-wrap pt-2 gap-1" data-testid="detail-panel-tags">
{#each tags as tag (tag.id)}

View File

@@ -20,7 +20,7 @@
import { fromISODateTime, fromISODateTimeUTC, toTimelineAsset } from '$lib/utils/timeline-util';
import { getParentPath } from '$lib/utils/tree-utils';
import { AssetMediaSize, getAssetInfo, type AlbumResponseDto, type AssetResponseDto } from '@immich/sdk';
import { Icon, IconButton, LoadingSpinner, modalManager } from '@immich/ui';
import { Icon, IconButton, LoadingSpinner, modalManager, Text } from '@immich/ui';
import {
mdiCalendar,
mdiCamera,
@@ -160,7 +160,7 @@
{#if !authManager.isSharedLink && isOwner}
<section class="px-4 pt-4 text-sm">
<div class="flex h-10 w-full items-center justify-between">
<h2 class="uppercase">{$t('people')}</h2>
<Text size="small" color="muted">{$t('people')}</Text>
<div class="flex gap-2 items-center">
{#if people.some((person) => person.isHidden)}
<IconButton
@@ -259,10 +259,10 @@
<div class="px-4 py-4">
{#if asset.exifInfo}
<div class="flex h-10 w-full items-center justify-between text-sm">
<h2 class="uppercase">{$t('details')}</h2>
<Text size="small" color="muted">{$t('details')}</Text>
</div>
{:else}
<p class="uppercase text-sm">{$t('no_exif_info_available')}</p>
<Text size="small" color="muted">{$t('no_exif_info_available')}</Text>
{/if}
{#if dateTime}
@@ -487,7 +487,7 @@
{#if currentAlbum && currentAlbum.albumUsers.length > 0 && asset.owner}
<section class="px-6 dark:text-immich-dark-fg mt-4">
<p class="uppercase text-sm">{$t('shared_by')}</p>
<Text size="small" color="muted">{$t('shared_by')}</Text>
<div class="flex gap-4 pt-4">
<div>
<UserAvatar user={asset.owner} size="md" />
@@ -504,7 +504,9 @@
{#if albums.length > 0}
<section class="px-6 py-6 dark:text-immich-dark-fg">
<p class="uppercase pb-4 text-sm">{$t('appears_in')}</p>
<div class="pb-4">
<Text size="small" color="muted">{$t('appears_in')}</Text>
</div>
{#each albums as album (album.id)}
<a href={Route.viewAlbum(album)}>
<div class="flex gap-4 pt-2 hover:cursor-pointer items-center">

View File

@@ -147,7 +147,7 @@
{/if}
</div>
<div class="px-4 py-4 text-sm">
<h2 class="mb-8 mt-4 uppercase">{$t('all_people')}</h2>
<h2 class="mb-8 mt-4">{$t('all_people')}</h2>
{#if isShowLoadingPeople}
<div class="flex w-full justify-center">
<LoadingSpinner />

View File

@@ -39,7 +39,7 @@
<Icon {icon} size="30" class="text-primary" />
{/if}
{#if title}
<p class="uppercase text-xl text-primary">
<p class="text-xl text-primary font-medium">
{title}
</p>
{/if}

View File

@@ -19,7 +19,7 @@
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="uppercase font-semibold text-4xl">{$t('light')}</p>
<p class="font-semibold text-4xl">{$t('light')}</p>
</div>
</button>
<button
@@ -31,7 +31,7 @@
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="uppercase font-semibold text-4xl">{$t('dark')}</p>
<p class="font-semibold text-4xl">{$t('dark')}</p>
</div>
</button>
</div>

View File

@@ -24,7 +24,7 @@
import { shortcuts } from '$lib/actions/shortcut';
import { generateId } from '$lib/utils/generate-id';
import { Icon, IconButton, Label } from '@immich/ui';
import { mdiClose, mdiMagnify, mdiUnfoldMoreHorizontal } from '@mdi/js';
import { mdiChevronDown, mdiClose, mdiMagnify } from '@mdi/js';
import { onMount, tick } from 'svelte';
import { t } from 'svelte-i18n';
import type { FormEventHandler } from 'svelte/elements';
@@ -251,7 +251,7 @@
</script>
<svelte:window onresize={onPositionChange} />
<Label class="block mb-1 {hideLabel ? 'sr-only' : ''}" for={inputId}>{label}</Label>
<Label class="block mb-1 {hideLabel ? 'sr-only' : ''} text-xs text-neutral-500 font-light" for={inputId}>{label}</Label>
<div
class="relative w-full dark:text-gray-300 text-gray-700 text-base"
use:focusOutside={{ onFocusOut: deactivate }}
@@ -351,7 +351,7 @@
size="small"
/>
{:else if !isOpen}
<Icon icon={mdiUnfoldMoreHorizontal} aria-hidden />
<Icon icon={mdiChevronDown} aria-hidden />
{/if}
</div>
</div>
@@ -391,7 +391,7 @@
<li
aria-selected={index === selectedIndex}
bind:this={optionRefs[index]}
class="text-start w-full px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-700 transition-all cursor-pointer aria-selected:bg-gray-200 aria-selected:dark:bg-gray-700 break-words"
class="text-start w-full px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-700 transition-all cursor-pointer aria-selected:bg-gray-200 aria-selected:dark:bg-gray-700 wrap-break-words"
id={`${listboxId}-${index}`}
onclick={() => handleSelect(option)}
role="option"

View File

@@ -10,6 +10,7 @@
import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte';
import { handlePromiseError } from '$lib/utils';
import { SearchSuggestionType, getSearchSuggestions } from '@immich/sdk';
import { Text } from '@immich/ui';
import { t } from 'svelte-i18n';
interface Props {
@@ -81,8 +82,7 @@
</script>
<div id="camera-selection">
<p class="uppercase immich-form-label">{$t('camera')}</p>
<Text fontWeight="medium">{$t('camera')}</Text>
<div class="grid grid-auto-fit-40 gap-5 mt-1">
<div class="w-full">
<Combobox

View File

@@ -1,13 +1,13 @@
<script lang="ts" module>
export interface SearchDateFilter {
takenBefore?: string;
takenAfter?: string;
takenBefore?: DateTime;
takenAfter?: DateTime;
}
</script>
<script lang="ts">
import DateInput from '$lib/elements/DateInput.svelte';
import { Text } from '@immich/ui';
import { DatePicker, Text } from '@immich/ui';
import type { DateTime } from 'luxon';
import { t } from 'svelte-i18n';
interface Props {
@@ -17,23 +17,19 @@
let { filters = $bindable() }: Props = $props();
let invalid = $derived(filters.takenAfter && filters.takenBefore && filters.takenAfter > filters.takenBefore);
const inputClasses = $derived(
`immich-form-input w-full mt-1 hover:cursor-pointer ${invalid ? 'border border-danger' : ''}`,
);
</script>
<div class="flex flex-col gap-1">
<div id="date-range-selection" class="grid grid-auto-fit-40 gap-5">
<label class="immich-form-label" for="start-date">
<span class="uppercase">{$t('start_date')}</span>
<DateInput class={inputClasses} type="date" id="start-date" name="start-date" bind:value={filters.takenAfter} />
</label>
<div>
<Text class="mb-2" fontWeight="medium">{$t('start_date')}</Text>
<DatePicker bind:value={filters.takenAfter} />
</div>
<label class="immich-form-label" for="end-date">
<span class="uppercase">{$t('end_date')}</span>
<DateInput class={inputClasses} type="date" id="end-date" name="end-date" bind:value={filters.takenBefore} />
</label>
<div>
<Text class="mb-2" fontWeight="medium">{$t('end_date')}</Text>
<DatePicker bind:value={filters.takenBefore} />
</div>
</div>
{#if invalid}
<Text color="danger">{$t('start_date_before_end_date')}</Text>

View File

@@ -7,7 +7,7 @@
</script>
<script lang="ts">
import { Checkbox, Label } from '@immich/ui';
import { Checkbox, Label, Text } from '@immich/ui';
import { t } from 'svelte-i18n';
@@ -20,19 +20,20 @@
<div id="display-options-selection">
<fieldset>
<legend class="uppercase immich-form-label">{$t('display_options')}</legend>
<Text class="mb-2" fontWeight="medium">{$t('display_options')}</Text>
<div class="flex flex-wrap gap-x-5 gap-y-2 mt-1">
<div class="flex items-center gap-2">
<Checkbox id="not-in-album-checkbox" size="tiny" bind:checked={filters.isNotInAlbum} />
<Label label={$t('not_in_any_album')} for="not-in-album-checkbox" />
<Label label={$t('not_in_any_album')} for="not-in-album-checkbox" class="text-sm font-normal" />
</div>
<div class="flex items-center gap-2">
<Checkbox id="archive-checkbox" size="tiny" bind:checked={filters.isArchive} />
<Label label={$t('archive')} for="archive-checkbox" />
<Label label={$t('archive')} for="archive-checkbox" class="text-sm font-normal" />
</div>
<div class="flex items-center gap-2">
<Checkbox id="favorites-checkbox" size="tiny" bind:checked={filters.isFavorite} />
<Label label={$t('favorites')} for="favorites-checkbox" />
<Label label={$t('favorites')} for="favorites-checkbox" class="text-sm font-normal" />
</div>
</div>
</fieldset>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { searchStore } from '$lib/stores/search.svelte';
import { Icon, IconButton } from '@immich/ui';
import { Icon, IconButton, Text } from '@immich/ui';
import { mdiClose, mdiMagnify } from '@mdi/js';
import { t } from 'svelte-i18n';
import { fly } from 'svelte/transition';
@@ -97,7 +97,7 @@
class="absolute w-full rounded-b-3xl border-2 border-t-0 border-gray-200 bg-white pb-5 shadow-2xl transition-all dark:border-gray-700 dark:bg-immich-dark-gray dark:text-gray-300 z-1"
>
<div class="flex items-center justify-between px-5 pt-5 text-xs">
<p class="uppercase py-2" aria-hidden={true}>{$t('recent_searches')}</p>
<Text class="py-2" color="muted" aria-hidden={true}>{$t('recent_searches')}</Text>
{#if showClearAll}
<button
id={getId(0)}

View File

@@ -10,6 +10,7 @@
import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte';
import { handlePromiseError } from '$lib/utils';
import { getSearchSuggestions, SearchSuggestionType } from '@immich/sdk';
import { Text } from '@immich/ui';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
@@ -74,7 +75,7 @@
</script>
<div id="location-selection">
<p class="uppercase immich-form-label">{$t('place')}</p>
<Text fontWeight="medium">{$t('place')}</Text>
<div class="grid grid-auto-fit-40 gap-5 mt-1">
<div class="w-full">

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { MediaType } from '$lib/constants';
import RadioButton from '$lib/elements/RadioButton.svelte';
import { Text } from '@immich/ui';
import { t } from 'svelte-i18n';
interface Props {
@@ -12,7 +13,8 @@
<div id="media-type-selection">
<fieldset>
<legend class="uppercase immich-form-label">{$t('media_type')}</legend>
<Text class="mb-2" fontWeight="medium">{$t('media_type')}</Text>
<div class="flex flex-wrap gap-x-5 gap-y-2 mt-1">
<RadioButton name="media-type" id="type-all" bind:group={filteredMedia} label={$t('all')} value={MediaType.All} />
<RadioButton

View File

@@ -5,7 +5,7 @@
import { getPeopleThumbnailUrl } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { getAllPeople, type PersonResponseDto } from '@immich/sdk';
import { Button, LoadingSpinner } from '@immich/ui';
import { Button, LoadingSpinner, Text } from '@immich/ui';
import { mdiArrowRight, mdiClose } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { SvelteSet } from 'svelte/reactivity';
@@ -63,12 +63,12 @@
<div id="people-selection" class="max-h-60 -mb-4 overflow-y-auto immich-scrollbar">
<div class="flex items-center w-full justify-between gap-6">
<p class="uppercase immich-form-label py-3">{$t('people')}</p>
<Text class="py-3" fontWeight="medium">{$t('people')}</Text>
<SearchBar bind:name placeholder={$t('filter_people')} showLoadingSpinner={false} />
</div>
<SingleGridRow
class="grid grid-auto-fill-20 gap-1 mt-2 overflow-y-auto immich-scrollbar"
class="grid grid-auto-fill-20 gap-1 mt-2 overflow-y-auto immich-scrollbar space-between"
bind:itemCount={numberOfPeople}
>
{#each peopleList as person (person.id)}

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { Text } from '@immich/ui';
import { t } from 'svelte-i18n';
import Combobox from '../combobox.svelte';
@@ -18,16 +19,14 @@
];
</script>
<div class="grid grid-auto-fit-40 gap-5">
<label class="immich-form-label" for="start-date">
<div class="[&_label]:uppercase">
<Combobox
label={$t('rating')}
placeholder={$t('search_rating')}
{options}
selectedOption={rating === undefined ? undefined : options[rating]}
onSelect={(r) => (rating = r === undefined ? undefined : Number.parseInt(r.value))}
/>
</div>
</label>
<div class="flex flex-col">
<Text class="mb-2" fontWeight="medium">{$t('rating')}</Text>
<Combobox
label={$t('rating')}
placeholder={$t('search_rating')}
hideLabel
{options}
selectedOption={rating === undefined ? undefined : options[rating]}
onSelect={(r) => (rating = r === undefined ? undefined : Number.parseInt(r.value))}
/>
</div>

View File

@@ -2,7 +2,7 @@
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 { Checkbox, Icon, Label } from '@immich/ui';
import { Checkbox, Icon, Label, Text } from '@immich/ui';
import { mdiClose } from '@mdi/js';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
@@ -43,18 +43,18 @@
{#if $preferences?.tags?.enabled}
<div id="location-selection">
<form autocomplete="off" id="create-tag-form">
<div class="my-4 flex flex-col gap-2">
<div class="[&_label]:uppercase">
<Combobox
disabled={selectedTags === null}
onSelect={handleSelect}
label={$t('tags')}
defaultFirstOption
options={allTags.map((tag) => ({ id: tag.id, label: tag.value, value: tag.id }))}
bind:selectedOption
placeholder={$t('search_tags')}
/>
</div>
<div class="mb-4 flex flex-col">
<Text class="py-3" fontWeight="medium">{$t('tags')}</Text>
<Combobox
disabled={selectedTags === null}
hideLabel
onSelect={handleSelect}
label={$t('tags')}
defaultFirstOption
options={allTags.map((tag) => ({ id: tag.id, label: tag.value, value: tag.id }))}
bind:selectedOption
placeholder={$t('search_tags')}
/>
</div>
<div class="flex items-center gap-2">
<Checkbox
@@ -65,7 +65,7 @@
selectedTags = checked ? null : new SvelteSet();
}}
/>
<Label label={$t('untagged')} for="untagged-checkbox" />
<Label label={$t('untagged')} for="untagged-checkbox" class="text-sm font-normal" />
</div>
</form>

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import RadioButton from '$lib/elements/RadioButton.svelte';
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { Field, Input, Text } from '@immich/ui';
import { t } from 'svelte-i18n';
interface Props {
@@ -11,73 +12,48 @@
let { query = $bindable(), queryType = $bindable('smart') }: Props = $props();
</script>
<fieldset>
<legend class="immich-form-label">{$t('search_type')}</legend>
<div class="flex flex-wrap gap-x-5 gap-y-2 mt-1 mb-2">
{#if featureFlagsManager.value.smartSearch}
<RadioButton name="query-type" id="context-radio" label={$t('context')} bind:group={queryType} value="smart" />
{/if}
<RadioButton
name="query-type"
id="file-name-radio"
label={$t('file_name_or_extension')}
bind:group={queryType}
value="metadata"
/>
<RadioButton
name="query-type"
id="description-radio"
label={$t('description')}
bind:group={queryType}
value="description"
/>
{#if featureFlagsManager.value.ocr}
<RadioButton name="query-type" id="ocr-radio" label={$t('ocr')} bind:group={queryType} value="ocr" />
{/if}
</div>
</fieldset>
<section>
<fieldset>
<Text class="mb-2" fontWeight="medium">{$t('search_type')}</Text>
<div class="flex flex-wrap gap-x-5 gap-y-2 my-2">
{#if featureFlagsManager.value.smartSearch}
<RadioButton name="query-type" id="context-radio" label={$t('context')} bind:group={queryType} value="smart" />
{/if}
<RadioButton
name="query-type"
id="file-name-radio"
label={$t('file_name_or_extension')}
bind:group={queryType}
value="metadata"
/>
<RadioButton
name="query-type"
id="description-radio"
label={$t('description')}
bind:group={queryType}
value="description"
/>
{#if featureFlagsManager.value.ocr}
<RadioButton name="query-type" id="ocr-radio" label={$t('ocr')} bind:group={queryType} value="ocr" />
{/if}
</div>
</fieldset>
{#if queryType === 'smart'}
<label for="context-input" class="immich-form-label">{$t('search_by_context')}</label>
<input
class="immich-form-input hover:cursor-text w-full mt-1!"
type="text"
id="context-input"
name="context"
placeholder={$t('sunrise_on_the_beach')}
bind:value={query}
/>
{:else if queryType === 'metadata'}
<label for="file-name-input" class="immich-form-label">{$t('search_by_filename')}</label>
<input
class="immich-form-input hover:cursor-text w-full mt-1!"
type="text"
id="file-name-input"
name="file-name"
placeholder={$t('search_by_filename_example')}
bind:value={query}
aria-labelledby="file-name-label"
/>
{:else if queryType === 'description'}
<label for="description-input" class="immich-form-label">{$t('search_by_description')}</label>
<input
class="immich-form-input hover:cursor-text w-full mt-1!"
type="text"
id="description-input"
name="description"
placeholder={$t('search_by_description_example')}
bind:value={query}
aria-labelledby="description-label"
/>
{:else if queryType === 'ocr'}
<label for="ocr-input" class="immich-form-label">{$t('search_by_ocr')}</label>
<input
class="immich-form-input hover:cursor-text w-full mt-1!"
type="text"
id="ocr-input"
name="ocr"
placeholder={$t('search_by_ocr_example')}
bind:value={query}
aria-labelledby="ocr-label"
/>
{/if}
{#if queryType === 'smart'}
<Field label={$t('search_by_context')}>
<Input type="text" placeholder={$t('sunrise_on_the_beach')} bind:value={query} />
</Field>
{:else if queryType === 'metadata'}
<Field label={$t('search_by_filename')}>
<Input type="text" placeholder={$t('search_by_filename_example')} bind:value={query} />
</Field>
{:else if queryType === 'description'}
<Field label={$t('search_by_description')}>
<Input type="text" placeholder={$t('search_by_description_example')} bind:value={query} />
</Field>
{:else if queryType === 'ocr'}
<Field label={$t('search_by_ocr')}>
<Input type="text" placeholder={$t('search_by_ocr_example')} bind:value={query} />
</Field>
{/if}
</section>

View File

@@ -81,7 +81,7 @@
<div class="mb-4 w-full">
<div class="flex place-items-center gap-1">
<label class="font-medium text-primary text-sm min-h-6 uppercase" for={label}>{label}</label>
<label class="font-medium text-primary text-sm min-h-6" for={label}>{label}</label>
{#if required}
<div class="text-red-400">*</div>
{/if}

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { handleError } from '$lib/utils/handle-error';
import { deleteAllSessions, deleteSession, getSessions, type SessionResponseDto } from '@immich/sdk';
import { Button, modalManager, toastManager } from '@immich/ui';
import { Button, modalManager, Text, toastManager } from '@immich/ui';
import { t } from 'svelte-i18n';
import DeviceCard from './device-card.svelte';
@@ -52,17 +52,17 @@
<section class="my-4">
{#if currentSession}
<div class="mb-6">
<h3 class="uppercase mb-2 text-xs font-medium text-primary">
<Text class="mb-2" fontWeight="medium" size="tiny" color="primary">
{$t('current_device')}
</h3>
</Text>
<DeviceCard session={currentSession} />
</div>
{/if}
{#if otherSessions.length > 0}
<div class="mb-6">
<h3 class="uppercase mb-2 text-xs font-medium text-primary">
<Text class="mb-2" fontWeight="medium" size="tiny" color="primary">
{$t('other_devices')}
</h3>
</Text>
{#each otherSessions as session, index (session.id)}
<DeviceCard {session} onDelete={() => handleDelete(session)} />
{#if index !== otherSessions.length - 1}
@@ -70,9 +70,11 @@
{/if}
{/each}
</div>
<h3 class="uppercase mb-2 text-xs font-medium text-primary">
{$t('log_out_all_devices')}
</h3>
<div class="my-3">
<hr />
</div>
<div class="flex justify-end">
<Button shape="round" color="danger" size="small" onclick={handleDeleteAll}>{$t('log_out_all_devices')}</Button>
</div>

View File

@@ -12,7 +12,7 @@
type PartnerResponseDto,
type UserResponseDto,
} from '@immich/sdk';
import { Button, Icon, IconButton, modalManager } from '@immich/ui';
import { Button, Icon, IconButton, modalManager, Text } from '@immich/ui';
import { mdiCheck, mdiClose } from '@mdi/js';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
@@ -157,10 +157,12 @@
<!-- I am sharing my assets with this user -->
{#if partner.sharedByMe}
<hr class="my-4 border border-gray-200 dark:border-gray-700" />
<p class="uppercase text-xs font-medium my-4">
<Text class="my-4" size="small" fontWeight="medium">
{$t('shared_with_partner', { values: { partner: partner.user.name } })}
</p>
<p class="text-md">{$t('partner_can_access', { values: { partner: partner.user.name } })}</p>
</Text>
<Text size="tiny" fontWeight="medium"
>{$t('partner_can_access', { values: { partner: partner.user.name } })}</Text
>
<ul class="text-sm">
<li class="flex gap-2 place-items-center py-1 mt-2">
<Icon icon={mdiCheck} />
@@ -176,9 +178,10 @@
<!-- this user is sharing assets with me -->
{#if partner.sharedWithMe}
<hr class="my-4 border border-gray-200 dark:border-gray-700" />
<p class="uppercase text-xs font-medium my-4">
<Text class="my-4" size="small" fontWeight="medium">
{$t('shared_from_partner', { values: { partner: partner.user.name } })}
</p>
</Text>
<SettingSwitch
title={$t('show_in_timeline')}
subtitle={$t('show_in_timeline_setting_description')}

View File

@@ -2,7 +2,7 @@
import AppDownloadModal from '$lib/modals/AppDownloadModal.svelte';
import ObtainiumConfigModal from '$lib/modals/ObtainiumConfigModal.svelte';
import { Route } from '$lib/route';
import { Icon, modalManager } from '@immich/ui';
import { Icon, modalManager, Text } from '@immich/ui';
import {
mdiCellphoneArrowDownVariant,
mdiContentDuplicate,
@@ -22,7 +22,7 @@
</script>
<div class="border border-gray-300 dark:border-immich-dark-gray rounded-3xl pt-1 pb-6 dark:text-white">
<p class="uppercase text-xs font-medium p-4">{$t('organize_your_library')}</p>
<Text size="tiny" color="muted" fontWeight="medium" class="p-4">{$t('organize_your_library')}</Text>
{#each links as link (link.href)}
<a href={link.href} class="w-full hover:bg-gray-100 dark:hover:bg-immich-dark-gray flex items-center gap-4 p-4">
@@ -33,7 +33,8 @@
</div>
<br />
<div class="border border-gray-300 dark:border-immich-dark-gray rounded-3xl pt-1 pb-6 dark:text-white">
<p class="uppercase text-xs font-medium p-4">{$t('download')}</p>
<Text size="tiny" color="muted" fontWeight="medium" class="p-4">{$t('download')}</Text>
<button
type="button"
onclick={() => modalManager.show(ObtainiumConfigModal, {})}

View File

@@ -113,7 +113,7 @@
<div class="rounded-lg bg-light-100 border p-3">
<div class="flex items-center gap-2 mb-1">
<Icon icon={mdiFlashOutline} size="18" class="text-primary" />
<span class="text-[10px] font-semibold uppercase tracking-wide">{$t('trigger')}</span>
<Text size="tiny" fontWeight="semi-bold">{$t('trigger')}</Text>
</div>
<p class="text-sm truncate pl-5">{getTriggerName(trigger.type)}</p>
</div>
@@ -128,7 +128,7 @@
<div class="rounded-lg bg-light-100 border p-3">
<div class="flex items-center gap-2 mb-2">
<Icon icon={mdiFilterOutline} size="18" class="text-warning" />
<span class="text-[10px] font-semibold uppercase tracking-wide">{$t('filters')}</span>
<Text size="tiny" fontWeight="semi-bold">{$t('filters')}</Text>
</div>
<div class="space-y-1 pl-5">
{#each filters as filter, index (index)}
@@ -154,7 +154,7 @@
<div class="rounded-lg bg-light-100 border p-3">
<div class="flex items-center gap-2 mb-2">
<Icon icon={mdiPlayCircleOutline} size="18" class="text-success" />
<span class="text-[10px] font-semibold uppercase tracking-wide">{$t('actions')}</span>
<Text size="tiny" fontWeight="semi-bold">{$t('actions')}</Text>
</div>
<div class="space-y-1 pl-5">
{#each actions as action, index (index)}

View File

@@ -12,5 +12,5 @@
<div class="flex items-center gap-2">
<input type="radio" {name} {id} {value} class="focus-visible:ring" bind:group />
<label for={id}>{label}</label>
<label for={id} class="text-sm">{label}</label>
</div>

View File

@@ -37,6 +37,7 @@
import { AssetTypeEnum, AssetVisibility, type MetadataSearchDto, type SmartSearchDto } from '@immich/sdk';
import { Button, HStack, Modal, ModalBody, ModalFooter } from '@immich/ui';
import { mdiTune } from '@mdi/js';
import type { DateTime } from 'luxon';
import { t } from 'svelte-i18n';
import { SvelteSet } from 'svelte/reactivity';
@@ -47,8 +48,8 @@
let { searchQuery, onClose }: Props = $props();
const parseOptionalDate = (dateString?: string) => (dateString ? parseUtcDate(dateString) : undefined);
const toStartOfDayDate = (dateString: string) => parseUtcDate(dateString)?.startOf('day').toISODate() || undefined;
const parseOptionalDate = (dateString?: DateTime) => (dateString ? parseUtcDate(dateString.toString()) : undefined);
const toStartOfDayDate = (dateString: string) => parseUtcDate(dateString)?.startOf('day') || undefined;
const formId = generateId();
// combobox and all the search components have terrible support for value | null so we use empty string instead.
@@ -187,7 +188,7 @@
<Modal icon={mdiTune} size="giant" title={$t('search_options')} {onClose}>
<ModalBody>
<form id={formId} autocomplete="off" {onsubmit} {onreset}>
<div class="flex flex-col gap-4 pb-10" tabindex="-1">
<div class="flex flex-col gap-5 pb-10" tabindex="-1">
<!-- PEOPLE -->
<SearchPeopleSection bind:selectedPeople={filter.personIds} />

View File

@@ -446,3 +446,17 @@ export const withoutIcons = (actions: ActionItem[]): ActionItem[] =>
actions.map((action) => ({ ...action, icon: undefined }));
export const isEnabled = ({ $if }: IfLike) => $if?.() ?? true;
export const transformToTitleCase = (text: string) => {
if (text.length === 0) {
return text;
} else if (text.length === 1) {
return text.charAt(0).toUpperCase();
}
let result = '';
for (const word of text.toLowerCase().split(' ')) {
result += word.charAt(0).toUpperCase() + word.slice(1) + ' ';
}
return result.trim();
};

View File

@@ -28,7 +28,7 @@
import { cancelMultiselect } from '$lib/utils/asset-utils';
import { toTimelineAsset } from '$lib/utils/timeline-util';
import { joinPaths } from '$lib/utils/tree-utils';
import { IconButton } from '@immich/ui';
import { IconButton, Text } from '@immich/ui';
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
@@ -77,7 +77,7 @@
<Sidebar>
<SkipLink target={`#${headerId}`} text={$t('skip_to_folders')} breakpoint="md" />
<section>
<div class="uppercase text-xs ps-4 mb-2 dark:text-white">{$t('explorer')}</div>
<Text class="ps-4 mb-4" size="small">{$t('explorer')}</Text>
<div class="h-full">
<TreeItems
icons={{ default: mdiFolderOutline, active: mdiFolder }}

View File

@@ -2,7 +2,6 @@
import { afterNavigate, goto } from '$app/navigation';
import { page } from '$app/state';
import { shortcut } from '$lib/actions/shortcut';
import AlbumCardGroup from '$lib/components/album-page/album-card-group.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
@@ -308,16 +307,6 @@
bind:clientWidth={viewport.width}
bind:this={searchResultsElement}
>
{#if searchResultAlbums.length > 0}
<section>
<div class="uppercase ms-6 text-4xl font-medium text-black/70 dark:text-white/80">{$t('albums')}</div>
<AlbumCardGroup albums={searchResultAlbums} showDateRange showItemCount />
<div class="uppercase m-6 text-4xl font-medium text-black/70 dark:text-white/80">
{$t('photos_and_videos')}
</div>
</section>
{/if}
<section id="search-content">
{#if searchResultAssets.length > 0}
<GalleryViewer

View File

@@ -30,6 +30,7 @@
import { preferences, user } from '$lib/stores/user.store';
import { joinPaths, TreeNode } from '$lib/utils/tree-utils';
import { getAllTags, type TagResponseDto } from '@immich/sdk';
import { Text } from '@immich/ui';
import { mdiDotsVertical, mdiPlus, mdiTag, mdiTagMultiple } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
@@ -82,7 +83,7 @@
<Sidebar>
<SkipLink target={`#${headerId}`} text={$t('skip_to_tags')} breakpoint="md" />
<section>
<div class="uppercase text-xs ps-4 mb-2 dark:text-white">{$t('explorer')}</div>
<Text class="ps-4 mb-4" size="small">{$t('explorer')}</Text>
<div class="h-full">
<TreeItems icons={{ default: mdiTag, active: mdiTag }} {tree} active={tag.path} {getLink} />
</div>

View File

@@ -139,9 +139,9 @@
<UserPageLayout title={data.meta.title} scrollbar={true}>
{#snippet buttons()}
<div class="flex gap-2 justify-end place-items-center">
<Text class="hidden md:block text-xs mr-4 text-dark/50">{$t('geolocation_instruction_location')}</Text>
<Text class="hidden md:block mr-4" size="tiny" color="muted">{$t('geolocation_instruction_location')}</Text>
<div class="border flex place-items-center place-content-center px-2 py-1 bg-primary/10 rounded-2xl">
<Text class="hidden md:inline-block text-xs text-gray-500 font-mono mr-5 ml-2 uppercase">
<Text class="hidden md:inline-block font-mono mr-5 ml-2" color="muted" size="tiny">
{$t('selected_gps_coordinates')}
</Text>
<Text

View File

@@ -208,9 +208,7 @@
<!-- Trigger Section -->
<div class="rounded-2xl border p-4 bg-light-50 border-light-200">
<div class="mb-3">
<Text class="text-xs uppercase tracking-widest" color="muted" fontWeight="semi-bold"
>{$t('trigger')}</Text
>
<Text size="tiny" color="muted" fontWeight="medium">{$t('trigger')}</Text>
</div>
{@render chipItem(getTriggerLabel(workflow.triggerType))}
</div>
@@ -218,9 +216,7 @@
<!-- Filters Section -->
<div class="rounded-2xl border p-4 bg-light-50 border-light-200">
<div class="mb-3">
<Text class="text-xs uppercase tracking-widest" color="muted" fontWeight="semi-bold"
>{$t('filters')}</Text
>
<Text size="tiny" color="muted" fontWeight="medium">{$t('filters')}</Text>
</div>
<div class="flex flex-wrap gap-2">
{#if workflow.filters.length === 0}
@@ -238,9 +234,7 @@
<!-- Actions Section -->
<div class="rounded-2xl border p-4 bg-light-50 border-light-200">
<div class="mb-3">
<Text class="text-xs uppercase tracking-widest" color="muted" fontWeight="semi-bold"
>{$t('actions')}</Text
>
<Text size="tiny" color="muted" fontWeight="medium">{$t('actions')}</Text>
</div>
<div>

View File

@@ -338,7 +338,7 @@
<div class="w-full border-t-2 border-dashed border-light-200"></div>
</div>
<div class="relative flex justify-center text-xs uppercase">
<span class="bg-white dark:bg-black px-2 font-semibold text-light-500">THEN</span>
<Text class="bg-white dark:bg-black px-2" fontWeight="semi-bold" size="tiny" color="muted">{$t('then')}</Text>
</div>
</div>
{/snippet}