0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-04-08 03:01:32 -05:00

chore(deps): update dependency eslint-plugin-svelte to v3 (#16532)

* chore(deps): update dependency eslint-plugin-svelte to v3

* chore: linting

* chore: rebase

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
This commit is contained in:
renovate[bot] 2025-03-03 14:24:26 +00:00 committed by GitHub
parent 5698f446f7
commit 3d6a6f77a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 469 additions and 474 deletions

View file

@ -2,6 +2,8 @@ import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import eslintPluginSvelte from 'eslint-plugin-svelte';
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
import globals from 'globals';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
@ -11,11 +13,12 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
...eslintPluginSvelte.configs.recommended,
eslintPluginUnicorn.configs.recommended,
js.configs.recommended,
{
ignores: [
'**/.DS_Store',
@ -36,15 +39,11 @@ export default [
'coverage',
],
},
...compat.extends(
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'plugin:unicorn/recommended',
),
...compat.extends('plugin:@typescript-eslint/recommended'),
{
plugins: {
'@typescript-eslint': typescriptEslint,
svelte: eslintPluginSvelte,
},
languageOptions: {

658
web/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -45,8 +45,8 @@
"dotenv": "^16.4.7",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-svelte": "^2.46.1",
"eslint-plugin-unicorn": "^56.0.1",
"eslint-plugin-svelte": "^3.0.0",
"eslint-plugin-unicorn": "^57.0.0",
"factory.ts": "^1.4.1",
"globals": "^16.0.0",
"postcss": "^8.5.0",

View file

@ -169,7 +169,7 @@
</script>
<div class="flex flex-col gap-7">
{#each jobList as [jobName, { title, subtitle, description, disabled, allText, refreshText, missingText, icon, handleCommand: handleCommandOverride }]}
{#each jobList as [jobName, { title, subtitle, description, disabled, allText, refreshText, missingText, icon, handleCommand: handleCommandOverride }] (jobName)}
{@const { jobCounts, queueStatus } = jobs[jobName]}
<JobTile
{icon}

View file

@ -46,7 +46,7 @@
<div>
<div in:fade={{ duration: 500 }}>
<form autocomplete="off" {onsubmit}>
{#each jobNames as jobName}
{#each jobNames as jobName (jobName)}
<div class="ml-4 mt-4 flex flex-col gap-4">
{#if isSystemConfigJobDto(jobName)}
<SettingInputField

View file

@ -46,7 +46,7 @@
<hr />
<div>
{#each config.machineLearning.urls as _, i}
{#each config.machineLearning.urls as _, i (i)}
{#snippet removeButton()}
{#if config.machineLearning.urls.length > 1}
<CircleIconButton

View file

@ -225,7 +225,7 @@
bind:value={selectedPreset}
onchange={handlePresetSelection}
>
{#each templateOptions.presetOptions as preset}
{#each templateOptions.presetOptions as preset (preset)}
<option value={preset}>{renderTemplate(preset)}</option>
{/each}
</select>
@ -246,7 +246,7 @@
<SettingInputField
label={$t('extension')}
inputType={SettingInputFieldType.TEXT}
value={'.jpg'}
value=".jpg"
disabled
/>
</div>

View file

@ -19,6 +19,7 @@
<h4>{$t('date_and_time').toUpperCase()}</h4>
</div>
<!-- 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>
@ -28,7 +29,7 @@
<div>
<p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('year').toUpperCase()}</p>
<ul>
{#each options.yearOptions as yearFormat}
{#each options.yearOptions as yearFormat, index (index)}
<li>{'{{'}{yearFormat}{'}}'} - {getLuxonExample(yearFormat)}</li>
{/each}
</ul>
@ -37,7 +38,7 @@
<div>
<p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('month').toUpperCase()}</p>
<ul>
{#each options.monthOptions as monthFormat}
{#each options.monthOptions as monthFormat, index (index)}
<li>{'{{'}{monthFormat}{'}}'} - {getLuxonExample(monthFormat)}</li>
{/each}
</ul>
@ -46,7 +47,7 @@
<div>
<p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('week').toUpperCase()}</p>
<ul>
{#each options.weekOptions as weekFormat}
{#each options.weekOptions as weekFormat, index (index)}
<li>{'{{'}{weekFormat}{'}}'} - {getLuxonExample(weekFormat)}</li>
{/each}
</ul>
@ -55,7 +56,7 @@
<div>
<p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('day').toUpperCase()}</p>
<ul>
{#each options.dayOptions as dayFormat}
{#each options.dayOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
@ -64,7 +65,7 @@
<div>
<p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('hour').toUpperCase()}</p>
<ul>
{#each options.hourOptions as dayFormat}
{#each options.hourOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
@ -73,7 +74,7 @@
<div>
<p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('minute').toUpperCase()}</p>
<ul>
{#each options.minuteOptions as dayFormat}
{#each options.minuteOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>
@ -82,7 +83,7 @@
<div>
<p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('second').toUpperCase()}</p>
<ul>
{#each options.secondOptions as dayFormat}
{#each options.secondOptions as dayFormat, index (index)}
<li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li>
{/each}
</ul>

View file

@ -92,7 +92,7 @@
<LoadingSpinner />
{/if}
{#each templateConfigs as { label, templateKey, descriptionTags, templateName }}
{#each templateConfigs as { label, templateKey, descriptionTags, templateName } (templateKey)}
<SettingTextarea
{label}
description={$t('admin.template_email_available_tags', { values: { tags: descriptionTags } })}

View file

@ -95,7 +95,7 @@
<p class="text-sm">{$t('owner')}</p>
</div>
</div>
{#each album.albumUsers as { user, role }}
{#each album.albumUsers as { user, role } (user.id)}
<div
class="flex w-full place-items-center justify-between gap-4 p-5 rounded-xl transition-colors hover:bg-gray-50 dark:hover:bg-gray-700"
>

View file

@ -73,7 +73,7 @@
<div class="mb-2 py-2 sticky">
<p class="text-xs font-medium">{$t('selected')}</p>
<div class="my-2">
{#each Object.values(selectedUsers) as { user }}
{#each Object.values(selectedUsers) as { user } (user.id)}
{#key user.id}
<div class="flex place-items-center gap-4 p-4">
<div
@ -116,7 +116,7 @@
<Text>{$t('users')}</Text>
<div class="my-2">
{#each users as user}
{#each users as user (user.id)}
{#if !Object.keys(selectedUsers).includes(user.id)}
<div class="flex place-items-center transition-all hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl">
<button type="button" onclick={() => handleToggle(user)} class="flex w-full place-items-center gap-4 p-4">
@ -161,7 +161,7 @@
</div>
<Stack gap={4}>
{#each sharedLinks as sharedLink}
{#each sharedLinks as sharedLink (sharedLink.id)}
<AlbumSharedLink {album} {sharedLink} />
{/each}
</Stack>

View file

@ -536,7 +536,7 @@
{#if albums.length > 0}
<section class="px-6 pt-6 dark:text-immich-dark-fg">
<p class="pb-4 text-sm">{$t('appears_in').toUpperCase()}</p>
{#each albums as album}
{#each albums as album (album.id)}
<a href="{AppRoute.ALBUMS}/{album.id}">
<div class="flex gap-4 pt-2 hover:cursor-pointer items-center">
<div>

View file

@ -137,7 +137,7 @@
<div class="flex h-10 w-full items-center justify-between text-sm">
<h2>{$t('editor_crop_tool_h2_aspect_ratios').toUpperCase()}</h2>
</div>
{#each sizesRows as sizesRow}
{#each sizesRows as sizesRow, index (index)}
<ul class="flex-wrap flex-row flex gap-x-6 py-2 justify-evenly">
{#each sizesRow as size (size.name)}
<CropPreset {size} {selectedSize} {rotateHorizontal} {selectType} />

View file

@ -325,7 +325,7 @@
<div class="h-[250px] overflow-y-auto mt-2">
{#if filteredCandidates.length > 0}
<div class="mt-2 rounded-lg">
{#each filteredCandidates as person}
{#each filteredCandidates as person (person.id)}
<button
onclick={() => tagFace(person)}
type="button"

View file

@ -225,6 +225,7 @@
: slideshowLookCssMapping[$slideshowLook]}"
draggable="false"
/>
<!-- eslint-disable-next-line svelte/require-each-key -->
{#each getBoundingBox($boundingBoxesArray, $photoZoomState, $photoViewerImgElement) as boundingbox}
<div
class="absolute border-solid border-white border-[3px] rounded-lg"

View file

@ -22,7 +22,7 @@
<div class="absolute z-50 top-2 left-2 transition-transform {isFocused ? 'translate-y-0' : '-translate-y-10 sr-only'}">
<Button
size={'sm'}
size="sm"
rounded="none"
onclick={moveFocus}
onfocus={() => (isFocused = true)}

View file

@ -18,7 +18,7 @@
class="dark:bg-immich-dark-gray flex h-full rounded-2xl bg-gray-200 ring-gray-400 has-[:focus-visible]:ring dark:ring-gray-600"
>
<legend class="sr-only">{label}</legend>
{#each filters as filter, index}
{#each filters as filter, index (`${id}-${index}`)}
<div class="group">
<input
type="radio"

View file

@ -111,7 +111,7 @@
<div></div>
{/snippet}
{#snippet trailing()}
<Button size={'sm'} disabled={!hasSelection} onclick={handleMerge}>
<Button size="sm" disabled={!hasSelection} onclick={handleMerge}>
<Icon path={mdiMerge} size={18} />
<span class="ml-2">{$t('merge')}</span></Button
>

View file

@ -221,7 +221,7 @@
<LoadingSpinner />
</div>
{:else}
{#each peopleWithFaces as face, index}
{#each peopleWithFaces as face, index (face.id)}
{@const personName = face.person ? face.person?.name : $t('face_unassigned')}
<div class="relative z-[20001] h-[115px] w-[95px]">
<div

View file

@ -131,7 +131,7 @@
<div class="flex gap-4">
<Button
title={$t('create_new_person_hint')}
size={'sm'}
size="sm"
disabled={disableButtons || hasSelection}
onclick={handleCreate}
>
@ -143,7 +143,7 @@
<span class="ml-2"> {$t('create_new_person')}</span></Button
>
<Button
size={'sm'}
size="sm"
title={$t('reassing_hint')}
disabled={disableButtons || !hasSelection}
onclick={handleReassign}

View file

@ -175,7 +175,7 @@
<form {onsubmit} autocomplete="off" class="m-4 flex flex-col gap-4">
<table class="text-left">
<tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
{#each validatedPaths as validatedPath, listIndex}
{#each validatedPaths as validatedPath, listIndex (validatedPath.importPath)}
<tr
class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${
listIndex % 2 == 0

View file

@ -125,7 +125,7 @@
<form {onsubmit} autocomplete="off" class="m-4 flex flex-col gap-4">
<table class="w-full text-left">
<tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
{#each exclusionPatterns as exclusionPattern, listIndex}
{#each exclusionPatterns as exclusionPattern, listIndex (exclusionPattern)}
<tr
class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${
listIndex % 2 == 0

View file

@ -129,6 +129,7 @@ Used for every occurrence of an HTML tag in a message
Result: Visit <a href="">docs</a> <strong>now</strong>
```
-->
<!-- eslint-disable-next-line svelte/require-each-key -->
{#each parts as { tag, message }}
{#if tag}
{#if children}{@render children({ tag, message })}{:else}{message}{/if}

View file

@ -183,6 +183,7 @@
if (!current) {
return;
}
// eslint-disable-next-line no-self-assign
current.memory.assets = current.memory.assets;
};
@ -222,6 +223,7 @@
current.memory.assets = current.memory.assets.filter((asset) => asset.id !== current.asset.id);
// eslint-disable-next-line no-self-assign
$memoryStore = $memoryStore;
await removeMemoryAssets({ id: current.memory.id, bulkIdsDto: { ids: [current.asset.id] } });
@ -351,7 +353,7 @@
class="hover:text-black"
/>
{#each current.memory.assets as asset, index}
{#each current.memory.assets as asset, index (asset.id)}
<a class="relative w-full py-2" href={asHref(asset)}>
<span class="absolute left-0 h-[2px] w-full bg-gray-500"></span>
{#await resetPromise}
@ -475,14 +477,10 @@
align="bottom-right"
class="text-white dark:text-white"
>
<MenuOption
onClick={() => handleDeleteMemory(current)}
text={'Remove memory'}
icon={mdiCardsOutline}
/>
<MenuOption onClick={() => handleDeleteMemory(current)} text="Remove memory" icon={mdiCardsOutline} />
<MenuOption
onClick={() => handleDeleteMemoryAsset(current)}
text={'Remove photo from this memory'}
text="Remove photo from this memory"
icon={mdiImageMinusOutline}
/>
<!-- shortcut={{ key: 'l', shift: shared }} -->

View file

@ -32,41 +32,39 @@
{#if config && $user}
<AdminSettings bind:config bind:this={adminSettingsComponent}>
{#snippet children()}
{#if config}
<SettingSwitch
title={$t('admin.map_settings')}
subtitle={$t('admin.map_implications')}
bind:checked={config.map.enabled}
/>
<SettingSwitch
title={$t('admin.version_check_settings')}
subtitle={$t('admin.version_check_implications')}
bind:checked={config.newVersionCheck.enabled}
/>
<div class="flex pt-4">
<div class="w-full flex place-content-start">
<Button class="flex gap-2 place-content-center" onclick={() => onPrevious()}>
<Icon path={mdiArrowLeft} size="18" />
<p>{$t('theme')}</p>
</Button>
</div>
<div class="flex w-full place-content-end">
<Button
onclick={() => {
adminSettingsComponent?.handleSave({ map: config?.map, newVersionCheck: config?.newVersionCheck });
onDone();
}}
>
<span class="flex place-content-center place-items-center gap-2">
{$t('admin.storage_template_settings')}
<Icon path={mdiArrowRight} size="18" />
</span>
</Button>
</div>
{#if config}
<SettingSwitch
title={$t('admin.map_settings')}
subtitle={$t('admin.map_implications')}
bind:checked={config.map.enabled}
/>
<SettingSwitch
title={$t('admin.version_check_settings')}
subtitle={$t('admin.version_check_implications')}
bind:checked={config.newVersionCheck.enabled}
/>
<div class="flex pt-4">
<div class="w-full flex place-content-start">
<Button class="flex gap-2 place-content-center" onclick={() => onPrevious()}>
<Icon path={mdiArrowLeft} size="18" />
<p>{$t('theme')}</p>
</Button>
</div>
{/if}
{/snippet}
<div class="flex w-full place-content-end">
<Button
onclick={() => {
adminSettingsComponent?.handleSave({ map: config?.map, newVersionCheck: config?.newVersionCheck });
onDone();
}}
>
<span class="flex place-content-center place-items-center gap-2">
{$t('admin.storage_template_settings')}
<Icon path={mdiArrowRight} size="18" />
</span>
</Button>
</div>
</div>
{/if}
</AdminSettings>
{/if}
</OnboardingCard>

View file

@ -33,7 +33,7 @@
};
</script>
{#each jobs as job}
{#each jobs as job (job)}
{#if isAllVideos || job !== AssetJobName.TranscodeVideo}
<MenuOption text={$getAssetJobName(job)} icon={getAssetJobIcon(job)} onClick={() => handleRunJob(job)} />
{/if}

View file

@ -119,7 +119,7 @@
data-date-group={dateGroup.date}
style:height={dateGroup.height + 'px'}
style:width={dateGroup.geometry.containerWidth + 'px'}
style:overflow={'clip'}
style:overflow="clip"
>
{#if !display}
<Skeleton height={dateGroup.height + 'px'} title={dateGroup.groupTitle} />

View file

@ -67,7 +67,7 @@
</script>
<section id="measure-asset-group-by-date" class="flex flex-wrap gap-x-12" use:measure>
{#each bucket.dateGroups as dateGroup}
{#each bucket.dateGroups as dateGroup (dateGroup.date)}
<div id="date-group" data-date-group={dateGroup.date}>
<div use:resizeObserver={({ height }) => $assetStore.updateBucketDateGroup(bucket, dateGroup, { height })}>
<div
@ -83,7 +83,7 @@
class="relative overflow-clip"
style:height={dateGroup.geometry.containerHeight + 'px'}
style:width={dateGroup.geometry.containerWidth + 'px'}
style:visibility={'hidden'}
style:visibility="hidden"
></div>
</div>
</div>

View file

@ -69,7 +69,7 @@
</div>
{/if}
<div class="inline-block" use:resizeObserver={({ width }) => (innerWidth = width)}>
{#each $memoryStore as memory}
{#each $memoryStore as memory (memory.id)}
{#if memory.assets.length > 0}
<a
class="memory-card relative mr-8 inline-block aspect-[3/4] md:aspect-video h-[215px] rounded-xl"

View file

@ -43,7 +43,7 @@
<div class="mt-4">
{#if !isCollapsed}
<div class="flex flex-row flex-wrap gap-4">
{#each places as item}
{#each places as item (item.id)}
{@const city = item.exifInfo?.city}
<a class="relative" href="{AppRoute.SEARCH}?{getMetadataSearchQuery({ city })}" draggable="false">
<div

View file

@ -83,6 +83,7 @@
<FullScreenModal title={shared ? $t('add_to_shared_album') : $t('add_to_album')} {onClose}>
<div class="mb-2 flex max-h-[400px] flex-col">
{#if loading}
<!-- eslint-disable-next-line svelte/require-each-key -->
{#each { length: 3 } as _}
<div class="flex animate-pulse gap-4 px-6 py-2">
<div class="h-12 w-12 rounded-xl bg-slate-200"></div>
@ -104,6 +105,7 @@
use:initInput
/>
<div class="immich-scrollbar overflow-y-auto">
<!-- eslint-disable-next-line svelte/require-each-key -->
{#each albumModalRows as row}
{#if row.type === AlbumModalRowType.NEW_ALBUM}
<NewAlbumListItem selected={row.selected || false} {onNewAlbum} searchQuery={search} />

View file

@ -139,7 +139,7 @@
use:clickOutside={{ onOutclick: () => (hideSuggestion = true) }}
>
{#if !hideSuggestion}
{#each suggestedPlaces as place, index}
{#each suggestedPlaces as place, index (place.latitude + place.longitude)}
<button
type="button"
class=" flex w-full border-t border-gray-400 dark:border-immich-dark-gray h-14 place-items-center bg-gray-200 p-2 dark:bg-gray-700 hover:bg-gray-300 hover:dark:bg-[#232932] focus:bg-gray-300 focus:dark:bg-[#232932] {index ===

View file

@ -75,7 +75,7 @@
>
<div class="flex place-items-center sm:gap-6 justify-self-start dark:text-immich-dark-fg">
{#if showBackButton}
<CircleIconButton title={$t('close')} onclick={handleClose} icon={backIcon} size={'24'} class={buttonClass} />
<CircleIconButton title={$t('close')} onclick={handleClose} icon={backIcon} size="24" class={buttonClass} />
{/if}
{@render leading?.()}
</div>

View file

@ -37,5 +37,5 @@
</h1>
</div>
<CircleIconButton onclick={onClose} icon={mdiClose} size={'20'} title={$t('close')} />
<CircleIconButton onclick={onClose} icon={mdiClose} size="20" title={$t('close')} />
</div>

View file

@ -18,7 +18,7 @@
<FullScreenModal title={$t('select_avatar_color')} width="auto" {onClose}>
<div class="flex items-center justify-center mt-4">
<div class="grid grid-cols-2 md:grid-cols-5 gap-4">
{#each colors as color}
{#each colors as color (color)}
<button type="button" onclick={() => onChoose(color)}>
<UserAvatar label={color} {user} {color} size="xl" showProfileImage={false} />
</button>

View file

@ -15,7 +15,7 @@
</script>
<Portal>
<FullScreenModal showLogo title={''} {onClose} width="wide">
<FullScreenModal showLogo title="" {onClose} width="wide">
{#if showProductActivated}
<PurchaseActivationSuccess onDone={onClose} />
{:else}

View file

@ -278,7 +278,7 @@
{/if}
</div>
<!-- Time Segment -->
{#each segments as segment}
{#each segments as segment (segment.date)}
<div
id="time-segment"
class="relative"

View file

@ -44,6 +44,7 @@
}
} else {
$accordionState.delete(key);
// eslint-disable-next-line no-self-assign
$accordionState = $accordionState;
}
};

View file

@ -30,7 +30,7 @@
</script>
<div class="mb-4 w-full">
<div class={`flex h-[26px] place-items-center gap-1`}>
<div class="flex h-[26px] place-items-center gap-1">
<label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for="{name}-select">
{label}
</label>
@ -51,7 +51,7 @@
</p>
{/if}
<div class="flex flex-col gap-2">
{#each options as option}
{#each options as option (option.value)}
<Checkbox
id="{option.value}-checkbox"
label={option.text}

View file

@ -70,7 +70,7 @@
</script>
<div class="mb-4 w-full">
<div class={`flex place-items-center gap-1`}>
<div class="flex place-items-center gap-1">
<label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for={label}>{label}</label>
{#if required}
<div class="text-red-400">*</div>

View file

@ -39,7 +39,7 @@
</script>
<div class="mb-4 w-full">
<div class={`flex h-[26px] place-items-center gap-1`}>
<div class="flex h-[26px] place-items-center gap-1">
<label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for="{name}-select"
>{label}</label
>
@ -63,7 +63,7 @@
<div class="grid">
<Icon
path={mdiChevronDown}
size={'1.2em'}
size="1.2em"
ariaHidden={true}
class="pointer-events-none right-1 relative col-start-1 row-start-1 self-center justify-self-end {disabled
? 'text-immich-bg'
@ -78,7 +78,7 @@
bind:value
onchange={handleChange}
>
{#each options as option}
{#each options as option (option.value)}
<option value={option.value}>{option.text}</option>
{/each}
</select>

View file

@ -30,7 +30,7 @@
</script>
<div class="mb-4 w-full">
<div class={`flex h-[26px] place-items-center gap-1`}>
<div class="flex h-[26px] place-items-center gap-1">
<label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for={label}>{label}</label>
{#if required}
<div class="text-red-400">*</div>

View file

@ -50,10 +50,10 @@
<div class="p-4">
<h2>{$t('general')}</h2>
<div class="text-sm">
{#each shortcuts.general as shortcut}
{#each shortcuts.general as shortcut (shortcut.key.join('-'))}
<div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm">
<div class="flex justify-self-end">
{#each shortcut.key as key}
{#each shortcut.key as key (key)}
<p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2">
{key}
</p>
@ -69,10 +69,10 @@
<div class="p-4">
<h2>{$t('actions')}</h2>
<div class="text-sm">
{#each shortcuts.actions as shortcut}
{#each shortcuts.actions as shortcut (shortcut.key.join('-'))}
<div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm">
<div class="flex justify-self-end">
{#each shortcut.key as key}
{#each shortcut.key as key (key)}
<p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2">
{key}
</p>

View file

@ -23,7 +23,7 @@
});
</script>
{#each albums as album}
{#each albums as album (album.id)}
<a
href={'/albums/' + album.id}
title={album.albumName}

View file

@ -71,7 +71,7 @@
>
<legend class="sr-only">{$t('rating')}</legend>
<div class="flex flex-row" data-testid="star-container">
{#each { length: count } as _, index}
{#each { length: count } as _, index (index)}
{@const value = index + 1}
{@const filled = hoverRating >= value || (hoverRating === 0 && ratingSelection >= value)}
{@const starId = `${id}-${value}`}

View file

@ -45,7 +45,7 @@
onclick={() => {}}
/>
</li>
{#each pathSegments as segment, index}
{#each pathSegments as segment, index (segment)}
{@const isLastSegment = index === pathSegments.length - 1}
<li
class="flex gap-2 items-center font-mono text-sm text-nowrap text-immich-primary dark:text-immich-dark-primary"

View file

@ -14,7 +14,7 @@
<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"
>
{#each items as item}
{#each items as item (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"
onclick={() => onClick(item)}

View file

@ -15,6 +15,7 @@
</script>
<ul class="list-none ml-2">
<!-- eslint-disable-next-line svelte/require-each-key -->
{#each Object.entries(items).sort() as [path, tree]}
{@const value = normalizeTreePath(`${parent}/${path}`)}
{@const key = value + getColor(value)}

View file

@ -71,7 +71,7 @@
<h3 class="mb-2 text-xs font-medium text-immich-primary dark:text-immich-dark-primary">
{$t('other_devices').toUpperCase()}
</h3>
{#each otherDevices as device, index}
{#each otherDevices as device, index (device.id)}
<DeviceCard {device} onDelete={() => handleDelete(device)} />
{#if index !== otherDevices.length - 1}
<hr class="my-3" />

View file

@ -39,7 +39,7 @@
<FullScreenModal title={$t('add_partner')} showLogo {onClose}>
<div class="immich-scrollbar max-h-[300px] overflow-y-auto">
{#if availableUsers.length > 0}
{#each availableUsers as user}
{#each availableUsers as user (user.id)}
<button
type="button"
onclick={() => selectUser(user)}

View file

@ -144,7 +144,7 @@
<CircleIconButton
onclick={() => handleRemovePartner(partner.user)}
icon={mdiClose}
size={'16'}
size="16"
title={$t('stop_sharing_photos_with_user')}
/>
{/if}

View file

@ -137,37 +137,35 @@
</tr>
</thead>
<tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
{#each keys as key, index}
{#key key.id}
<tr
class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${
index % 2 == 0
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
}`}
>
<td class="w-1/3 text-ellipsis px-4 text-sm">{key.name}</td>
<td class="w-1/3 text-ellipsis px-4 text-sm"
>{new Date(key.createdAt).toLocaleDateString($locale, format)}
</td>
<td class="flex flex-row flex-wrap justify-center gap-x-2 gap-y-1 w-1/3">
<CircleIconButton
color="primary"
icon={mdiPencilOutline}
title={$t('edit_key')}
size="16"
onclick={() => (editKey = key)}
/>
<CircleIconButton
color="primary"
icon={mdiTrashCanOutline}
title={$t('delete_key')}
size="16"
onclick={() => handleDelete(key)}
/>
</td>
</tr>
{/key}
{#each keys as key, index (key.id)}
<tr
class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${
index % 2 == 0
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
}`}
>
<td class="w-1/3 text-ellipsis px-4 text-sm">{key.name}</td>
<td class="w-1/3 text-ellipsis px-4 text-sm"
>{new Date(key.createdAt).toLocaleDateString($locale, format)}
</td>
<td class="flex flex-row flex-wrap justify-center gap-x-2 gap-y-1 w-1/3">
<CircleIconButton
color="primary"
icon={mdiPencilOutline}
title={$t('edit_key')}
size="16"
onclick={() => (editKey = key)}
/>
<CircleIconButton
color="primary"
icon={mdiTrashCanOutline}
title={$t('delete_key')}
size="16"
onclick={() => handleDelete(key)}
/>
</td>
</tr>
{/each}
</tbody>
</table>

View file

@ -137,7 +137,7 @@
await loadNextPage();
}
export const loadNextPage = async () => {
const loadNextPage = async () => {
if (!nextPage || searchResultAssets.length >= MAX_ASSET_COUNT) {
return;
}
@ -230,6 +230,7 @@
return tagNames.join(', ');
}
// eslint-disable-next-line no-self-assign
const triggerAssetUpdate = () => (searchResultAssets = searchResultAssets);
const onAddToAlbum = (assetIds: string[]) => {

View file

@ -195,7 +195,7 @@
</thead>
<tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
{#if allUsers}
{#each allUsers as immichUser, index}
{#each allUsers as immichUser, index (immichUser.id)}
<tr
class="flex h-[80px] overflow-hidden w-full place-items-center text-center dark:text-immich-dark-fg {immichUser.deletedAt
? 'bg-red-300 dark:bg-red-900'