mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
@@ -268,9 +268,9 @@
|
||||
</script>
|
||||
|
||||
<svelte:window onresize={onPositionChange} />
|
||||
<Label class="block mb-1 {hideLabel ? 'sr-only' : ''} text-xs text-neutral-500 font-light" for={inputId}>{label}</Label>
|
||||
<Label class="mb-1 block {hideLabel ? 'sr-only' : ''} text-xs font-light text-neutral-500" for={inputId}>{label}</Label>
|
||||
<div
|
||||
class="relative w-full dark:text-gray-300 text-gray-700 text-base"
|
||||
class="relative w-full text-base text-gray-700 dark:text-gray-300"
|
||||
use:focusOutside={{ onFocusOut: deactivate }}
|
||||
use:shortcuts={[
|
||||
{
|
||||
@@ -284,7 +284,7 @@
|
||||
>
|
||||
<div>
|
||||
{#if isActive}
|
||||
<div class="absolute inset-y-0 start-0 flex items-center ps-3">
|
||||
<div class="absolute inset-y-0 inset-s-0 flex items-center ps-3">
|
||||
<div class="dark:text-immich-dark-fg/75">
|
||||
<Icon icon={mdiMagnify} aria-hidden />
|
||||
</div>
|
||||
@@ -300,11 +300,11 @@
|
||||
aria-expanded={isOpen}
|
||||
autocomplete="off"
|
||||
bind:this={input}
|
||||
class:!ps-8={isActive}
|
||||
class:!rounded-b-none={isOpen && dropdownDirection === 'bottom'}
|
||||
class:!rounded-t-none={isOpen && dropdownDirection === 'top'}
|
||||
class:ps-8!={isActive}
|
||||
class:rounded-b-none!={isOpen && dropdownDirection === 'bottom'}
|
||||
class:rounded-t-none!={isOpen && dropdownDirection === 'top'}
|
||||
class:cursor-pointer={!isActive}
|
||||
class="immich-form-input text-sm w-full pe-12! transition-all"
|
||||
class="immich-form-input w-full pe-12! text-sm transition-all"
|
||||
id={inputId}
|
||||
onfocus={activate}
|
||||
oninput={onInput}
|
||||
@@ -355,7 +355,7 @@
|
||||
/>
|
||||
|
||||
<div
|
||||
class="absolute end-0 top-0 h-full flex px-4 justify-center items-center content-between"
|
||||
class="absolute inset-e-0 top-0 flex h-full content-between items-center justify-center px-4"
|
||||
class:pe-2={selectedOption}
|
||||
class:pointer-events-none={!selectedOption}
|
||||
>
|
||||
@@ -379,10 +379,10 @@
|
||||
role="listbox"
|
||||
id={listboxId}
|
||||
in:fly={{ duration: 250 }}
|
||||
class="fixed z-1 text-start text-sm w-full overflow-y-auto bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-900"
|
||||
class="fixed z-1 w-full overflow-y-auto border-gray-300 bg-white text-start text-sm dark:border-gray-900 dark:bg-gray-800"
|
||||
class:rounded-b-xl={dropdownDirection === 'bottom'}
|
||||
class:rounded-t-xl={dropdownDirection === 'top'}
|
||||
class:shadow={dropdownDirection === 'bottom'}
|
||||
class:shadow-sm={dropdownDirection === 'bottom'}
|
||||
class:border={isOpen}
|
||||
style:top={position?.top}
|
||||
style:bottom={position?.bottom}
|
||||
@@ -398,7 +398,7 @@
|
||||
role="option"
|
||||
aria-selected={selectedIndex === 0}
|
||||
aria-disabled={true}
|
||||
class="text-start w-full px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-700 cursor-default aria-selected:bg-gray-200 aria-selected:dark:bg-gray-700"
|
||||
class="w-full cursor-default px-4 py-2 text-start hover:bg-gray-200 aria-selected:bg-gray-200 dark:hover:bg-gray-700 aria-selected:dark:bg-gray-700"
|
||||
id={`${listboxId}-${0}`}
|
||||
onclick={closeDropdown}
|
||||
>
|
||||
@@ -410,7 +410,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 wrap-break-words"
|
||||
class="wrap-break-words w-full cursor-pointer px-4 py-2 text-start transition-all hover:bg-gray-200 aria-selected:bg-gray-200 dark:hover:bg-gray-700 aria-selected:dark:bg-gray-700"
|
||||
id={`${listboxId}-${index}`}
|
||||
onclick={() => handleSelect(option)}
|
||||
role="option"
|
||||
|
||||
@@ -66,12 +66,12 @@
|
||||
!multiRow && 'grid-cols-[10%_80%_10%] sm:grid-cols-[25%_50%_25%]',
|
||||
'justify-between lg:grid-cols-[25%_50%_25%]',
|
||||
appBarBorder,
|
||||
'mx-2 my-2 place-items-center rounded-lg p-2 max-md:p-0 transition-all',
|
||||
'm-2 place-items-center rounded-lg p-2 transition-all max-md:p-0',
|
||||
tailwindClasses,
|
||||
forceDark ? 'bg-immich-dark-gray! text-white' : 'bg-subtle dark:bg-immich-dark-gray',
|
||||
]}
|
||||
>
|
||||
<div class="flex place-items-center sm:gap-6 justify-self-start dark:text-immich-dark-fg {forceDark ? 'dark' : ''}">
|
||||
<div class="flex place-items-center justify-self-start sm:gap-6 dark:text-immich-dark-fg {forceDark ? 'dark' : ''}">
|
||||
{#if showBackButton}
|
||||
<IconButton
|
||||
aria-label={$t('close')}
|
||||
@@ -90,7 +90,7 @@
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
<div class="max-[350px]:me-0 max-[350px]:gap-0 me-4 flex place-items-center gap-1 justify-self-end">
|
||||
<div class="me-4 flex place-items-center gap-1 justify-self-end max-[350px]:me-0 max-[350px]:gap-0">
|
||||
{@render trailing?.()}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<img {src} alt="" width="500" draggable="false" />
|
||||
|
||||
{#if title}
|
||||
<h2 class="text-xl font-medium my-4">{title}</h2>
|
||||
<h2 class="my-4 text-xl font-medium">{title}</h2>
|
||||
{/if}
|
||||
<p class="text-immich-text-gray-500 dark:text-immich-dark-fg font-light text-center">{text}</p>
|
||||
<p class="text-immich-text-gray-500 text-center font-light dark:text-immich-dark-fg">{text}</p>
|
||||
</svelte:element>
|
||||
|
||||
@@ -15,6 +15,6 @@
|
||||
|
||||
<div style="width: {width}px; height: {width}px">
|
||||
{#await promise then url}
|
||||
<img src={url} {alt} class="h-full w-full" />
|
||||
<img src={url} {alt} class="size-full" />
|
||||
{/await}
|
||||
</div>
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
let { label, onRemove }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex group transition-all">
|
||||
<div class="group flex 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-primary rounded-s-full hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all"
|
||||
class="inline-block h-min rounded-s-full bg-primary py-1 ps-3 pe-1 text-center align-baseline leading-none whitespace-nowrap text-gray-100 transition-all group-hover:ps-3 hover:bg-immich-primary/80 dark:text-immich-dark-gray dark:hover:bg-immich-dark-primary/80"
|
||||
>
|
||||
<p class="text-sm">
|
||||
{label}
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="text-gray-100 dark:text-immich-dark-gray bg-immich-primary/95 dark:bg-immich-dark-primary/95 rounded-e-full place-items-center place-content-center pe-2 ps-1 py-1 hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all"
|
||||
class="place-content-center place-items-center rounded-e-full bg-immich-primary/95 py-1 ps-1 pe-2 text-gray-100 transition-all hover:bg-immich-primary/80 dark:bg-immich-dark-primary/95 dark:text-immich-dark-gray dark:hover:bg-immich-dark-primary/80"
|
||||
title={$t('remove_tag')}
|
||||
onclick={onRemove}
|
||||
>
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
</script>
|
||||
|
||||
<figure
|
||||
class="{sizeClass} {colorClass} {interactiveClass} overflow-hidden shadow-md rounded-full"
|
||||
class="{sizeClass} {colorClass} {interactiveClass} overflow-hidden rounded-full shadow-md"
|
||||
title={noTitle ? undefined : title}
|
||||
>
|
||||
{#if user.profileImagePath}
|
||||
@@ -86,14 +86,14 @@
|
||||
bind:this={img}
|
||||
src={getProfileImageUrl(user)}
|
||||
alt={$t('profile_image_of_user', { values: { user: title } })}
|
||||
class="h-full w-full object-cover"
|
||||
class="size-full object-cover"
|
||||
class:hidden={showFallback}
|
||||
draggable="false"
|
||||
/>
|
||||
{/if}
|
||||
{#if showFallback}
|
||||
<span
|
||||
class="uppercase flex h-full w-full select-none items-center justify-center font-medium"
|
||||
class="flex size-full items-center justify-center font-medium uppercase select-none"
|
||||
class:text-xs={size === 'sm'}
|
||||
class:text-lg={size === 'lg'}
|
||||
class:text-xl={size === 'xl'}
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
type="button"
|
||||
onclick={() => onNewAlbum(searchQuery)}
|
||||
use:scrollIntoViewIfSelected
|
||||
class="flex w-full items-center gap-4 px-6 py-2 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl"
|
||||
class="flex w-full items-center gap-4 rounded-xl px-6 py-2 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700"
|
||||
class:bg-gray-200={selected}
|
||||
class:dark:bg-gray-700={selected}
|
||||
>
|
||||
<div class="flex h-12 w-12 items-center justify-center">
|
||||
<div class="flex size-12 items-center justify-center">
|
||||
<Icon icon={mdiPlus} size="30" />
|
||||
</div>
|
||||
<p class="">
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<div
|
||||
bind:this={menuScrollView}
|
||||
class={[
|
||||
'duration-250 ease-in-out fixed min-w-50 w-max max-w-75 rounded-lg shadow-lg bg-slate-100 z-1 immich-scrollbar',
|
||||
'fixed z-1 w-max max-w-75 min-w-50 rounded-lg bg-slate-100 shadow-lg duration-250 ease-in-out immich-scrollbar',
|
||||
position.needScrollBar ? 'overflow-auto' : 'overflow-hidden',
|
||||
]}
|
||||
style:left="{position.left}px"
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
onclick={handleClick}
|
||||
onmouseover={() => ($selectedIdStore = id)}
|
||||
onmouseleave={() => ($selectedIdStore = undefined)}
|
||||
class="w-full p-4 text-start text-sm font-medium {textColor} focus:outline-none focus:ring-2 focus:ring-inset cursor-pointer border-gray-200 flex gap-2 items-center {isActive
|
||||
class="w-full p-4 text-start text-sm font-medium {textColor} flex cursor-pointer items-center gap-2 border-gray-200 focus:ring-2 focus:outline-none focus:ring-inset {isActive
|
||||
? activeColor
|
||||
: 'bg-slate-100'}"
|
||||
role="menuitem"
|
||||
@@ -65,7 +65,7 @@
|
||||
<div class="flex justify-between">
|
||||
{text}
|
||||
{#if shortcutLabel}
|
||||
<span class="text-gray-500 ps-4">
|
||||
<span class="ps-4 text-gray-500">
|
||||
{shortcutLabel}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
},
|
||||
]}
|
||||
>
|
||||
<section class="fixed start-0 top-0 flex h-dvh w-dvw" {oncontextmenu} role="presentation">
|
||||
<section class="fixed inset-s-0 top-0 flex h-dvh w-dvw" {oncontextmenu} role="presentation">
|
||||
<ContextMenu
|
||||
{direction}
|
||||
{x}
|
||||
|
||||
@@ -387,7 +387,7 @@
|
||||
/>
|
||||
{#if showAssetName && !isTimelineAsset(asset)}
|
||||
<div
|
||||
class="absolute text-center p-1 text-xs font-mono font-semibold w-full bottom-0 bg-linear-to-t bg-slate-50/75 dark:bg-slate-800/75 overflow-clip text-ellipsis whitespace-pre-wrap"
|
||||
class="absolute bottom-0 w-full overflow-clip bg-slate-50/75 bg-linear-to-t p-1 text-center font-mono text-xs font-semibold text-ellipsis whitespace-pre-wrap dark:bg-slate-800/75"
|
||||
>
|
||||
{asset.originalFileName}
|
||||
</div>
|
||||
|
||||
@@ -390,7 +390,7 @@
|
||||
>
|
||||
{#snippet children({ feature })}
|
||||
<div
|
||||
class="rounded-full w-10 h-10 bg-immich-primary text-white flex justify-center items-center font-mono font-bold shadow-lg hover:bg-immich-dark-primary transition-all duration-200 hover:text-immich-dark-bg opacity-90"
|
||||
class="flex size-10 items-center justify-center rounded-full bg-immich-primary font-mono font-bold text-white opacity-90 shadow-lg transition-all duration-200 hover:bg-immich-dark-primary hover:text-immich-dark-bg"
|
||||
>
|
||||
{feature.properties?.point_count?.toLocaleString()}
|
||||
</div>
|
||||
@@ -407,11 +407,11 @@
|
||||
>
|
||||
{#snippet children({ feature }: { feature: Feature })}
|
||||
{#if useLocationPin}
|
||||
<Icon icon={mdiMapMarker} size="50px" class="text-primary -translate-y-[50%]" />
|
||||
<Icon icon={mdiMapMarker} size="50px" class="translate-y-[-50%] text-primary" />
|
||||
{:else}
|
||||
<img
|
||||
src={getAssetMediaUrl({ id: feature.properties?.id })}
|
||||
class="rounded-full w-15 h-15 border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-cover bg-immich-primary"
|
||||
class="size-15 rounded-full border-2 border-immich-primary bg-immich-primary object-cover shadow-lg transition-all duration-200 hover:scale-150 hover:border-immich-dark-primary"
|
||||
alt={feature.properties?.city && feature.properties.country
|
||||
? $t('map_marker_for_images', {
|
||||
values: { city: feature.properties.city, country: feature.properties.country },
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
in:fade={{ duration: 100 }}
|
||||
out:fade={{ duration: 100 }}
|
||||
id="account-info-panel"
|
||||
class="absolute z-1 end-6 top-19 w-[min(360px,100vw-50px)] rounded-3xl bg-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray"
|
||||
class="absolute inset-e-6 top-19 z-1 w-[min(360px,100vw-50px)] rounded-3xl bg-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray"
|
||||
use:focusTrap
|
||||
>
|
||||
<div
|
||||
@@ -39,7 +39,7 @@
|
||||
>
|
||||
<div class="relative">
|
||||
<UserAvatar user={authManager.user} size="xl" />
|
||||
<div class="absolute bottom-0 end-0 rounded-full w-6 h-6">
|
||||
<div class="absolute inset-e-0 bottom-0 size-6 rounded-full">
|
||||
<IconButton
|
||||
color="primary"
|
||||
icon={mdiPencil}
|
||||
@@ -68,9 +68,9 @@
|
||||
color="secondary"
|
||||
variant="ghost"
|
||||
shape="round"
|
||||
class="border dark:border-immich-dark-gray dark:bg-gray-500 dark:hover:bg-immich-dark-primary/50 hover:bg-immich-primary/10 dark:text-white"
|
||||
class="border hover:bg-immich-primary/10 dark:border-immich-dark-gray dark:bg-gray-500 dark:text-white dark:hover:bg-immich-dark-primary/50"
|
||||
>
|
||||
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
|
||||
<div class="flex place-content-center place-items-center gap-2 px-2 text-center">
|
||||
<Icon icon={mdiCog} size="18" aria-hidden />
|
||||
{$t('account_settings')}
|
||||
</div>
|
||||
@@ -84,9 +84,9 @@
|
||||
size="small"
|
||||
color="secondary"
|
||||
aria-current={page.url.pathname.includes('/admin') ? 'page' : undefined}
|
||||
class="border dark:border-immich-dark-gray dark:bg-gray-500 dark:hover:bg-immich-dark-primary/50 hover:bg-immich-primary/10 dark:text-white"
|
||||
class="border hover:bg-immich-primary/10 dark:border-immich-dark-gray dark:bg-gray-500 dark:text-white dark:hover:bg-immich-dark-primary/50"
|
||||
>
|
||||
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
|
||||
<div class="flex place-content-center place-items-center gap-2 px-2 text-center">
|
||||
<Icon icon={mdiWrench} size="18" aria-hidden />
|
||||
{$t('administration')}
|
||||
</div>
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="text-center mt-4 underline text-xs text-primary"
|
||||
class="mt-4 text-center text-xs text-primary underline"
|
||||
onclick={async () => {
|
||||
onClose?.();
|
||||
if (info) {
|
||||
|
||||
@@ -49,14 +49,14 @@
|
||||
|
||||
<svelte:window bind:innerWidth />
|
||||
|
||||
<nav id="dashboard-navbar" class="max-md:h-(--navbar-height-md) h-(--navbar-height) w-dvw text-sm">
|
||||
<nav id="dashboard-navbar" class="h-(--navbar-height) w-dvw text-sm max-md:h-(--navbar-height-md)">
|
||||
<SkipLink text={$t('skip_to_content')} />
|
||||
<div
|
||||
class="grid h-full grid-cols-[--spacing(32)_auto] items-center py-2 sidebar:grid-cols-[--spacing(64)_auto] {noBorder
|
||||
? ''
|
||||
: 'border-b'}"
|
||||
>
|
||||
<div class="flex flex-row gap-1 mx-4 items-center">
|
||||
<div class="mx-4 flex flex-row items-center gap-1">
|
||||
<IconButton
|
||||
id={menuButtonId}
|
||||
shape="round"
|
||||
@@ -80,14 +80,14 @@
|
||||
<Logo variant={mediaQueryManager.isFullSidebar ? 'inline' : 'icon'} class="max-md:h-12" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex justify-between gap-4 lg:gap-8 pe-6">
|
||||
<div class="hidden w-full max-w-5xl flex-1 tall:ps-0 sm:block">
|
||||
<div class="flex justify-between gap-4 pe-6 lg:gap-8">
|
||||
<div class="hidden w-full max-w-5xl flex-1 sm:block tall:ps-0">
|
||||
{#if featureFlagsManager.value.search}
|
||||
<SearchBar grayTheme={true} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<section class="flex place-items-center justify-end gap-1 md:gap-2 w-full sm:w-auto">
|
||||
<section class="flex w-full place-items-center justify-end gap-1 sm:w-auto md:gap-2">
|
||||
{#if featureFlagsManager.value.search}
|
||||
<IconButton
|
||||
color="secondary"
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
{#if hasUnreadNotifications}
|
||||
<div
|
||||
class="pointer-events-none absolute border top-0 right-1 flex h-5 w-5 items-center justify-center rounded-full bg-primary text-[10px] font-bold text-light"
|
||||
class="pointer-events-none absolute top-0 right-1 flex size-5 items-center justify-center rounded-full border bg-primary text-[10px] font-bold text-light"
|
||||
>
|
||||
{notificationManager.notifications.length}
|
||||
</div>
|
||||
|
||||
@@ -100,13 +100,13 @@
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="min-h-20 p-2 py-3 hover:bg-immich-primary/10 dark:hover:bg-immich-dark-primary/10 border-b border-gray-200 dark:border-immich-dark-gray w-full"
|
||||
class="min-h-20 w-full border-b border-gray-200 p-2 py-3 hover:bg-immich-primary/10 dark:border-immich-dark-gray dark:hover:bg-immich-dark-primary/10"
|
||||
type="button"
|
||||
onclick={() => onclick(notification)}
|
||||
title={notification.createdAt}
|
||||
>
|
||||
<div class="grid grid-cols-[56px_1fr_32px] items-center gap-2">
|
||||
<div class="flex place-items-center place-content-center">
|
||||
<div class="flex place-content-center place-items-center">
|
||||
<IconButton
|
||||
icon={getIconType(notification.type)}
|
||||
color={getAlertColor(notification.level)}
|
||||
@@ -118,7 +118,7 @@
|
||||
</div>
|
||||
|
||||
<Stack class="text-left" gap={1}>
|
||||
<Text size="tiny" class="text-black dark:text-white text-base" fontWeight="semi-bold">{notification.title}</Text>
|
||||
<Text size="tiny" class="text-base text-black dark:text-white" fontWeight="semi-bold">{notification.title}</Text>
|
||||
{#if notification.description}
|
||||
<Text class="overflow-hidden text-gray-600 dark:text-gray-300">{notification.description}</Text>
|
||||
{/if}
|
||||
@@ -127,7 +127,7 @@
|
||||
</Stack>
|
||||
|
||||
{#if !notification.readAt}
|
||||
<div class="w-2 h-2 rounded-full bg-primary text-right justify-self-center"></div>
|
||||
<div class="size-2 justify-self-center rounded-full bg-primary text-right"></div>
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -66,11 +66,11 @@
|
||||
in:fade={{ duration: 100 }}
|
||||
out:fade={{ duration: 100 }}
|
||||
id="notification-panel"
|
||||
class="absolute right-6 top-17.5 z-1 w-[min(360px,100vw-50px)] rounded-3xl bg-gray-100 border border-gray-200 shadow-lg dark:border dark:border-light dark:bg-immich-dark-gray text-light"
|
||||
class="absolute top-17.5 right-6 z-1 w-[min(360px,100vw-50px)] rounded-3xl border border-gray-200 bg-gray-100 text-light shadow-lg dark:border dark:border-light dark:bg-immich-dark-gray"
|
||||
use:focusTrap
|
||||
>
|
||||
<Stack class="max-h-125">
|
||||
<div class="flex justify-between items-center mt-4 mx-4">
|
||||
<div class="mx-4 mt-4 flex items-center justify-between">
|
||||
<Text size="medium" color="secondary" fontWeight="semi-bold">{$t('notifications')}</Text>
|
||||
<div>
|
||||
<Button
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
{#if noUnreadNotifications}
|
||||
<Stack
|
||||
class="py-12 flex flex-col place-items-center place-content-center text-gray-700 dark:text-gray-300"
|
||||
class="flex flex-col place-content-center place-items-center py-12 text-gray-700 dark:text-gray-300"
|
||||
gap={1}
|
||||
>
|
||||
<Icon icon={mdiBellOutline} size="20"></Icon>
|
||||
|
||||
@@ -91,5 +91,5 @@
|
||||
</script>
|
||||
|
||||
{#if !hidden}
|
||||
<span class="absolute start-0 h-[3px] bg-immich-primary shadow-2xl" style:width={`${$progress * 100}%`}></span>
|
||||
<span class="absolute inset-s-0 h-[3px] bg-immich-primary shadow-2xl" style:width={`${$progress * 100}%`}></span>
|
||||
{/if}
|
||||
|
||||
+6
-6
@@ -8,11 +8,11 @@
|
||||
|
||||
<!-- Individual Purchase Option -->
|
||||
<div
|
||||
class="border border-gray-300 dark:border-gray-800 w-[min(375px,100%)] p-8 rounded-3xl bg-gray-100 dark:bg-gray-900"
|
||||
class="w-[min(375px,100%)] rounded-3xl border border-gray-300 bg-gray-100 p-8 dark:border-gray-800 dark:bg-gray-900"
|
||||
>
|
||||
<div class="text-primary">
|
||||
<Icon icon={mdiAccount} size="56" />
|
||||
<p class="font-semibold text-lg mt-1">{$t('purchase_individual_title')}</p>
|
||||
<p class="mt-1 text-lg font-semibold">{$t('purchase_individual_title')}</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 dark:text-immich-gray">
|
||||
@@ -20,20 +20,20 @@
|
||||
<p>{$t('purchase_per_user')}</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col justify-between h-50 dark:text-immich-gray">
|
||||
<div class="flex h-50 flex-col justify-between dark:text-immich-gray">
|
||||
<div class="mt-6 flex flex-col gap-1">
|
||||
<div class="grid grid-cols-[36px_auto]">
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="text-green-500 self-center" />
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="self-center text-green-500" />
|
||||
<p class="self-center">{$t('purchase_individual_description_1')}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-[36px_auto]">
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="text-green-500 self-center" />
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="self-center text-green-500" />
|
||||
<p class="self-center">{$t('purchase_lifetime_description')}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-[36px_auto]">
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="text-green-500 self-center" />
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="self-center text-green-500" />
|
||||
<p class="self-center">{$t('purchase_individual_description_2')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+4
-4
@@ -13,12 +13,12 @@
|
||||
let { onDone }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="m-auto w-3/4 text-center flex flex-col place-content-center place-items-center my-6">
|
||||
<div class="m-auto my-6 flex w-3/4 flex-col place-content-center place-items-center text-center">
|
||||
<Icon icon={mdiPartyPopper} class="text-primary" size="96" />
|
||||
<p class="text-4xl mt-8 font-bold">{$t('purchase_activated_title')}</p>
|
||||
<p class="text-lg mt-6">{$t('purchase_activated_subtitle')}</p>
|
||||
<p class="mt-8 text-4xl font-bold">{$t('purchase_activated_title')}</p>
|
||||
<p class="mt-6 text-lg">{$t('purchase_activated_subtitle')}</p>
|
||||
|
||||
<div class="mb-4 w-full mt-6 border rounded-xl p-4 bg-gray-50 dark:bg-gray-900 dark:border-gray-600">
|
||||
<div class="mt-6 mb-4 w-full rounded-xl border bg-gray-50 p-4 dark:border-gray-600 dark:bg-gray-900">
|
||||
<SettingSwitch
|
||||
title={$t('show_supporter_badge')}
|
||||
subtitle={$t('show_supporter_badge_description')}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-6 mt-4 justify-between">
|
||||
<div class="mt-4 flex flex-col justify-between gap-6 sm:flex-row">
|
||||
<ServerPurchaseOptionCard />
|
||||
<UserPurchaseOptionCard />
|
||||
</div>
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
<!-- SERVER Purchase Options -->
|
||||
<div
|
||||
class="border border-gray-300 dark:border-gray-800 w-[min(375px,100%)] p-8 rounded-3xl bg-gray-100 dark:bg-gray-900"
|
||||
class="w-[min(375px,100%)] rounded-3xl border border-gray-300 bg-gray-100 p-8 dark:border-gray-800 dark:bg-gray-900"
|
||||
>
|
||||
<div class="text-primary">
|
||||
<Icon icon={mdiServer} size="56" />
|
||||
<p class="font-semibold text-lg mt-1">{$t('purchase_server_title')}</p>
|
||||
<p class="mt-1 text-lg font-semibold">{$t('purchase_server_title')}</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 dark:text-immich-gray">
|
||||
@@ -20,20 +20,20 @@
|
||||
<p>{$t('purchase_per_server')}</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col justify-between h-50 dark:text-immich-gray">
|
||||
<div class="flex h-50 flex-col justify-between dark:text-immich-gray">
|
||||
<div class="mt-6 flex flex-col gap-1">
|
||||
<div class="grid grid-cols-[36px_auto]">
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="text-green-500 self-center" />
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="self-center text-green-500" />
|
||||
<p class="self-center">{$t('purchase_server_description_1')}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-[36px_auto]">
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="text-green-500 self-center" />
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="self-center text-green-500" />
|
||||
<p class="self-center">{$t('purchase_lifetime_description')}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-[36px_auto]">
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="text-green-500 self-center" />
|
||||
<Icon icon={mdiCheckCircleOutline} size="24" class="self-center text-green-500" />
|
||||
<p class="self-center">{$t('purchase_server_description_2')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -248,11 +248,11 @@
|
||||
]}
|
||||
/>
|
||||
|
||||
<div class="w-full relative z-auto" use:focusOutside={{ onFocusOut }} tabindex="-1">
|
||||
<div class="relative z-auto w-full" use:focusOutside={{ onFocusOut }} tabindex="-1">
|
||||
<form
|
||||
draggable="false"
|
||||
autocomplete="off"
|
||||
class="select-text text-sm"
|
||||
class="text-sm select-text"
|
||||
action={Route.search()}
|
||||
onreset={() => (value = '')}
|
||||
{onsubmit}
|
||||
@@ -265,11 +265,11 @@
|
||||
type="text"
|
||||
name="q"
|
||||
id="main-search-bar"
|
||||
class="w-full transition-all border-2 ps-14 py-4 max-md:py-2 text-immich-fg/75 dark:text-immich-dark-fg
|
||||
class="w-full border-2 py-4 ps-14 text-immich-fg/75 transition-all max-md:py-2 dark:text-immich-dark-fg
|
||||
{showClearIcon ? 'pe-22.5' : 'pe-14'}
|
||||
{grayTheme ? 'dark:bg-immich-dark-gray' : 'dark:bg-immich-dark-bg'}
|
||||
{showSuggestions && isSearchSuggestions ? 'rounded-t-3xl' : 'rounded-3xl bg-gray-200'}
|
||||
{searchStore.isSearchEnabled ? 'border-gray-200 dark:border-gray-700 bg-white' : 'border-transparent'}"
|
||||
{searchStore.isSearchEnabled ? 'border-gray-200 bg-white dark:border-gray-700' : 'border-transparent'}"
|
||||
placeholder={$t('search_your_photos')}
|
||||
required
|
||||
pattern="^(?!m:$).*$"
|
||||
@@ -309,9 +309,9 @@
|
||||
|
||||
<div
|
||||
id={searchTypeId}
|
||||
class="absolute inset-y-0 flex items-center end-16"
|
||||
class="absolute inset-y-0 inset-e-16 flex items-center"
|
||||
class:max-md:hidden={value}
|
||||
class:end-28={value.length > 0}
|
||||
class:inset-e-28={value.length > 0}
|
||||
>
|
||||
<div class="relative" use:focusOutside={{ onFocusOut: closeSearchTypeDropdown }}>
|
||||
<Button
|
||||
@@ -320,7 +320,7 @@
|
||||
color={searchStore.isSearchEnabled ? 'primary' : 'secondary'}
|
||||
class="px-3 py-1 text-xs {searchStore.isSearchEnabled
|
||||
? 'border border-transparent'
|
||||
: 'border border-secondary/5 text-muted hover:text-dark font-light'}"
|
||||
: 'border-secondary/5 border font-light text-muted hover:text-dark'}"
|
||||
onclick={toggleSearchTypeDropdown}
|
||||
aria-expanded={showSearchTypeDropdown}
|
||||
aria-haspopup="listbox"
|
||||
@@ -330,13 +330,13 @@
|
||||
|
||||
{#if showSearchTypeDropdown}
|
||||
<div
|
||||
class="absolute top-full right-0 mt-1 bg-white dark:bg-immich-dark-gray border border-gray-200 dark:border-gray-600 rounded-lg shadow-lg py-1 min-w-32 z-9999"
|
||||
class="absolute top-full right-0 z-9999 mt-1 min-w-32 rounded-lg border border-gray-200 bg-white py-1 shadow-lg dark:border-gray-600 dark:bg-immich-dark-gray"
|
||||
>
|
||||
{#each searchTypes as searchType (searchType.value)}
|
||||
<button
|
||||
type="button"
|
||||
tabindex="0"
|
||||
class="w-full text-left px-3 py-2 text-xs hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors
|
||||
class="w-full px-3 py-2 text-left text-xs transition-colors hover:bg-gray-100 dark:hover:bg-gray-700
|
||||
{currentSearchType === searchType.value ? 'bg-gray-100 dark:bg-gray-700' : ''}"
|
||||
onclick={() => selectSearchType(searchType.value)}
|
||||
>
|
||||
@@ -349,7 +349,7 @@
|
||||
</div>
|
||||
|
||||
{#if showClearIcon}
|
||||
<div class="absolute inset-y-0 end-0 flex items-center pe-2">
|
||||
<div class="absolute inset-y-0 inset-e-0 flex items-center pe-2">
|
||||
<IconButton
|
||||
onclick={onClear}
|
||||
icon={mdiClose}
|
||||
@@ -361,7 +361,7 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="absolute inset-y-0 start-0 flex items-center ps-2">
|
||||
<div class="absolute inset-y-0 inset-s-0 flex items-center ps-2">
|
||||
<IconButton
|
||||
type="submit"
|
||||
aria-label={$t('search')}
|
||||
@@ -375,7 +375,7 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="absolute inset-y-0 {showClearIcon ? 'end-14' : 'end-2'} flex items-center ps-6 transition-all">
|
||||
<div class="absolute inset-y-0 {showClearIcon ? 'inset-e-14' : 'inset-e-2'} flex items-center ps-6 transition-all">
|
||||
<IconButton
|
||||
aria-label={$t('show_search_options')}
|
||||
shape="round"
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
<div id="camera-selection">
|
||||
<Text fontWeight="medium">{$t('camera')}</Text>
|
||||
<div class="grid grid-auto-fit-40 gap-5 mt-1">
|
||||
<div class="mt-1 grid grid-auto-fit-40 gap-5">
|
||||
<div class="w-full">
|
||||
<Combobox
|
||||
label={$t('make')}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<fieldset>
|
||||
<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="mt-1 flex flex-wrap gap-x-5 gap-y-2">
|
||||
<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" class="text-sm font-normal" />
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
{#if isOpen && isSearchSuggestions}
|
||||
<div
|
||||
transition:fly={{ y: 25, duration: 150 }}
|
||||
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"
|
||||
class="absolute z-1 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"
|
||||
>
|
||||
<div class="flex items-center justify-between px-5 pt-5 text-xs">
|
||||
<Text class="py-2" color="muted" aria-hidden={true}>{$t('recent_searches')}</Text>
|
||||
@@ -102,7 +102,7 @@
|
||||
<button
|
||||
id={getId(0)}
|
||||
type="button"
|
||||
class="rounded-lg p-2 font-semibold text-primary aria-selected:bg-immich-primary/25 hover:bg-immich-primary/25"
|
||||
class="rounded-lg p-2 font-semibold text-primary hover:bg-immich-primary/25 aria-selected:bg-immich-primary/25"
|
||||
role="option"
|
||||
onclick={() => handleClearAll()}
|
||||
tabindex="-1"
|
||||
@@ -121,7 +121,7 @@
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<div
|
||||
id={getId(index)}
|
||||
class="relative flex w-full cursor-pointer gap-3 py-3 ps-5 hover:bg-gray-100 aria-selected:bg-gray-100 dark:aria-selected:bg-gray-500/30 dark:hover:bg-gray-500/30"
|
||||
class="relative flex w-full cursor-pointer gap-3 py-3 ps-5 hover:bg-gray-100 aria-selected:bg-gray-100 dark:hover:bg-gray-500/30 dark:aria-selected:bg-gray-500/30"
|
||||
onclick={() => handleSelect(savedSearchTerm)}
|
||||
role="option"
|
||||
tabindex="-1"
|
||||
@@ -131,7 +131,7 @@
|
||||
<Icon icon={mdiMagnify} size="1.5em" aria-hidden />
|
||||
{savedSearchTerm}
|
||||
</div>
|
||||
<div aria-hidden={true} class="absolute end-5 top-0 items-center justify-center py-3">
|
||||
<div aria-hidden={true} class="absolute inset-e-5 top-0 items-center justify-center py-3">
|
||||
<IconButton
|
||||
shape="round"
|
||||
color="secondary"
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<div id="location-selection">
|
||||
<Text fontWeight="medium">{$t('place')}</Text>
|
||||
|
||||
<div class="grid grid-auto-fit-40 gap-5 mt-1">
|
||||
<div class="mt-1 grid grid-auto-fit-40 gap-5">
|
||||
<div class="w-full">
|
||||
<Combobox
|
||||
label={$t('country')}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<fieldset>
|
||||
<Text class="mb-2" fontWeight="medium">{$t('media_type')}</Text>
|
||||
|
||||
<div class="flex flex-wrap gap-x-5 gap-y-2 mt-1">
|
||||
<div class="mt-1 flex flex-wrap gap-x-5 gap-y-2">
|
||||
<RadioButton name="media-type" id="type-all" bind:group={filteredMedia} label={$t('all')} value={MediaType.All} />
|
||||
<RadioButton
|
||||
name="media-type"
|
||||
|
||||
@@ -52,10 +52,10 @@
|
||||
};
|
||||
|
||||
const styles = tv({
|
||||
base: 'flex flex-col items-center rounded-3xl border-2 hover:bg-subtle dark:hover:bg-immich-dark-primary/20 p-2 transition-all',
|
||||
base: 'flex flex-col items-center rounded-3xl border-2 p-2 transition-all hover:bg-subtle dark:hover:bg-immich-dark-primary/20',
|
||||
variants: {
|
||||
selected: {
|
||||
true: 'dark:border-slate-500 border-slate-400 bg-slate-200 dark:bg-slate-800 dark:text-white',
|
||||
true: 'border-slate-400 bg-slate-200 dark:border-slate-500 dark:bg-slate-800 dark:text-white',
|
||||
false: 'border-transparent',
|
||||
},
|
||||
},
|
||||
@@ -63,7 +63,7 @@
|
||||
</script>
|
||||
|
||||
{#await peoplePromise}
|
||||
<div id="spinner" class="flex h-54 items-center justify-center -mb-4">
|
||||
<div id="spinner" class="-mb-4 flex h-54 items-center justify-center">
|
||||
<LoadingSpinner size="large" />
|
||||
</div>
|
||||
{:then people}
|
||||
@@ -72,14 +72,14 @@
|
||||
? filterPeople(people, name)
|
||||
: filterPeople(people, name).slice(0, numberOfPeople)}
|
||||
|
||||
<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">
|
||||
<div id="people-selection" class="-mb-4 max-h-60 overflow-y-auto immich-scrollbar">
|
||||
<div class="flex w-full items-center justify-between gap-6">
|
||||
<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 space-between"
|
||||
class="space-between mt-2 grid grid-auto-fill-20 gap-1 overflow-y-auto immich-scrollbar"
|
||||
bind:itemCount={numberOfPeople}
|
||||
>
|
||||
{#each peopleList as person (person.id)}
|
||||
@@ -95,13 +95,13 @@
|
||||
</SingleGridRow>
|
||||
|
||||
{#if showAllPeople || people.length > peopleList.length}
|
||||
<div class="flex justify-center mt-2">
|
||||
<div class="mt-2 flex justify-center">
|
||||
<Button
|
||||
color="primary"
|
||||
variant="ghost"
|
||||
shape="round"
|
||||
leadingIcon={showAllPeople ? mdiClose : mdiArrowRight}
|
||||
class="flex gap-2 place-items-center"
|
||||
class="flex place-items-center gap-2"
|
||||
onclick={() => (showAllPeople = !showAllPeople)}
|
||||
>
|
||||
{showAllPeople ? $t('collapse') : $t('see_all_people')}
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<section class="flex flex-wrap pt-2 gap-1">
|
||||
<section class="flex flex-wrap gap-1 pt-2">
|
||||
{#each selectedTags ?? [] as tagId (tagId)}
|
||||
{@const tag = tagMap[tagId]}
|
||||
{#if tag}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<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">
|
||||
<div class="my-2 flex flex-wrap gap-x-5 gap-y-2">
|
||||
{#if featureFlagsManager.value.smartSearch}
|
||||
<RadioButton name="query-type" id="context-radio" label={$t('context')} bind:group={queryType} value="smart" />
|
||||
{/if}
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="border-2 rounded-2xl border-primary/20 mt-4 px-6 py-4 transition-all {isOpen
|
||||
class="mt-4 rounded-2xl border-2 border-primary/20 px-6 py-4 transition-all {isOpen
|
||||
? 'border-primary/60 shadow-md'
|
||||
: ''}"
|
||||
bind:this={accordionElement}
|
||||
@@ -76,7 +76,7 @@
|
||||
class="flex w-full place-items-center justify-between text-start"
|
||||
>
|
||||
<div>
|
||||
<div class="flex gap-2 place-items-center">
|
||||
<div class="flex place-items-center gap-2">
|
||||
{#if icon}
|
||||
<Icon {icon} class="text-primary" size="24" aria-hidden />
|
||||
{/if}
|
||||
@@ -86,7 +86,7 @@
|
||||
</div>
|
||||
|
||||
{#if subtitleSnippet}{@render subtitleSnippet()}{:else}
|
||||
<p class="text-sm dark:text-immich-dark-fg mt-1">{subtitle}</p>
|
||||
<p class="mt-1 text-sm dark:text-immich-dark-fg">{subtitle}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
</button>
|
||||
|
||||
{#if isOpen}
|
||||
<ul transition:slide={{ duration: 150 }} class="mb-2 ms-4">
|
||||
<ul transition:slide={{ duration: 150 }} class="ms-4 mb-2">
|
||||
{@render children?.()}
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<div class="flex place-items-center justify-between">
|
||||
<div>
|
||||
<div class="flex h-6.5 place-items-center gap-1">
|
||||
<label class="font-medium text-sm" for={title}>
|
||||
<label class="text-sm font-medium" for={title}>
|
||||
{title}
|
||||
</label>
|
||||
{#if isEdited}
|
||||
|
||||
@@ -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" for={label}>{label}</label>
|
||||
<label class="min-h-6 text-sm font-medium text-primary" for={label}>{label}</label>
|
||||
{#if required}
|
||||
<div class="text-red-400">*</div>
|
||||
{/if}
|
||||
@@ -97,7 +97,7 @@
|
||||
</div>
|
||||
|
||||
{#if description}
|
||||
<p class="immich-form-label pb-2 text-sm" id="{label}-desc">
|
||||
<p class="pb-2 text-sm immich-form-label" id="{label}-desc">
|
||||
{description}
|
||||
</p>
|
||||
{:else}
|
||||
@@ -105,11 +105,11 @@
|
||||
{/if}
|
||||
|
||||
{#if inputType !== SettingInputFieldType.PASSWORD}
|
||||
<div class="flex place-items-center place-content-center gap-2">
|
||||
<div class="flex place-content-center place-items-center gap-2">
|
||||
{#if inputType === SettingInputFieldType.COLOR}
|
||||
<input
|
||||
bind:this={input}
|
||||
class="immich-form-input w-full pb-2 rounded-none me-1"
|
||||
class="me-1 immich-form-input w-full rounded-none pb-2"
|
||||
aria-describedby={description ? `${label}-desc` : undefined}
|
||||
aria-labelledby="{label}-label"
|
||||
id={label}
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
<input
|
||||
bind:this={input}
|
||||
class="immich-form-input w-full pb-2 min-w-[50px]"
|
||||
class="immich-form-input w-full min-w-[50px] pb-2"
|
||||
class:color-picker={inputType === SettingInputFieldType.COLOR}
|
||||
aria-describedby={description ? `${label}-desc` : undefined}
|
||||
aria-labelledby="{label}-label"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="flex place-items-center justify-between">
|
||||
<div class="me-2">
|
||||
<div class="flex h-6.5 place-items-center gap-1">
|
||||
<label class="font-medium text-primary text-sm" for={switchId}>
|
||||
<label class="text-sm font-medium text-primary" for={switchId}>
|
||||
{title}
|
||||
</label>
|
||||
{#if isEdited}
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
|
||||
<PurchaseInfo />
|
||||
|
||||
<div class="mb-6 mt-2">
|
||||
<div class="mt-2 mb-6">
|
||||
<ServerStatus />
|
||||
</div>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
{#if authManager.isPurchased && authManager.preferences.purchase.showSupportBadge}
|
||||
<button
|
||||
onclick={() => goto(Route.userSettings({ isOpen: OpenQueryParam.PURCHASE_SETTINGS }))}
|
||||
class="w-full mt-2"
|
||||
class="mt-2 w-full"
|
||||
type="button"
|
||||
>
|
||||
<SupporterBadge size="small" effect="always" />
|
||||
@@ -86,18 +86,18 @@
|
||||
onmouseleave={() => (hoverButton = false)}
|
||||
onfocus={onButtonHover}
|
||||
onblur={() => (hoverButton = false)}
|
||||
class="p-2 flex justify-between place-items-center place-content-center border border-immich-primary/20 dark:border-immich-dark-primary/10 mt-2 rounded-lg shadow-md dark:bg-immich-dark-primary/10 min-w-52 w-full"
|
||||
class="mt-2 flex w-full min-w-52 place-content-center place-items-center justify-between rounded-lg border border-immich-primary/20 p-2 shadow-md dark:border-immich-dark-primary/10 dark:bg-immich-dark-primary/10"
|
||||
>
|
||||
<div class="flex justify-between w-full place-items-center place-content-center">
|
||||
<div class="flex place-items-center place-content-center gap-1">
|
||||
<div class="flex w-full place-content-center place-items-center justify-between">
|
||||
<div class="flex place-content-center place-items-center gap-1">
|
||||
<Logo variant="icon" size="tiny" />
|
||||
<p class="flex text-primary font-medium">
|
||||
<p class="flex font-medium text-primary">
|
||||
{$t('purchase_button_buy_immich')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Icon icon={mdiInformationOutline} class="hidden sidebar:flex text-primary font-medium" size="18" />
|
||||
<Icon icon={mdiInformationOutline} class="hidden font-medium text-primary sidebar:flex" size="18" />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
@@ -108,15 +108,15 @@
|
||||
{#if showMessage}
|
||||
<dialog
|
||||
open
|
||||
class="hidden sidebar:block w-125 absolute bottom-19 start-64 bg-gray-50 dark:border-gray-800 border border-gray-200 dark:bg-immich-dark-gray dark:text-white text-black rounded-3xl shadow-2xl px-8 py-6"
|
||||
class="absolute inset-s-64 bottom-19 hidden w-125 rounded-3xl border border-gray-200 bg-gray-50 px-8 py-6 text-black shadow-2xl sidebar:block dark:border-gray-800 dark:bg-immich-dark-gray dark:text-white"
|
||||
transition:fade={{ duration: 150 }}
|
||||
onmouseover={() => (hoverMessage = true)}
|
||||
onmouseleave={() => (hoverMessage = false)}
|
||||
onfocus={() => (hoverMessage = true)}
|
||||
onblur={() => (hoverMessage = false)}
|
||||
>
|
||||
<div class="flex justify-between place-items-center">
|
||||
<div class="h-10 w-10">
|
||||
<div class="flex place-items-center justify-between">
|
||||
<div class="size-10">
|
||||
<Logo variant="icon" size="small" />
|
||||
</div>
|
||||
<IconButton
|
||||
@@ -133,11 +133,11 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h1 class="text-lg font-medium my-3 text-primary">
|
||||
<h1 class="my-3 text-lg font-medium text-primary">
|
||||
{$t('purchase_panel_title')}
|
||||
</h1>
|
||||
|
||||
<div class="text-gray-800 dark:text-white my-4">
|
||||
<div class="my-4 text-gray-800 dark:text-white">
|
||||
<p>
|
||||
{$t('purchase_panel_info_1')}
|
||||
</p>
|
||||
|
||||
@@ -29,17 +29,17 @@
|
||||
<a
|
||||
href={Route.viewAlbum(album)}
|
||||
title={album.albumName}
|
||||
class="flex w-full place-items-center justify-between gap-4 rounded-e-full py-3 transition-[padding] delay-100 duration-100 hover:cursor-pointer hover:bg-subtle hover:text-immich-primary dark:text-immich-dark-fg dark:hover:bg-immich-dark-gray dark:hover:text-immich-dark-primary ps-10 group-hover:sm:px-10 md:px-10"
|
||||
class="flex w-full place-items-center justify-between gap-4 rounded-e-full py-3 ps-10 transition-[padding] delay-100 duration-100 hover:cursor-pointer hover:bg-subtle hover:text-immich-primary group-hover:sm:px-10 md:px-10 dark:text-immich-dark-fg dark:hover:bg-immich-dark-gray dark:hover:text-immich-dark-primary"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="h-6 w-6 bg-cover rounded bg-gray-200 dark:bg-gray-600"
|
||||
class="size-6 rounded-sm bg-gray-200 bg-cover dark:bg-gray-600"
|
||||
style={album.albumThumbnailAssetId
|
||||
? `background-image:url('${getAssetMediaUrl({ id: album.albumThumbnailAssetId })}')`
|
||||
: ''}
|
||||
></div>
|
||||
</div>
|
||||
<div class="grow text-sm font-medium truncate">
|
||||
<div class="grow truncate text-sm font-medium">
|
||||
{album.albumName}
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -58,16 +58,16 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="text-sm flex md:flex ps-5 pe-1 place-items-center place-content-center justify-between min-w-52 overflow-hidden dark:text-immich-dark-fg"
|
||||
class="flex min-w-52 place-content-center place-items-center justify-between overflow-hidden ps-5 pe-1 text-sm md:flex dark:text-immich-dark-fg"
|
||||
>
|
||||
{#if $connected}
|
||||
<div class="flex gap-2 place-items-center place-content-center">
|
||||
<div class="w-1.75 h-1.75 bg-green-500 rounded-full"></div>
|
||||
<div class="flex place-content-center place-items-center gap-2">
|
||||
<div class="size-1.75 rounded-full bg-green-500"></div>
|
||||
<p class="dark:text-immich-gray">{$t('server_online')}</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex gap-2 place-items-center place-content-center">
|
||||
<div class="w-1.75 h-1.75 bg-red-500 rounded-full"></div>
|
||||
<div class="flex place-content-center place-items-center gap-2">
|
||||
<div class="size-1.75 rounded-full bg-red-500"></div>
|
||||
<p class="text-red-500">{$t('server_offline')}</p>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -77,7 +77,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => info && modalManager.show(ServerAboutModal, { versions, info })}
|
||||
class="dark:text-immich-gray flex gap-1 place-items-center place-content-center"
|
||||
class="flex place-content-center place-items-center gap-1 dark:text-immich-gray"
|
||||
>
|
||||
{#if isMain}
|
||||
<Icon icon={mdiAlert} size="1.5em" color="#ffcc4d" /> {info?.sourceRef}
|
||||
@@ -96,17 +96,17 @@
|
||||
href={releaseInfo.releaseUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="mt-3 p-2.5 ms-4 rounded-lg text-sm min-w-52 border border-gray-200/50 dark:border-gray-700/50 bg-white/50 dark:bg-gray-800/50 hover:border-immich-primary/40 dark:hover:border-immich-dark-primary/40 hover:bg-immich-primary/5 dark:hover:bg-immich-dark-primary/5 transition-all duration-200 group block"
|
||||
class="group ms-4 mt-3 block min-w-52 rounded-lg border border-gray-200/50 bg-white/50 p-2.5 text-sm transition-all duration-200 hover:border-immich-primary/40 hover:bg-immich-primary/5 dark:border-gray-700/50 dark:bg-gray-800/50 dark:hover:border-immich-dark-primary/40 dark:hover:bg-immich-dark-primary/5"
|
||||
>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon icon={mdiNewBox} size="16" class="text-immich-primary dark:text-immich-dark-primary opacity-80" />
|
||||
<Icon icon={mdiNewBox} size="16" class="text-immich-primary opacity-80 dark:text-immich-dark-primary" />
|
||||
<Text size="tiny" fontWeight="medium" class="text-gray-700 dark:text-gray-300">
|
||||
{releaseInfo.availableVersion}
|
||||
</Text>
|
||||
</div>
|
||||
<span
|
||||
class="text-[11px] text-gray-500 dark:text-gray-400 group-hover:text-immich-primary dark:group-hover:text-immich-dark-primary transition-colors opacity-70 group-hover:opacity-100"
|
||||
class="text-[11px] text-gray-500 opacity-70 transition-colors group-hover:text-immich-primary group-hover:opacity-100 dark:text-gray-400 dark:group-hover:text-immich-dark-primary"
|
||||
>
|
||||
{$t('new_update')}!
|
||||
</span>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="p-4 bg-light-100 ms-4 rounded-lg text-sm min-w-52"
|
||||
class="ms-4 min-w-52 rounded-lg bg-light-100 p-4 text-sm"
|
||||
title={$t('storage_usage', {
|
||||
values: {
|
||||
used: getByteUnitString(usedBytes, $locale, 3),
|
||||
@@ -58,7 +58,7 @@
|
||||
{thresholds}
|
||||
/>
|
||||
{:else}
|
||||
<p class="font-medium text-immich-dark-gray dark:text-white mb-4">{$t('storage')}</p>
|
||||
<p class="mb-4 font-medium text-immich-dark-gray dark:text-white">{$t('storage')}</p>
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="bg-gray-50 dark:bg-immich-dark-gray/50 w-full p-2 rounded-2xl border border-gray-100 dark:border-gray-900 overflow-y-auto immich-scrollbar"
|
||||
class="w-full overflow-y-auto rounded-2xl border border-gray-100 bg-gray-50 p-2 immich-scrollbar dark:border-gray-900 dark:bg-immich-dark-gray/50"
|
||||
>
|
||||
<ol class="flex gap-2 items-center">
|
||||
<ol class="flex items-center gap-2">
|
||||
<li>
|
||||
<IconButton
|
||||
shape="round"
|
||||
@@ -51,15 +51,15 @@
|
||||
/>
|
||||
</li>
|
||||
{#each parents as parent (parent)}
|
||||
<li class="flex gap-2 items-center font-mono text-sm text-nowrap text-primary">
|
||||
<li class="flex items-center gap-2 font-mono text-sm text-nowrap text-primary">
|
||||
<Icon icon={mdiChevronRight} class="text-gray-500 dark:text-gray-300" size="16" aria-hidden />
|
||||
<a class="underline hover:font-semibold whitespace-pre-wrap" href={getLink(parent.path)}>
|
||||
<a class="whitespace-pre-wrap underline hover:font-semibold" href={getLink(parent.path)}>
|
||||
{parent.value}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
|
||||
<li class="flex gap-2 items-center font-mono text-sm text-nowrap text-primary">
|
||||
<li class="flex items-center gap-2 font-mono text-sm text-nowrap text-primary">
|
||||
<Icon icon={mdiChevronRight} class="text-gray-500 dark:text-gray-300" size="16" aria-hidden />
|
||||
<p class="cursor-default whitespace-pre-wrap">{node.value}</p>
|
||||
</li>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<a
|
||||
href={getLink(node.path)}
|
||||
title={node.value}
|
||||
class={`flex grow place-items-center ps-2 py-1 text-sm rounded-lg hover:bg-slate-200 dark:hover:bg-slate-800 hover:font-semibold ${isTarget ? 'bg-slate-100 dark:bg-slate-700 font-semibold text-primary' : 'dark:text-gray-200'}`}
|
||||
class={`flex grow place-items-center rounded-lg py-1 ps-2 text-sm hover:bg-slate-200 hover:font-semibold dark:hover:bg-slate-800 ${isTarget ? 'bg-slate-100 font-semibold text-primary dark:bg-slate-700' : 'dark:text-gray-200'}`}
|
||||
data-sveltekit-keepfocus
|
||||
>
|
||||
{#if node.size > 0}
|
||||
@@ -34,7 +34,7 @@
|
||||
<Icon icon={isOpen ? mdiChevronDown : mdiChevronRight} class="text-gray-400" size="20" />
|
||||
</button>
|
||||
{/if}
|
||||
<div class={node.size === 0 ? 'ml-[1.5em] ' : ''}>
|
||||
<div class={node.size === 0 ? 'ml-[1.5em]' : ''}>
|
||||
<Icon
|
||||
icon={isActive ? icons.active : icons.default}
|
||||
class={isActive ? 'text-primary' : 'text-gray-400'}
|
||||
@@ -42,7 +42,7 @@
|
||||
size="20"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-nowrap overflow-hidden text-ellipsis font-mono ps-1 pt-1 whitespace-pre-wrap">{node.value}</span>
|
||||
<span class="overflow-hidden ps-1 pt-1 font-mono text-nowrap text-ellipsis whitespace-pre-wrap">{node.value}</span>
|
||||
</a>
|
||||
|
||||
{#if isOpen}
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
|
||||
{#if items.length > 0}
|
||||
<div
|
||||
class="w-full grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-6 2xl:grid-cols-8 gap-2 bg-gray-50 dark:bg-immich-dark-gray/50 rounded-2xl border border-gray-100 dark:border-gray-900"
|
||||
class="grid w-full grid-cols-2 gap-2 rounded-2xl border border-gray-100 bg-gray-50 sm:grid-cols-4 lg:grid-cols-6 2xl:grid-cols-8 dark:border-gray-900 dark:bg-immich-dark-gray/50"
|
||||
>
|
||||
<!-- eslint-disable-next-line svelte/require-each-key -->
|
||||
{#each items as item}
|
||||
<button
|
||||
class="flex flex-col place-items-center gap-2 py-2 px-4 hover:bg-immich-primary/10 dark:hover:bg-immich-primary/40 rounded-xl"
|
||||
class="flex flex-col place-items-center gap-2 rounded-xl px-4 py-2 hover:bg-immich-primary/10 dark:hover:bg-immich-primary/40"
|
||||
onclick={() => onClick(item.value)}
|
||||
title={item.value}
|
||||
type="button"
|
||||
>
|
||||
<Icon {icon} class="text-primary" size="64" />
|
||||
<p class="text-sm dark:text-gray-200 text-nowrap text-ellipsis overflow-clip w-full whitespace-pre-wrap">
|
||||
<p class="w-full overflow-clip text-sm text-nowrap text-ellipsis whitespace-pre-wrap dark:text-gray-200">
|
||||
{item.value}
|
||||
</p>
|
||||
</button>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
let { tree, active, icons, getLink }: Props = $props();
|
||||
</script>
|
||||
|
||||
<ul class="list-none ms-2">
|
||||
<ul class="ms-2 list-none">
|
||||
{#each tree.children as node (node.color ? node.path + node.color : node.path)}
|
||||
<li>
|
||||
<Tree {node} {icons} {active} {getLink} />
|
||||
|
||||
Reference in New Issue
Block a user