refactor(web): use declaration tags instead of @const (#32639)

(cherry picked from commit c6d1e15c77c5f3786b26b292def27247b258cde5)
This commit is contained in:
Mees Frensel
2026-10-26 22:34:24 +03:00
committed by Codex
parent 86c8b9e04d
commit c48394aa6e
52 changed files with 102 additions and 99 deletions
+1
View File
@@ -164,6 +164,7 @@ export default defineConfig(
'@typescript-eslint/switch-exhaustiveness-check': ['error', { considerDefaultExhaustiveForUnions: true }],
'svelte/button-has-type': 'error',
'object-shorthand': ['error', 'always'],
'svelte/no-at-const-tags': 'error',
'svelte/no-navigation-without-resolve': 'off',
'unicorn/prefer-early-return': 'off',
'unicorn/prefer-ternary': 'off',
+2 -2
View File
@@ -36,8 +36,8 @@
"@photo-sphere-viewer/resolution-plugin": "^5.14.0",
"@photo-sphere-viewer/settings-plugin": "^5.14.0",
"@photo-sphere-viewer/video-plugin": "^5.14.0",
"@tanstack/svelte-query": "^6.3.2",
"@simplewebauthn/browser": "14.0.0",
"@tanstack/svelte-query": "^6.3.2",
"@types/geojson": "^7946.0.16",
"@zoom-image/core": "^0.43.0",
"@zoom-image/svelte": "^0.3.0",
@@ -101,7 +101,7 @@
"eslint-plugin-better-tailwindcss": "^4.5.0",
"eslint-plugin-compat": "^7.0.0",
"eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-svelte": "^3.12.4",
"eslint-plugin-svelte": "^3.23.1",
"eslint-plugin-unicorn": "^75.0.0",
"factory.ts": "^1.4.1",
"globals": "^17.0.0",
@@ -70,9 +70,11 @@
</div>
{#each data.series as day, idx (day.date)}
{@const date = DateTime.fromISO(day.date, { zone: 'utc' }).toLocaleString(
{ month: 'short', day: 'numeric' },
{ locale: $locale },
{const date = $derived(
DateTime.fromISO(day.date, { zone: 'utc' }).toLocaleString(
{ month: 'short', day: 'numeric' },
{ locale: $locale },
),
)}
<div
class="aspect-square size-full rounded-sm {itemColors(day.count)} row-start-(--heatmap-row-start)"
@@ -49,7 +49,7 @@
{@render button()}
</div>
{:else}
{@const albumId = albumIds[0]}
{const albumId = $derived(albumIds[0])}
{#if albumId}
<AlbumThumbnail {albumId} onDelete={() => (albumIds = [])} />
{:else}
@@ -92,7 +92,7 @@
<Select options={schema.enum} bind:value={getString, setValue} />
</Field>
{:else if schema.array}
{@const values = getValue<string[]>([])}
{const values = $derived(getValue<string[]>([]))}
<Field {label} {description}>
<Input value={values.join(',')} disabled />
<HelperText>{$t('unsupported_field_type')}</HelperText>
@@ -23,6 +23,8 @@
preload = false,
contextMenuItems,
}: Props = $props();
const owner = $derived(album.albumUsers[0].user);
</script>
<div
@@ -74,7 +76,6 @@
{/if}
{#if showOwner}
{@const owner = album.albumUsers[0].user}
{#if owner.id === authManager.user.id}
<p>{$t('owned')}</p>
{:else}
@@ -66,8 +66,8 @@
{#if !isCollapsed}
<div class="grid grid-auto-fill-56 gap-y-4" transition:slide={{ duration: 300 }}>
{#each albums as album, index (album.id)}
{@const { Edit, Share, Download, Leave, Delete } = getAlbumActions($t, album)}
{@const items = [Edit, Share, Download, Leave, Delete]}
{const { Edit, Share, Download, Leave, Delete } = $derived(getAlbumActions($t, album))}
{const items = $derived([Edit, Share, Download, Leave, Delete])}
<a
href={Route.viewAlbum(album)}
class="h-fit"
@@ -39,8 +39,8 @@
</tbody>
{:else}
{#each groupedAlbums as albumGroup (albumGroup.id)}
{@const isCollapsed = isAlbumGroupCollapsed($albumViewSettings, albumGroup.id)}
{@const iconRotation = isCollapsed ? 'rotate-0' : 'rotate-90'}
{const isCollapsed = $derived(isAlbumGroupCollapsed($albumViewSettings, albumGroup.id))}
{const iconRotation = $derived(isCollapsed ? 'rotate-0' : 'rotate-90')}
<tbody
class="mt-4 block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray dark:text-immich-dark-fg"
>
@@ -649,10 +649,9 @@
{/if}
{#if stack && withStacked && !assetViewerManager.isShowEditor && $slideshowState === SlideshowState.None}
{@const stackedAssets = stack.assets}
<div id="stack-slideshow" class="absolute bottom-0 col-span-4 col-start-1 w-fit max-w-full">
<div class="no-wrap horizontal-scrollbar relative flex flex-row overflow-x-auto overflow-y-hidden">
{#each stackedAssets as stackedAsset (stackedAsset.id)}
{#each stack.assets as stackedAsset (stackedAsset.id)}
<div
class={['relative inline-block px-1 pb-2 transition-all']}
style:bottom={stackedAsset.id === asset.id ? '0' : '-10px'}
@@ -142,11 +142,11 @@
<ActionMenuItem action={StackActions.RemoveAsset} />
{#if album}
{@const { SetCover } = getAlbumAssetActions($t, album, asset)}
{const { SetCover } = $derived(getAlbumAssetActions($t, album, asset))}
<ActionMenuItem action={SetCover} />
{/if}
{#if person}
{@const { SetFeaturedPhoto } = getPersonAssetActions($t, person, asset)}
{const { SetFeaturedPhoto } = $derived(getPersonAssetActions($t, person, asset))}
<ActionMenuItem action={SetFeaturedPhoto} />
{/if}
@@ -186,7 +186,7 @@
{getMegapixel(asset.exifInfo.exifImageHeight, asset.exifInfo.exifImageWidth)} MP
</p>
{/if}
{@const { width, height } = getDimensions(asset.exifInfo)}
{const { width, height } = $derived(getDimensions(asset.exifInfo))}
<p>{width} × {height}</p>
{/if}
{#if asset.exifInfo?.fileSizeInByte}
@@ -295,8 +295,8 @@
onOpenInMapView={() => goto(Route.map({ ...latlng, zoom: 12.5 }))}
>
{#snippet popup({ marker })}
{@const { lat, lon } = marker}
<div class="flex flex-col items-center gap-1">
{const { lat, lon } = $derived(marker)}
<Text fontWeight="bold">{lat.toPrecision(6)}, {lon.toPrecision(6)}</Text>
<Link
href="https://www.openstreetmap.org/?mlat={lat}&mlon={lon}&zoom=13#map=15/{lat}/{lon}"
@@ -103,8 +103,10 @@
<div class="mt-2 grid {visiblePeople.length <= 6 ? 'grid-cols-3 gap-3' : 'grid-cols-4 gap-2'}">
{#each visiblePeople as person (person.id)}
{@const personFaces = faceManager.facesByPersonId.get(person.id) ?? []}
{@const isHighlighted = personFaces.some((f) => assetViewerManager.highlightedFaces.some((b) => b.id === f.id))}
{const personFaces = $derived(faceManager.facesByPersonId.get(person.id) ?? [])}
{const isHighlighted = $derived(
personFaces.some((f) => assetViewerManager.highlightedFaces.some((b) => b.id === f.id)),
)}
<a
class="group outline-none"
href={Route.viewPerson(person, { previousRoute })}
@@ -265,7 +265,7 @@
</svg>
</div>
{#each boundingBoxes as boundingbox (boundingbox.id)}
{@const isActive = assetViewerManager.highlightedFaces.some((f) => f.id === boundingbox.id)}
{const isActive = $derived(assetViewerManager.highlightedFaces.some((f) => f.id === boundingbox.id))}
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
class="pointer-events-auto absolute rounded-lg {isActive && 'border-3 border-solid border-white'}"
@@ -274,9 +274,10 @@
onpointerleave={() => assetViewerManager.clearHighlightedFaces()}
>
{#if isActive && boundingbox.name}
{@const labelAbove =
{const labelAbove = $derived(
boundingbox.top + boundingbox.height + faceLabelOffset > overlaySize.height &&
boundingbox.top >= faceLabelOffset}
boundingbox.top >= faceLabelOffset,
)}
<div
aria-hidden="true"
class="absolute rounded-sm bg-white/90 px-2 py-1 text-sm font-medium whitespace-nowrap text-black shadow-lg"
@@ -93,7 +93,7 @@
></div>
{#each edges as edge (edge)}
{@const rotatedEdge = rotateBoundary(edges, edge, transformManager.normalizedRotation / 90)}
{const rotatedEdge = $derived(rotateBoundary(edges, edge, transformManager.normalizedRotation / 90))}
<button
class={['absolute', edge]}
style={`${edge}: -10px`}
@@ -104,7 +104,7 @@
{/each}
{#each corners as corner (corner)}
{@const rotatedCorner = rotateBoundary(corners, corner, transformManager.normalizedRotation / 90)}
{const rotatedCorner = $derived(rotateBoundary(corners, corner, transformManager.normalizedRotation / 90))}
<button
class={['corner', corner]}
onmousedown={(e) => transformManager.handleMouseDownOn(e, corner)}
@@ -238,8 +238,8 @@
</div>
{:else}
{#each peopleWithFaces as face, index (face.id)}
{@const personName = face.person ? face.person.name : $t('face_unassigned')}
{@const isHighlighted = assetViewerManager.highlightedFaces.some((b) => b.id === face.id)}
{const personName = face.person ? face.person.name : $t('face_unassigned')}
{const isHighlighted = $derived(assetViewerManager.highlightedFaces.some((b) => b.id === face.id))}
<div class="relative h-29 w-24">
<div
role="button"
@@ -348,8 +348,8 @@
>
{#each assets as asset, index (asset.id + '-' + index)}
{#if isInOrNearViewport(index)}
{@const currentAsset = toTimelineAsset(asset)}
<div class="absolute" style:overflow="clip" style={getStyle(index)}>
{const currentAsset = toTimelineAsset(asset)}
<Thumbnail
readonly={disableAssetSelect}
onClick={() => {
@@ -100,9 +100,9 @@
</div>
{#each filteredSearchTerms as savedSearchTerm, i (i)}
{@const index = showClearAll ? i + 1 : i}
<div class="flex w-full items-center justify-between text-black dark:text-gray-300">
<div class="relative w-full items-center">
{const index = $derived(showClearAll ? i + 1 : i)}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
id={getId(index)}
@@ -46,14 +46,14 @@
</div>
{:then people}
{#if people && people.length > 0}
{@const peopleList = showAllPeople
? filterPeople(people, name)
: filterPeople(people, name).slice(0, numberOfPeople)}
<div id="people-selection" class="max-h-80 immich-scrollbar overflow-y-auto">
<Text class="pb-5">{$t('people_search_description')}</Text>
<SearchBar bind:name placeholder={$t('filter_people')} showLoadingSpinner={false} />
{const peopleList = $derived(
showAllPeople ? filterPeople(people, name) : filterPeople(people, name).slice(0, numberOfPeople),
)}
<SingleGridRow
class="space-between grid immich-scrollbar grid-auto-fill-20 gap-5 overflow-y-auto pt-5"
bind:itemCount={numberOfPeople}
@@ -81,7 +81,7 @@
{#if selectedTags?.size}
<section class="flex flex-wrap gap-2 pt-5">
{#each selectedTags as tagId (tagId)}
{@const tag = tagMap[tagId]}
{const tag = $derived(tagMap[tagId])}
{#if tag}
<Button
size="small"
@@ -35,8 +35,8 @@
<!-- Image grid -->
<div data-image-grid class="relative overflow-clip" style:height={height + 'px'} style:width={width + 'px'}>
{#each viewerAssets as viewerAsset (viewerAsset.id)}
{@const position = viewerAsset.position!}
{@const asset = viewerAsset.asset!}
{const position = viewerAsset.position!}
{const asset = viewerAsset.asset!}
<!-- note: don't remove data-asset-id - its used by web e2e tests -->
<div
+2 -3
View File
@@ -58,7 +58,6 @@
</script>
{#each filterIsInOrNearViewport(timelineMonth.timelineDays) as timelineDay, groupIndex (timelineDay.day)}
{@const isTimelineDaySelected = assetInteraction.selectedGroup.has(timelineDay.groupTitle)}
<!-- svelte-ignore a11y_no_static_element_interactions -->
<section
class={[{ 'transition-all': !timelineMonth.timelineManager.suspendTransitions }]}
@@ -76,10 +75,10 @@
style:width={timelineDay.width + 'px'}
>
{#if !singleSelect}
{const isTimelineDaySelected = $derived(assetInteraction.selectedGroup.has(timelineDay.groupTitle))}
<div
class="w-0 overflow-hidden transition-all duration-200 ease-out hover:cursor-pointer"
class:w-8={hoveredTimelineDay === timelineDay.groupTitle ||
assetInteraction.selectedGroup.has(timelineDay.groupTitle)}
class:w-8={hoveredTimelineDay === timelineDay.groupTitle || isTimelineDaySelected}
onclick={() => onTimelineDaySelect(timelineDay, assetsSnapshot(timelineDay.getAssets()))}
onkeydown={() => onTimelineDaySelect(timelineDay, assetsSnapshot(timelineDay.getAssets()))}
>
@@ -634,24 +634,21 @@
</section>
{#each timelineManager.months as timelineMonth (timelineMonth.viewId)}
{@const isInOrNearViewport = timelineMonth.isInOrNearViewport}
{@const absoluteHeight = timelineMonth.top}
{#if !timelineMonth.isLoaded}
<div
style:height={timelineMonth.height + 'px'}
style:position="absolute"
style:transform={`translate3d(0,${absoluteHeight}px,0)`}
style:transform={`translate3d(0,${timelineMonth.top}px,0)`}
style:width="100%"
>
<Skeleton {invisible} height={timelineMonth.height} title={timelineMonth.title} />
</div>
{:else if isInOrNearViewport}
{:else if timelineMonth.isInOrNearViewport}
<div
class="timeline-month"
style:height={timelineMonth.height + 'px'}
style:position="absolute"
style:transform={`translate3d(0,${absoluteHeight}px,0)`}
style:transform={`translate3d(0,${timelineMonth.top}px,0)`}
style:width="100%"
>
<Month
@@ -663,10 +660,11 @@
onTimelineDaySelect={handleGroupSelect}
>
{#snippet thumbnail({ asset, position, timelineDay, groupIndex })}
{@const isAssetSelectionCandidate = assetInteraction.hasSelectionCandidate(asset.id)}
{@const isAssetSelected =
assetInteraction.hasSelectedAsset(asset.id) || timelineManager.albumAssets.has(asset.id)}
{@const isAssetDisabled = timelineManager.albumAssets.has(asset.id)}
{const isAssetSelectionCandidate = $derived(assetInteraction.hasSelectionCandidate(asset.id))}
{const isAssetSelected = $derived(
assetInteraction.hasSelectedAsset(asset.id) || timelineManager.albumAssets.has(asset.id),
)}
{const isAssetDisabled = $derived(timelineManager.albumAssets.has(asset.id))}
<Thumbnail
showStackedIcon={withStacked}
{showArchiveIcon}
+2 -2
View File
@@ -112,8 +112,8 @@
)}"
>
{#each options as option (option)}
{@const renderedOption = renderOption(option)}
{@const buttonStyle = renderedOption.disabled ? '' : 'transition-all hover:bg-gray-300 dark:hover:bg-gray-800'}
{const renderedOption = renderOption(option)}
{const buttonStyle = renderedOption.disabled ? '' : 'transition-all hover:bg-gray-300 dark:hover:bg-gray-800'}
<button
type="button"
class="grid grid-cols-[36px_1fr] place-items-center p-2 disabled:opacity-40 {buttonStyle}"
+3 -3
View File
@@ -70,9 +70,9 @@
<legend class="sr-only">{$t('rating')}</legend>
<div class="flex flex-row" data-testid="star-container">
{#each { length: count } as _, index (index)}
{@const value = index + 1}
{@const filled = hoverRating === null ? (ratingSelection ?? 0) >= value : hoverRating >= value}
{@const starId = `${id}-${value}`}
{const value = index + 1}
{const filled = $derived(hoverRating === null ? (ratingSelection ?? 0) >= value : hoverRating >= value)}
{const starId = `${id}-${value}`}
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<label
+1 -1
View File
@@ -79,7 +79,7 @@
<section class="flex flex-wrap gap-1 pt-2">
{#each selectedIds as tagId (tagId)}
{@const tag = tagMap[tagId]}
{const tag = $derived(tagMap[tagId])}
{#if tag}
<TagPill label={tag.value} onRemove={() => handleRemove(tagId)} />
{/if}
+1 -1
View File
@@ -82,7 +82,7 @@
</script>
{#snippet row(id: string, label: string, userId: string, onPick: () => Promise<void>)}
{@const user = getUser(userId)}
{const user = $derived(getUser(userId))}
<div class="flex items-center justify-between gap-2">
<Label id="{id}-label" for={id}>{label}</Label>
<Button
+1 -1
View File
@@ -72,7 +72,7 @@
{:else if filteredPeople.length > 0}
<div class="grid grid-cols-3 gap-4 p-2">
{#each filteredPeople as person (person.id)}
{@const isSelected = selectedPeople.some((p) => p.id === person.id)}
{const isSelected = $derived(selectedPeople.some((p) => p.id === person.id))}
<button
type="button"
onclick={() => togglePerson(person)}
+1 -1
View File
@@ -74,7 +74,7 @@
<Label size="small" color="primary" for="version-history">{$t('version_history')}</Label>
<ul id="version-history" class="list-none">
{#each versions.slice(0, 5) as item (item.id)}
{@const createdAt = DateTime.fromISO(item.createdAt)}
{const createdAt = DateTime.fromISO(item.createdAt)}
<li>
<span
class="pb-2 text-xs immich-form-label"
@@ -390,7 +390,7 @@
{#if assetMultiSelectManager.selectionActive}
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t, album)}
{const Actions = $derived(getAssetBulkActions($t, album))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
@@ -61,7 +61,7 @@
{#if assetMultiSelectManager.selectionActive}
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ArchiveAction
unarchive
@@ -64,7 +64,7 @@
<!-- Multiselection mode app bar -->
{#if assetMultiSelectManager.selectionActive}
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<FavoriteAction removeFavorite onFavorite={(assetIds) => timelineManager.removeAssets(assetIds)} />
<ActionButton action={Actions.CreateSharedLink} />
@@ -133,7 +133,7 @@
{#if assetMultiSelectManager.selectionActive}
<div class="fixed inset-s-0 top-0 w-full">
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
<IconButton
@@ -115,8 +115,8 @@
</aside>
{#if assetMultiSelectManager.selectionActive}
{@const Actions = getAssetBulkActions($t)}
{@const StackActions = getStackBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
{const StackActions = $derived(getStackBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<Portal target="body">
@@ -277,7 +277,7 @@
{#if assetMultiSelectManager.selectionActive}
<div class="dark sticky top-0 z-1">
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
@@ -41,7 +41,7 @@
{#if assetMultiSelectManager.selectionActive}
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
@@ -476,7 +476,7 @@
<header>
{#if assetMultiSelectManager.selectionActive}
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
@@ -148,7 +148,7 @@
<div class="flex flex-wrap gap-1 p-2 pb-8 md:px-8">
<PeopleInfiniteScroll {people} hasNextPage={nextPage !== null} {loadNextPage}>
{#snippet children({ person })}
{@const hidden = overrides.get(person.id) ?? person.isHidden}
{const hidden = $derived(overrides.get(person.id) ?? person.isHidden)}
<button
type="button"
class="group relative size-full"
@@ -123,8 +123,8 @@
{#if assetMultiSelectManager.selectionActive}
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{@const StackActions = getStackBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
{const StackActions = $derived(getStackBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
@@ -39,7 +39,7 @@
{#if !isCollapsed}
<div class="flex flex-row flex-wrap gap-4">
{#each places as item (item.id)}
{@const city = item.exifInfo?.city}
{const city = item.exifInfo?.city}
<a class="relative" href={Route.search({ city })} draggable="false">
<div
class="flex w-[calc((100vw-(72px+5rem))/2)] max-w-39 justify-center overflow-hidden rounded-xl brightness-75 filter"
@@ -98,8 +98,8 @@
{#if assetMultiSelectManager.selectionActive}
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{@const StackActions = getStackBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
{const StackActions = $derived(getStackBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
@@ -259,7 +259,7 @@
<section id="search-chips" class="mx-auto mt-24 w-full max-w-7xl px-4 sm:px-8 lg:px-12">
<div class="flex w-full flex-wrap place-content-center place-items-center gap-2.5 sm:gap-3">
{#each searchTermKeys as searchKey (searchKey)}
{@const value = terms[searchKey]}
{const value = terms[searchKey]}
<div
class="inline-flex max-w-full items-center rounded-full bg-primary/10 py-1 ps-1 pe-1 text-xs text-primary ring-1 ring-primary/15 transition-shadow hover:ring-primary/25 dark:bg-immich-dark-primary/15 dark:text-immich-dark-primary dark:ring-immich-dark-primary/20 dark:hover:ring-immich-dark-primary/30"
>
@@ -344,7 +344,7 @@
{#if assetMultiSelectManager.selectionActive}
<div class="fixed inset-s-0 top-0 z-2 w-full">
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
@@ -120,7 +120,7 @@
{#if assetMultiSelectManager.selectionActive}
<div class="fixed inset-s-0 top-0 w-full">
<AssetSelectControlBar>
{@const Actions = getAssetBulkActions($t)}
{const Actions = $derived(getAssetBulkActions($t))}
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
<ActionButton action={Actions.CreateSharedLink} />
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
@@ -251,10 +251,12 @@
<Card class="mt-4">
<CardBody>
{#each users as user, index (user.id)}
{@const { ManageAccess } = getPeopleUserActions($t, [
user,
...users.filter(({ id }) => id !== authManager.user.id && id !== user.id),
])}
{const { ManageAccess } = $derived(
getPeopleUserActions($t, [
user,
...users.filter(({ id }) => id !== authManager.user.id && id !== user.id),
]),
)}
<div class="flex items-center justify-between gap-4" class:mt-4={index > 0}>
<div class="flex items-center gap-4">
<UserAvatar {user} size="md" />
@@ -300,7 +302,7 @@
{/each}
{#each sentRequests as request, index (request.id)}
{@const user = candidates[request.userId]}
{const user = $derived(candidates[request.userId])}
<div
class="flex items-center justify-between gap-4"
class:mt-4={index > 0 || receivedRequests.length > 0}
@@ -39,7 +39,7 @@
<TableBody>
{#each keys as key (key.id)}
{@const { Update, Rotate, Delete } = getApiKeyActions($t, key)}
{const { Update, Rotate, Delete } = $derived(getApiKeyActions($t, key))}
<TableRow>
<TableCell>{key.name}</TableCell>
<TableCell>
@@ -39,7 +39,7 @@
<TableBody>
{#each passkeys as passkey (passkey.id)}
{@const { Update, Delete } = getPasskeyActions($t, passkey)}
{const { Update, Delete } = $derived(getPasskeyActions($t, passkey))}
<TableRow>
<TableCell>{passkey.name ?? $t('passkeys', { values: { count: 1 } })}</TableCell>
<TableCell>{new Date(passkey.createdAt).toLocaleDateString($locale, dateFormats.settings)}</TableCell>
+1 -1
View File
@@ -61,7 +61,7 @@
{:else}
<div class="my-6 flex flex-col gap-3">
{#each workflows as workflow (workflow.id)}
{@const { ToggleEnabled, Duplicate, Logs, Edit, Delete } = getWorkflowActions($t, workflow)}
{const { ToggleEnabled, Duplicate, Logs, Edit, Delete } = $derived(getWorkflowActions($t, workflow))}
<Card class="group shadow-none transition-colors hover:border-primary">
<CardHeader>
@@ -40,7 +40,7 @@
<Link href={Route.viewUser(owner)}>{owner.name}</Link>
</TableCell>
{#if stats}
{@const [diskUsage, diskUsageUnit] = getBytesWithUnit(stats.usage, 0)}
{const [diskUsage, diskUsageUnit] = $derived(getBytesWithUnit(stats.usage, 0))}
<TableCell class={libraryTableClasses.column3}>
{stats.photos.toLocaleString($locale)}
</TableCell>
@@ -63,7 +63,7 @@
<table class="w-full">
<tbody>
{#each library.importPaths as folder (folder)}
{@const { Edit, Delete } = getLibraryFolderActions($t, library, folder)}
{const { Edit, Delete } = $derived(getLibraryFolderActions($t, library, folder))}
<tr class="h-12">
<td>
<Code>{folder}</Code>
@@ -83,7 +83,7 @@
<table class="w-full">
<tbody>
{#each library.exclusionPatterns as exclusionPattern (exclusionPattern)}
{@const { Edit, Delete } = getLibraryExclusionPatternActions($t, library, exclusionPattern)}
{const { Edit, Delete } = $derived(getLibraryExclusionPatternActions($t, library, exclusionPattern))}
<tr class="h-12">
<td>
<Code>{exclusionPattern}</Code>
+2 -4
View File
@@ -86,8 +86,8 @@
{/if}
{#if description}
{@const SvelteComponent = description}
<div class="text-sm dark:text-white">
{const SvelteComponent = $derived(description)}
<SvelteComponent />
</div>
{/if}
@@ -139,10 +139,8 @@
</QueueCardButton>
{/if}
{#if queue.isPaused}
{@const size = waitingCount > 0 ? '24' : '48'}
<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} />
<Icon icon={mdiFastForward} size={waitingCount > 0 ? '24' : '48'} />
<span>{$t('resume')}</span>
</QueueCardButton>
{:else}
@@ -127,7 +127,7 @@
<div class="mt-10 flex flex-col gap-7">
{#each queueList as [queueName, props] (queueName)}
{@const queue = queues.find(({ name }) => name === queueName)}
{const queue = $derived(queues.find(({ name }) => name === queueName))}
{#if queue}
<QueueCard {queue} onCommand={(command) => handleCommand(queueName, command)} {...props} />
{/if}
@@ -100,7 +100,7 @@
<div class="relative flex text-center font-mono text-2xl font-medium">
{#if stats}
{@const storageUsageWithUnit = getStorageUsageWithUnit(stats.usage)}
{const storageUsageWithUnit = $derived(getStorageUsageWithUnit(stats.usage))}
<span class="text-light-300">{zeros(storageUsageWithUnit[0])}</span><span class="text-primary"
>{storageUsageWithUnit[0]}</span
>
@@ -130,7 +130,7 @@
{#each users as user (user.id)}
<TableRow>
<TableCell class="w-1/4">{user.name}</TableCell>
{@const userStats = getUserStats(user.id)}
{const userStats = $derived(getUserStats(user.id))}
{#if userStats}
<TableCell class="w-1/4">
{userStats.photos.toLocaleString($locale)} (<FormatBytes bytes={userStats.usagePhotos} />)</TableCell