mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat(web) dark mode (#867)
This commit is contained in:
		@@ -59,15 +59,15 @@ input:focus-visible {
 | 
			
		||||
 | 
			
		||||
@layer utilities {
 | 
			
		||||
	.immich-form-input {
 | 
			
		||||
		@apply bg-slate-100 p-2 rounded-md focus:border-immich-primary text-sm;
 | 
			
		||||
		@apply bg-slate-100 p-2 rounded-md dark:text-immich-dark-bg focus:border-immich-primary text-sm;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.immich-form-label {
 | 
			
		||||
		@apply font-medium text-sm text-gray-500;
 | 
			
		||||
		@apply font-medium text-sm text-gray-500 dark:text-gray-300;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.immich-btn-primary {
 | 
			
		||||
		@apply bg-immich-primary text-gray-100 border rounded-xl py-2 px-4 transition-all duration-150 hover:bg-immich-primary hover:shadow-lg text-sm font-medium;
 | 
			
		||||
		@apply bg-immich-primary dark:bg-immich-dark-primary dark:text-immich-dark-gray text-gray-100 border dark:border-immich-dark-gray rounded-xl py-2 px-4 transition-all duration-150 hover:bg-immich-primary dark:hover:bg-immich-dark-primary/90 hover:shadow-lg text-sm font-medium;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.immich-text-button {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<html lang="en" class="dark">
 | 
			
		||||
	<head>
 | 
			
		||||
		<meta charset="utf-8" />
 | 
			
		||||
		<link rel="icon" href="%sveltekit.assets%/favicon.png" />
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
		%sveltekit.head%
 | 
			
		||||
	</head>
 | 
			
		||||
 | 
			
		||||
	<body>
 | 
			
		||||
	<body class="bg-immich-bg dark:bg-immich-dark-bg">
 | 
			
		||||
		<div>%sveltekit.body%</div>
 | 
			
		||||
	</body>
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,17 +11,17 @@
 | 
			
		||||
	const dispatch = createEventDispatcher();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="flex border-b pb-5">
 | 
			
		||||
<div class="flex border-b pb-5 dark:border-b-immich-dark-gray">
 | 
			
		||||
	<div class="w-[70%]">
 | 
			
		||||
		<h1 class="text-immich-primary text-sm">{title.toUpperCase()}</h1>
 | 
			
		||||
		<p class="text-sm mt-1">{subtitle}</p>
 | 
			
		||||
		<p class="text-sm">
 | 
			
		||||
		<h1 class="text-immich-primary dark:text-immich-dark-primary text-sm">{title.toUpperCase()}</h1>
 | 
			
		||||
		<p class="text-sm mt-1 dark:text-immich-dark-fg">{subtitle}</p>
 | 
			
		||||
		<p class="text-sm dark:text-immich-dark-fg">
 | 
			
		||||
			<slot />
 | 
			
		||||
		</p>
 | 
			
		||||
		<table class="text-left w-full mt-5">
 | 
			
		||||
			<!-- table header -->
 | 
			
		||||
			<thead
 | 
			
		||||
				class="border rounded-md mb-2 bg-immich-primary/10 flex text-immich-primary w-full h-12"
 | 
			
		||||
				class="border rounded-md mb-2 dark:bg-immich-dark-gray dark:border-immich-dark-gray bg-immich-primary/10 flex text-immich-primary dark:text-immich-dark-primary w-full h-12"
 | 
			
		||||
			>
 | 
			
		||||
				<tr class="flex w-full place-items-center">
 | 
			
		||||
					<th class="text-center w-1/3 font-medium text-sm">Status</th>
 | 
			
		||||
@@ -29,8 +29,10 @@
 | 
			
		||||
					<th class="text-center w-1/3 font-medium text-sm">Waiting</th>
 | 
			
		||||
				</tr>
 | 
			
		||||
			</thead>
 | 
			
		||||
			<tbody class="overflow-y-auto rounded-md w-full max-h-[320px] block border bg-white">
 | 
			
		||||
				<tr class="text-center flex place-items-center w-full h-[40px]">
 | 
			
		||||
			<tbody
 | 
			
		||||
				class="overflow-y-auto rounded-md w-full max-h-[320px] block border bg-white dark:border-immich-dark-gray dark:bg-[#e5e5e5] dark:text-immich-dark-bg"
 | 
			
		||||
			>
 | 
			
		||||
				<tr class="text-center flex place-items-center w-full h-[60px]">
 | 
			
		||||
					<td class="text-sm px-2 w-1/3 text-ellipsis">{jobStatus ? 'Active' : 'Idle'}</td>
 | 
			
		||||
					<td class="text-sm px-2 w-1/3 text-ellipsis">{activeJobCount}</td>
 | 
			
		||||
					<td class="text-sm px-2 w-1/3 text-ellipsis">{waitingJobCount}</td>
 | 
			
		||||
@@ -41,7 +43,7 @@
 | 
			
		||||
	<div class="w-[30%] flex place-items-center place-content-end">
 | 
			
		||||
		<button
 | 
			
		||||
			on:click={() => dispatch('click')}
 | 
			
		||||
			class="px-6 py-3 text-sm bg-immich-primary font-medium rounded-2xl hover:bg-immich-primary/50 transition-all hover:cursor-pointer disabled:cursor-not-allowed shadow-sm text-immich-bg"
 | 
			
		||||
			class="px-6 py-3 text-sm bg-immich-primary dark:bg-immich-dark-primary font-medium rounded-2xl hover:bg-immich-primary/50 transition-all hover:cursor-pointer disabled:cursor-not-allowed shadow-sm text-immich-bg dark:text-immich-dark-gray"
 | 
			
		||||
			disabled={jobStatus}
 | 
			
		||||
		>
 | 
			
		||||
			{#if jobStatus}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
<div class="flex flex-col gap-5">
 | 
			
		||||
	<div>
 | 
			
		||||
		<p class="text-sm">TOTAL USAGE</p>
 | 
			
		||||
		<p class="text-sm dark:text-immich-dark-fg">TOTAL USAGE</p>
 | 
			
		||||
 | 
			
		||||
		<div class="flex mt-5 justify-between">
 | 
			
		||||
			<StatsCard logo={CameraIris} title={'PHOTOS'} value={stats.photos.toString()} />
 | 
			
		||||
@@ -33,9 +33,11 @@
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div>
 | 
			
		||||
		<p class="text-sm">USER USAGE DETAIL</p>
 | 
			
		||||
		<p class="text-sm dark:text-immich-dark-fg">USER USAGE DETAIL</p>
 | 
			
		||||
		<table class="text-left w-full mt-5">
 | 
			
		||||
			<thead class="border rounded-md mb-4 bg-gray-50 flex text-immich-primary w-full h-12">
 | 
			
		||||
			<thead
 | 
			
		||||
				class="border rounded-md mb-4 bg-gray-50 dark:bg-immich-dark-gray dark:border-immich-dark-gray flex text-immich-primary dark:text-immich-dark-primary  w-full h-12"
 | 
			
		||||
			>
 | 
			
		||||
				<tr class="flex w-full place-items-center">
 | 
			
		||||
					<th class="text-center w-1/5 font-medium text-sm">User</th>
 | 
			
		||||
					<th class="text-center w-1/5 font-medium text-sm">Photos</th>
 | 
			
		||||
@@ -44,11 +46,13 @@
 | 
			
		||||
					<th class="text-center w-1/5 font-medium text-sm">Size</th>
 | 
			
		||||
				</tr>
 | 
			
		||||
			</thead>
 | 
			
		||||
			<tbody class="overflow-y-auto rounded-md w-full max-h-[320px] block border">
 | 
			
		||||
			<tbody
 | 
			
		||||
				class="overflow-y-auto rounded-md w-full max-h-[320px] block border dark:border-immich-dark-gray dark:text-immich-dark-bg"
 | 
			
		||||
			>
 | 
			
		||||
				{#each stats.usageByUser as user, i}
 | 
			
		||||
					<tr
 | 
			
		||||
						class={`text-center flex place-items-center w-full h-[50px] ${
 | 
			
		||||
							i % 2 == 0 ? 'bg-immich-gray' : 'bg-immich-bg'
 | 
			
		||||
							i % 2 == 0 ? 'bg-immich-gray dark:bg-[#e5e5e5]' : 'bg-immich-bg dark:bg-[#eeeeee]'
 | 
			
		||||
						}`}
 | 
			
		||||
					>
 | 
			
		||||
						<td class="text-sm px-2 w-1/5 text-ellipsis">{getFullName(user.userId)}</td>
 | 
			
		||||
 
 | 
			
		||||
@@ -17,15 +17,17 @@
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="w-[180px] h-[140px] bg-immich-gray rounded-3xl p-5 flex flex-col justify-between">
 | 
			
		||||
	<div class="flex place-items-center gap-4">
 | 
			
		||||
		<svelte:component this={logo} size="40" color={'#4250af'} />
 | 
			
		||||
		<p class="text-immich-primary">{title}</p>
 | 
			
		||||
<div
 | 
			
		||||
	class="w-[180px] h-[140px] bg-immich-gray dark:bg-immich-dark-gray rounded-3xl p-5 flex flex-col justify-between"
 | 
			
		||||
>
 | 
			
		||||
	<div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
 | 
			
		||||
		<svelte:component this={logo} size="40" />
 | 
			
		||||
		<p>{title}</p>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class="relative text-center font-mono font-semibold text-2xl">
 | 
			
		||||
		<span class="text-[#DCDADA]">{zeros()}</span><span class="text-immich-primary"
 | 
			
		||||
			>{parseInt(value)}</span
 | 
			
		||||
		<span class="text-[#DCDADA] dark:text-[#525252]">{zeros()}</span><span
 | 
			
		||||
			class="text-immich-primary dark:text-immich-dark-primary">{parseInt(value)}</span
 | 
			
		||||
		>
 | 
			
		||||
		{#if unit}
 | 
			
		||||
			<span class="absolute -top-5 right-2 text-base font-light text-gray-400">{unit}</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,9 @@
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<table class="text-left w-full my-5">
 | 
			
		||||
	<thead class="border rounded-md mb-4 bg-gray-50 flex text-immich-primary w-full h-12 ">
 | 
			
		||||
	<thead
 | 
			
		||||
		class="border rounded-md mb-4 bg-gray-50 flex text-immich-primary w-full h-12 dark:bg-immich-dark-gray dark:text-immich-dark-primary dark:border-immich-dark-gray"
 | 
			
		||||
	>
 | 
			
		||||
		<tr class="flex w-full place-items-center">
 | 
			
		||||
			<th class="text-center w-1/4 font-medium text-sm">Email</th>
 | 
			
		||||
			<th class="text-center w-1/4 font-medium text-sm">First name</th>
 | 
			
		||||
@@ -17,11 +19,13 @@
 | 
			
		||||
			<th class="text-center w-1/4 font-medium text-sm">Edit</th>
 | 
			
		||||
		</tr>
 | 
			
		||||
	</thead>
 | 
			
		||||
	<tbody class="overflow-y-auto rounded-md w-full max-h-[320px] block border">
 | 
			
		||||
	<tbody
 | 
			
		||||
		class="overflow-y-auto rounded-md w-full max-h-[320px] block border dark:border-immich-dark-gray"
 | 
			
		||||
	>
 | 
			
		||||
		{#each allUsers as user, i}
 | 
			
		||||
			<tr
 | 
			
		||||
				class={`text-center flex place-items-center w-full h-[80px] ${
 | 
			
		||||
					i % 2 == 0 ? 'bg-gray-100' : 'bg-immich-bg'
 | 
			
		||||
				class={`text-center flex place-items-center w-full h-[80px] dark:text-immich-dark-bg ${
 | 
			
		||||
					i % 2 == 0 ? 'bg-immich-gray dark:bg-[#e5e5e5]' : 'bg-immich-bg dark:bg-[#eeeeee]'
 | 
			
		||||
				}`}
 | 
			
		||||
			>
 | 
			
		||||
				<td class="text-sm px-4 w-1/4 text-ellipsis">{user.email}</td>
 | 
			
		||||
@@ -32,7 +36,7 @@
 | 
			
		||||
						on:click={() => {
 | 
			
		||||
							dispatch('edit-user', { user });
 | 
			
		||||
						}}
 | 
			
		||||
						class="bg-immich-primary text-gray-100 rounded-full p-3 transition-all duration-150 hover:bg-immich-primary/75"
 | 
			
		||||
						class="bg-immich-primary dark:bg-immich-dark-primary text-gray-100 dark:text-gray-700  rounded-full p-3 transition-all duration-150 hover:bg-immich-primary/75"
 | 
			
		||||
						><PencilOutline size="20" /></button
 | 
			
		||||
					></td
 | 
			
		||||
				>
 | 
			
		||||
 
 | 
			
		||||
@@ -60,12 +60,7 @@
 | 
			
		||||
		on:click|stopPropagation|preventDefault={showAlbumContextMenu}
 | 
			
		||||
		data-testid="context-button-parent"
 | 
			
		||||
	>
 | 
			
		||||
		<CircleIconButton
 | 
			
		||||
			logo={DotsVertical}
 | 
			
		||||
			size={'20'}
 | 
			
		||||
			hoverColor={'rgba(95,99,104, 0.5)'}
 | 
			
		||||
			logoColor={'#fdf8ec'}
 | 
			
		||||
		/>
 | 
			
		||||
		<CircleIconButton logo={DotsVertical} size={'20'} hoverColor={'rgba(95,99,104, 0.5)'} />
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class={`h-[275px] w-[275px] z-[-1]`}>
 | 
			
		||||
@@ -78,11 +73,14 @@
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class="mt-4">
 | 
			
		||||
		<p class="text-sm font-medium text-gray-800" data-testid="album-name">
 | 
			
		||||
		<p
 | 
			
		||||
			class="text-sm font-medium text-gray-800 dark:text-immich-dark-primary"
 | 
			
		||||
			data-testid="album-name"
 | 
			
		||||
		>
 | 
			
		||||
			{album.albumName}
 | 
			
		||||
		</p>
 | 
			
		||||
 | 
			
		||||
		<span class="text-xs flex gap-2" data-testid="album-details">
 | 
			
		||||
		<span class="text-xs flex gap-2 dark:text-immich-dark-fg" data-testid="album-details">
 | 
			
		||||
			<p>{album.assetCount} items</p>
 | 
			
		||||
 | 
			
		||||
			{#if album.shared}
 | 
			
		||||
 
 | 
			
		||||
@@ -331,7 +331,7 @@
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<section class="bg-immich-bg">
 | 
			
		||||
<section class="bg-immich-bg dark:bg-immich-dark-bg">
 | 
			
		||||
	<!-- Multiselection mode app bar -->
 | 
			
		||||
	{#if isMultiSelectionMode}
 | 
			
		||||
		<ControlAppBar
 | 
			
		||||
@@ -340,7 +340,9 @@
 | 
			
		||||
			tailwindClasses={'bg-white shadow-md'}
 | 
			
		||||
		>
 | 
			
		||||
			<svelte:fragment slot="leading">
 | 
			
		||||
				<p class="font-medium text-immich-primary">Selected {multiSelectAsset.size}</p>
 | 
			
		||||
				<p class="font-medium text-immich-primary dark:text-immich-dark-primary">
 | 
			
		||||
					Selected {multiSelectAsset.size}
 | 
			
		||||
				</p>
 | 
			
		||||
			</svelte:fragment>
 | 
			
		||||
			<svelte:fragment slot="trailing">
 | 
			
		||||
				{#if isOwned}
 | 
			
		||||
@@ -386,7 +388,7 @@
 | 
			
		||||
					<button
 | 
			
		||||
						disabled={album.assetCount == 0}
 | 
			
		||||
						on:click={() => (isShowShareUserSelection = true)}
 | 
			
		||||
						class="immich-text-button border bg-immich-primary text-gray-50 hover:bg-immich-primary/75 px-6 text-sm disabled:opacity-25 disabled:bg-gray-500 disabled:cursor-not-allowed"
 | 
			
		||||
						class="immich-text-button border bg-immich-primary dark:bg-immich-dark-primary text-gray-50 hover:bg-immich-primary/75 px-6 text-sm disabled:opacity-25 disabled:bg-gray-500 disabled:cursor-not-allowed dark:text-immich-dark-bg dark:border-immich-dark-gray"
 | 
			
		||||
						><span class="px-2">Share</span></button
 | 
			
		||||
					>
 | 
			
		||||
				{/if}
 | 
			
		||||
@@ -404,9 +406,9 @@
 | 
			
		||||
			}}
 | 
			
		||||
			on:focus={() => (isEditingTitle = true)}
 | 
			
		||||
			on:blur={() => (isEditingTitle = false)}
 | 
			
		||||
			class={`transition-all text-6xl text-immich-primary w-[99%] border-b-2 border-transparent outline-none ${
 | 
			
		||||
			class={`transition-all text-6xl text-immich-primary dark:text-immich-dark-primary w-[99%] border-b-2 border-transparent outline-none ${
 | 
			
		||||
				isOwned ? 'hover:border-gray-400' : 'hover:border-transparent'
 | 
			
		||||
			} focus:outline-none focus:border-b-2 focus:border-immich-primary bg-immich-bg`}
 | 
			
		||||
			} focus:outline-none focus:border-b-2 focus:border-immich-primary dark:focus:border-immich-dark-primary bg-immich-bg dark:bg-immich-dark-bg dark:focus:bg-immich-dark-gray`}
 | 
			
		||||
			type="text"
 | 
			
		||||
			bind:value={album.albumName}
 | 
			
		||||
			disabled={!isOwned}
 | 
			
		||||
@@ -468,13 +470,15 @@
 | 
			
		||||
			<!-- Album is empty - Show asset selectection buttons -->
 | 
			
		||||
			<section id="empty-album" class=" mt-[200px] flex place-content-center place-items-center">
 | 
			
		||||
				<div class="w-[300px]">
 | 
			
		||||
					<p class="text-xs">ADD PHOTOS</p>
 | 
			
		||||
					<p class="text-xs dark:text-immich-dark-fg">ADD PHOTOS</p>
 | 
			
		||||
					<button
 | 
			
		||||
						on:click={() => (isShowAssetSelection = true)}
 | 
			
		||||
						class="w-full py-8 border bg-white rounded-md mt-5 flex place-items-center gap-6 px-8 transition-all hover:bg-gray-100 hover:text-immich-primary"
 | 
			
		||||
						class="w-full py-8 border bg-immich-bg dark:bg-immich-dark-gray text-immich-fg dark:text-immich-dark-fg dark:hover:text-immich-dark-primary rounded-md mt-5 flex place-items-center gap-6 px-8 transition-all hover:bg-gray-100 hover:text-immich-primary dark:border-none"
 | 
			
		||||
					>
 | 
			
		||||
						<span><Plus color="#4250af" size="24" /> </span>
 | 
			
		||||
						<span class="text-lg text-immich-fg">Select photos</span>
 | 
			
		||||
						<span class="text-text-immich-primary dark:text-immich-dark-primary"
 | 
			
		||||
							><Plus size="24" />
 | 
			
		||||
						</span>
 | 
			
		||||
						<span class="text-lg">Select photos</span>
 | 
			
		||||
					</button>
 | 
			
		||||
				</div>
 | 
			
		||||
			</section>
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,7 @@
 | 
			
		||||
 | 
			
		||||
<section
 | 
			
		||||
	transition:fly={{ y: 500, duration: 100, easing: quintOut }}
 | 
			
		||||
	class="absolute top-0 left-0 w-full h-full  bg-immich-bg z-[9999]"
 | 
			
		||||
	class="absolute top-0 left-0 w-full h-full bg-immich-bg dark:bg-immich-dark-bg z-[9999]"
 | 
			
		||||
>
 | 
			
		||||
	<ControlAppBar
 | 
			
		||||
		on:close-button-click={() => {
 | 
			
		||||
@@ -80,28 +80,28 @@
 | 
			
		||||
	>
 | 
			
		||||
		<svelte:fragment slot="leading">
 | 
			
		||||
			{#if $selectedAssets.size == 0}
 | 
			
		||||
				<p class="text-lg">Add to album</p>
 | 
			
		||||
				<p class="text-lg dark:text-immich-dark-fg">Add to album</p>
 | 
			
		||||
			{:else}
 | 
			
		||||
				<p class="text-lg">{$selectedAssets.size} selected</p>
 | 
			
		||||
				<p class="text-lg dark:text-immich-dark-fg">{$selectedAssets.size} selected</p>
 | 
			
		||||
			{/if}
 | 
			
		||||
		</svelte:fragment>
 | 
			
		||||
 | 
			
		||||
		<svelte:fragment slot="trailing">
 | 
			
		||||
			<button
 | 
			
		||||
				on:click={() => openFileUploadDialog(UploadType.ALBUM)}
 | 
			
		||||
				class="text-immich-primary text-sm hover:bg-immich-primary/10 transition-all px-6 py-2 rounded-lg font-medium"
 | 
			
		||||
				class="text-immich-primary dark:text-immich-dark-primary text-sm hover:bg-immich-primary/10 dark:hover:bg-immich-dark-primary/25 transition-all px-6 py-2 rounded-lg font-medium"
 | 
			
		||||
			>
 | 
			
		||||
				Select from computer
 | 
			
		||||
			</button>
 | 
			
		||||
			<button
 | 
			
		||||
				disabled={$selectedAssets.size === 0}
 | 
			
		||||
				on:click={addSelectedAssets}
 | 
			
		||||
				class="immich-text-button border bg-immich-primary text-gray-50 hover:bg-immich-primary/75 px-6 text-sm disabled:opacity-25 disabled:bg-gray-500 disabled:cursor-not-allowed"
 | 
			
		||||
				class="immich-text-button border bg-immich-primary dark:bg-immich-dark-primary text-gray-50 hover:bg-immich-primary/75 px-6 text-sm disabled:opacity-25 disabled:bg-gray-500 disabled:cursor-not-allowed dark:text-immich-dark-bg dark:border-immich-dark-gray"
 | 
			
		||||
				><span class="px-2">Done</span></button
 | 
			
		||||
			>
 | 
			
		||||
		</svelte:fragment>
 | 
			
		||||
	</ControlAppBar>
 | 
			
		||||
	<section class="pt-[100px] pl-[70px] grid h-screen bg-immich-bg">
 | 
			
		||||
	<section class="pt-[100px] pl-[70px] grid h-screen bg-immich-bg dark:bg-immich-dark-bg">
 | 
			
		||||
		<AssetGrid isAlbumSelectionMode={true} />
 | 
			
		||||
	</section>
 | 
			
		||||
</section>
 | 
			
		||||
 
 | 
			
		||||
@@ -68,14 +68,14 @@
 | 
			
		||||
<BaseModal on:close={() => dispatch('close')}>
 | 
			
		||||
	<svelte:fragment slot="title">
 | 
			
		||||
		<span class="flex gap-2 place-items-center">
 | 
			
		||||
			<p class="font-medium text-immich-fg">Options</p>
 | 
			
		||||
			<p class="font-medium text-immich-fg dark:text-immich-dark-fg">Options</p>
 | 
			
		||||
		</span>
 | 
			
		||||
	</svelte:fragment>
 | 
			
		||||
 | 
			
		||||
	<section class="max-h-[400px] overflow-y-auto immich-scrollbar pb-4">
 | 
			
		||||
		{#each album.sharedUsers as user}
 | 
			
		||||
			<div
 | 
			
		||||
				class="flex gap-4 p-5 place-items-center justify-between w-full transition-colors hover:bg-gray-50"
 | 
			
		||||
				class="flex gap-4 p-5 place-items-center justify-between w-full transition-colors hover:bg-gray-50 dark:hover:bg-gray-700"
 | 
			
		||||
			>
 | 
			
		||||
				<div class="flex gap-4 place-items-center">
 | 
			
		||||
					<CircleAvatar {user} />
 | 
			
		||||
@@ -88,14 +88,13 @@
 | 
			
		||||
							on:click={() => showContextMenu(user.id)}
 | 
			
		||||
							logo={DotsVertical}
 | 
			
		||||
							backgroundColor={'transparent'}
 | 
			
		||||
							logoColor={'#5f6368'}
 | 
			
		||||
							hoverColor={'#e2e7e9'}
 | 
			
		||||
							size={'20'}
 | 
			
		||||
						/>
 | 
			
		||||
					{:else if user.id == currentUser?.id}
 | 
			
		||||
						<button
 | 
			
		||||
							on:click={() => removeUser('me')}
 | 
			
		||||
							class="text-sm text-immich-primary font-medium transition-colors hover:text-immich-primary/75"
 | 
			
		||||
							class="text-sm text-immich-primary dark:text-immich-dark-primary font-medium transition-colors hover:text-immich-primary/75"
 | 
			
		||||
							>Leave</button
 | 
			
		||||
						>
 | 
			
		||||
					{/if}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
	<svelte:fragment slot="title">
 | 
			
		||||
		<span class="flex gap-2 place-items-center">
 | 
			
		||||
			<img src="/immich-logo.svg" width="24" alt="Immich" />
 | 
			
		||||
			<p class="font-medium text-immich-fg">Invite to album</p>
 | 
			
		||||
			<p class="font-medium">Invite to album</p>
 | 
			
		||||
		</span>
 | 
			
		||||
	</svelte:fragment>
 | 
			
		||||
 | 
			
		||||
@@ -51,7 +51,7 @@
 | 
			
		||||
					{#key user.id}
 | 
			
		||||
						<button
 | 
			
		||||
							on:click={() => deselectUser(user)}
 | 
			
		||||
							class="flex gap-1 place-items-center border border-gray-400 rounded-full p-1 hover:bg-gray-200 transition-colors"
 | 
			
		||||
							class="flex gap-1 place-items-center border border-gray-400 rounded-full p-1 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
 | 
			
		||||
						>
 | 
			
		||||
							<CircleAvatar size={28} {user} />
 | 
			
		||||
							<p class="text-xs font-medium">{user.firstName} {user.lastName}</p>
 | 
			
		||||
@@ -68,11 +68,11 @@
 | 
			
		||||
				{#each users as user}
 | 
			
		||||
					<button
 | 
			
		||||
						on:click={() => selectUser(user)}
 | 
			
		||||
						class="w-full flex place-items-center gap-4 py-4 px-5 hover:bg-gray-200  transition-all"
 | 
			
		||||
						class="w-full flex place-items-center gap-4 py-4 px-5 hover:bg-gray-200 dark:hover:bg-gray-700 transition-all"
 | 
			
		||||
					>
 | 
			
		||||
						{#if selectedUsers.includes(user)}
 | 
			
		||||
							<span
 | 
			
		||||
								class="bg-immich-primary text-white rounded-full w-12 h-12 border flex place-items-center place-content-center text-3xl"
 | 
			
		||||
								class="bg-immich-primary dark:bg-immich-dark-primary text-white dark:text-immich-dark-bg rounded-full w-12 h-12 border flex place-items-center place-content-center text-3xl dark:border-immich-dark-gray"
 | 
			
		||||
								>✓</span
 | 
			
		||||
							>
 | 
			
		||||
						{:else}
 | 
			
		||||
@@ -80,7 +80,7 @@
 | 
			
		||||
						{/if}
 | 
			
		||||
 | 
			
		||||
						<div class="text-left">
 | 
			
		||||
							<p class="text-immich-fg">
 | 
			
		||||
							<p class="text-immich-fg dark:text-immich-dark-fg">
 | 
			
		||||
								{user.firstName}
 | 
			
		||||
								{user.lastName}
 | 
			
		||||
							</p>
 | 
			
		||||
 
 | 
			
		||||
@@ -207,7 +207,7 @@
 | 
			
		||||
		<div
 | 
			
		||||
			transition:fly={{ duration: 150 }}
 | 
			
		||||
			id="detail-panel"
 | 
			
		||||
			class="bg-immich-bg w-[360px] row-span-full transition-all overflow-y-auto"
 | 
			
		||||
			class="bg-immich-bg w-[360px] row-span-full transition-all overflow-y-auto dark:bg-immich-dark-bg dark:border-l dark:border-l-immich-dark-gray"
 | 
			
		||||
			translate="yes"
 | 
			
		||||
		>
 | 
			
		||||
			<DetailPanel {asset} albums={appearsInAlbums} on:close={() => (isShowDetail = false)} />
 | 
			
		||||
 
 | 
			
		||||
@@ -97,16 +97,16 @@
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<section class="p-2">
 | 
			
		||||
<section class="p-2 dark:bg-immich-dark-bg dark:text-immich-dark-fg">
 | 
			
		||||
	<div class="flex place-items-center gap-2">
 | 
			
		||||
		<button
 | 
			
		||||
			class="rounded-full p-3 flex place-items-center place-content-center hover:bg-gray-200 transition-colors"
 | 
			
		||||
			class="rounded-full p-3 flex place-items-center place-content-center hover:bg-gray-200 transition-colors dark:text-immich-dark-fg dark:hover:bg-gray-900"
 | 
			
		||||
			on:click={() => dispatch('close')}
 | 
			
		||||
		>
 | 
			
		||||
			<Close size="24" color="#232323" />
 | 
			
		||||
			<Close size="24" />
 | 
			
		||||
		</button>
 | 
			
		||||
 | 
			
		||||
		<p class="text-immich-fg text-lg">Info</p>
 | 
			
		||||
		<p class="text-immich-fg dark:text-immich-dark-fg text-lg">Info</p>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class="px-4 py-4">
 | 
			
		||||
@@ -202,7 +202,7 @@
 | 
			
		||||
	<div class="h-[360px] w-full" id="map" />
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<section class="p-2">
 | 
			
		||||
<section class="p-2 dark:text-immich-dark-fg">
 | 
			
		||||
	<div class="px-4 py-4">
 | 
			
		||||
		{#if albums.length > 0}
 | 
			
		||||
			<p class="text-sm pb-4 ">APPEARS IN</p>
 | 
			
		||||
@@ -219,7 +219,7 @@
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div class="mt-auto mb-auto">
 | 
			
		||||
						<p>{album.albumName}</p>
 | 
			
		||||
						<p class="dark:text-immich-dark-primary">{album.albumName}</p>
 | 
			
		||||
						<div class="flex gap-2 text-sm">
 | 
			
		||||
							<p>{album.assetCount} items</p>
 | 
			
		||||
							{#if album.shared}
 | 
			
		||||
 
 | 
			
		||||
@@ -51,11 +51,17 @@
 | 
			
		||||
	}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="border bg-white p-4 shadow-sm w-[500px] rounded-md py-8">
 | 
			
		||||
<div
 | 
			
		||||
	class="border bg-immich-bg dark:bg-immich-dark-gray dark:border-immich-dark-gray p-4 shadow-sm w-[500px] rounded-3xl py-8 dark:text-immich-dark-fg"
 | 
			
		||||
>
 | 
			
		||||
	<div class="flex flex-col place-items-center place-content-center gap-4 px-4">
 | 
			
		||||
		<img class="text-center" src="/immich-logo.svg" height="100" width="100" alt="immich-logo" />
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary font-medium">Admin Registration</h1>
 | 
			
		||||
		<p class="text-sm border rounded-md p-4 font-mono text-gray-600">
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary dark:text-immich-dark-primary font-medium">
 | 
			
		||||
			Admin Registration
 | 
			
		||||
		</h1>
 | 
			
		||||
		<p
 | 
			
		||||
			class="text-sm border rounded-md p-4 font-mono text-gray-600 dark:border-immich-dark-bg dark:text-gray-300"
 | 
			
		||||
		>
 | 
			
		||||
			Since you are the first user on the system, you will be assigned as the Admin and are
 | 
			
		||||
			responsible for administrative tasks, and additional users will be created by you.
 | 
			
		||||
		</p>
 | 
			
		||||
@@ -117,7 +123,7 @@
 | 
			
		||||
		<div class="flex w-full">
 | 
			
		||||
			<button
 | 
			
		||||
				type="submit"
 | 
			
		||||
				class="m-4 p-2 bg-immich-primary hover:bg-immich-primary/75 px-6 py-4 text-white rounded-md shadow-md w-full"
 | 
			
		||||
				class="m-4 p-2 bg-immich-primary dark:bg-immich-dark-primary hover:bg-immich-primary/75 dark:hover:bg-immich-dark-primary/80 dark:text-immich-dark-gray px-6 py-4 text-white rounded-md shadow-md w-full"
 | 
			
		||||
				>Sign Up</button
 | 
			
		||||
			>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -43,12 +43,18 @@
 | 
			
		||||
	}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="border bg-white p-4 shadow-sm w-[500px] rounded-md py-8">
 | 
			
		||||
<div
 | 
			
		||||
	class="border bg-immich-bg dark:bg-immich-dark-gray dark:border-immich-dark-gray p-4 shadow-sm w-[500px] rounded-3xl py-8 dark:text-immich-dark-fg"
 | 
			
		||||
>
 | 
			
		||||
	<div class="flex flex-col place-items-center place-content-center gap-4 px-4">
 | 
			
		||||
		<img class="text-center" src="/immich-logo.svg" height="100" width="100" alt="immich-logo" />
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary font-medium">Change Password</h1>
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary dark:text-immich-dark-primary font-medium">
 | 
			
		||||
			Change Password
 | 
			
		||||
		</h1>
 | 
			
		||||
 | 
			
		||||
		<p class="text-sm border rounded-md p-4 font-mono text-gray-600">
 | 
			
		||||
		<p
 | 
			
		||||
			class="text-sm border rounded-md p-4 font-mono text-gray-600 dark:border-immich-dark-bg dark:text-gray-300"
 | 
			
		||||
		>
 | 
			
		||||
			Hi {user.firstName}
 | 
			
		||||
			{user.lastName} ({user.email}),
 | 
			
		||||
			<br />
 | 
			
		||||
@@ -93,7 +99,7 @@
 | 
			
		||||
		<div class="flex w-full">
 | 
			
		||||
			<button
 | 
			
		||||
				type="submit"
 | 
			
		||||
				class="m-4 p-2 bg-immich-primary hover:bg-immich-primary/75 px-6 py-4 text-white rounded-md shadow-md w-full"
 | 
			
		||||
				class="m-4 p-2 bg-immich-primary dark:bg-immich-dark-primary hover:bg-immich-primary/75 dark:hover:bg-immich-dark-primary/80 dark:text-immich-dark-gray px-6 py-4 text-white rounded-md shadow-md w-full"
 | 
			
		||||
				>Change Password</button
 | 
			
		||||
			>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -53,11 +53,17 @@
 | 
			
		||||
	}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="border bg-white p-4 shadow-sm w-[500px] rounded-3xl py-8">
 | 
			
		||||
<div
 | 
			
		||||
	class="border bg-immich-bg dark:bg-immich-dark-gray dark:border-immich-dark-gray p-4 shadow-sm w-[500px] rounded-3xl py-8 dark:text-immich-dark-fg"
 | 
			
		||||
>
 | 
			
		||||
	<div class="flex flex-col place-items-center place-content-center gap-4 px-4">
 | 
			
		||||
		<img class="text-center" src="/immich-logo.svg" height="100" width="100" alt="immich-logo" />
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary font-medium">Create new user</h1>
 | 
			
		||||
		<p class="text-sm border rounded-md p-4 font-mono text-gray-600">
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary dark:text-immich-dark-primary font-medium">
 | 
			
		||||
			Create new user
 | 
			
		||||
		</h1>
 | 
			
		||||
		<p
 | 
			
		||||
			class="text-sm border rounded-md p-4 font-mono text-gray-600 dark:border-immich-dark-bg dark:text-gray-300"
 | 
			
		||||
		>
 | 
			
		||||
			Please provide your user with the password, they will have to change it on their first sign
 | 
			
		||||
			in.
 | 
			
		||||
		</p>
 | 
			
		||||
@@ -113,7 +119,7 @@
 | 
			
		||||
		<div class="flex w-full">
 | 
			
		||||
			<button
 | 
			
		||||
				type="submit"
 | 
			
		||||
				class="m-4 bg-immich-primary hover:bg-immich-primary/75 px-6 py-3 text-white rounded-full shadow-md w-full font-medium"
 | 
			
		||||
				class="m-4 bg-immich-primary dark:bg-immich-dark-primary hover:bg-immich-primary/75 dark:hover:bg-immich-dark-primary/80 px-6 py-3 text-white dark:text-immich-dark-gray rounded-full shadow-md w-full font-medium"
 | 
			
		||||
				>Create
 | 
			
		||||
			</button>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -65,11 +65,16 @@
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="border bg-white p-4 shadow-sm w-[500px] rounded-3xl py-8">
 | 
			
		||||
	<div class="flex flex-col place-items-center place-content-center gap-4 px-4">
 | 
			
		||||
		<!--        <img class="text-center" src="/immich-logo.svg" height="100" width="100" alt="immich-logo"/>-->
 | 
			
		||||
		<AccountEditOutline size="4em" color="#4250affe" />
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary font-medium">Edit user</h1>
 | 
			
		||||
<div
 | 
			
		||||
	class="border bg-immich-bg dark:bg-immich-dark-gray dark:border-immich-dark-gray p-4 shadow-sm w-[500px] rounded-3xl py-8 dark:text-immich-dark-fg"
 | 
			
		||||
>
 | 
			
		||||
	<div
 | 
			
		||||
		class="flex flex-col place-items-center place-content-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
 | 
			
		||||
	>
 | 
			
		||||
		<AccountEditOutline size="4em" />
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary dark:text-immich-dark-primary font-medium">
 | 
			
		||||
			Edit user
 | 
			
		||||
		</h1>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<form on:submit|preventDefault={editUser} autocomplete="off">
 | 
			
		||||
@@ -124,7 +129,7 @@
 | 
			
		||||
			</button>
 | 
			
		||||
			<button
 | 
			
		||||
				type="submit"
 | 
			
		||||
				class="flex-1 transition-colors bg-immich-primary hover:bg-immich-primary/75 px-6 py-3 text-white rounded-full shadow-md w-full font-medium"
 | 
			
		||||
				class="flex-1 transition-colors bg-immich-primary dark:bg-immich-dark-primary hover:bg-immich-primary/75 dark:hover:bg-immich-dark-primary/80 dark:text-immich-dark-gray px-6 py-3 text-white rounded-full shadow-md w-full font-medium"
 | 
			
		||||
				>Confirm
 | 
			
		||||
			</button>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -32,15 +32,17 @@
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="border bg-white p-4 shadow-sm w-[500px] rounded-md py-8">
 | 
			
		||||
<div
 | 
			
		||||
	class="border bg-white dark:bg-immich-dark-gray dark:border-immich-dark-gray p-4 shadow-sm w-[500px] rounded-md py-8"
 | 
			
		||||
>
 | 
			
		||||
	<div class="flex flex-col place-items-center place-content-center gap-4 px-4">
 | 
			
		||||
		<img class="text-center" src="/immich-logo.svg" height="100" width="100" alt="immich-logo" />
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary font-medium">Login</h1>
 | 
			
		||||
		<h1 class="text-2xl text-immich-primary dark:text-immich-dark-primary font-medium">Login</h1>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	{#if loginPageMessage}
 | 
			
		||||
		<p
 | 
			
		||||
			class="text-sm border rounded-md m-4 p-4 text-immich-primary font-medium bg-immich-primary/5"
 | 
			
		||||
			class="text-sm border rounded-md m-4 p-4 text-immich-primary dark:text-immich-dark-primary font-medium bg-immich-primary/5 dark:border-immich-dark-bg"
 | 
			
		||||
		>
 | 
			
		||||
			{@html loginPageMessage}
 | 
			
		||||
		</p>
 | 
			
		||||
@@ -78,7 +80,7 @@
 | 
			
		||||
		<div class="flex w-full">
 | 
			
		||||
			<button
 | 
			
		||||
				type="submit"
 | 
			
		||||
				class="m-4 p-2 bg-immich-primary hover:bg-immich-primary/75 px-6 py-4 text-white rounded-md shadow-md w-full font-semibold"
 | 
			
		||||
				class="m-4 p-2 bg-immich-primary dark:bg-immich-dark-primary dark:text-immich-dark-gray dark:hover:bg-immich-dark-primary/80 hover:bg-immich-primary/75 px-6 py-4 text-white rounded-md shadow-md w-full font-semibold"
 | 
			
		||||
				>Login</button
 | 
			
		||||
			>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -115,7 +115,9 @@
 | 
			
		||||
			on:mouseleave={() => (isMouseOverGroup = false)}
 | 
			
		||||
		>
 | 
			
		||||
			<!-- Date group title -->
 | 
			
		||||
			<p class="font-medium text-sm text-immich-fg mb-2 flex place-items-center h-6">
 | 
			
		||||
			<p
 | 
			
		||||
				class="font-medium text-sm text-immich-fg dark:text-immich-dark-fg mb-2 flex place-items-center h-6"
 | 
			
		||||
			>
 | 
			
		||||
				{#if (hoveredDateGroup == dateGroupTitle && isMouseOverGroup) || $selectedGroup.has(dateGroupTitle)}
 | 
			
		||||
					<div
 | 
			
		||||
						transition:fly={{ x: -24, duration: 200, opacity: 0.5 }}
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@
 | 
			
		||||
	<div
 | 
			
		||||
		use:clickOutside
 | 
			
		||||
		on:out-click={() => dispatch('close')}
 | 
			
		||||
		class="bg-white w-[450px] min-h-[200px] max-h-[500px] rounded-lg shadow-md"
 | 
			
		||||
		class="bg-immich-bg dark:bg-immich-dark-gray dark:text-immich-dark-fg w-[450px] min-h-[200px] max-h-[500px] rounded-lg shadow-md"
 | 
			
		||||
	>
 | 
			
		||||
		<div class="flex justify-between place-items-center p-5">
 | 
			
		||||
			<div>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@
 | 
			
		||||
	export let logo: any;
 | 
			
		||||
	export let backgroundColor = 'transparent';
 | 
			
		||||
	export let hoverColor = '#e2e7e9';
 | 
			
		||||
	export let logoColor = '#5f6368';
 | 
			
		||||
	export let size = '24';
 | 
			
		||||
	export let title = '';
 | 
			
		||||
	let iconButton: HTMLButtonElement;
 | 
			
		||||
@@ -26,10 +25,10 @@
 | 
			
		||||
<button
 | 
			
		||||
	{title}
 | 
			
		||||
	bind:this={iconButton}
 | 
			
		||||
	class={`immich-circle-icon-button rounded-full p-3 flex place-items-center place-content-center transition-all`}
 | 
			
		||||
	class={`immich-circle-icon-button dark:text-immich-dark-fg hover:dark:text-immich-dark-gray rounded-full p-3 flex place-items-center place-content-center transition-all`}
 | 
			
		||||
	on:click={(mouseEvent) => dispatch('click', { mouseEvent })}
 | 
			
		||||
>
 | 
			
		||||
	<svelte:component this={logo} {size} color={logoColor} />
 | 
			
		||||
	<svelte:component this={logo} {size} />
 | 
			
		||||
</button>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
<div
 | 
			
		||||
	transition:slide={{ duration: 200, easing: quintOut }}
 | 
			
		||||
	bind:this={menuEl}
 | 
			
		||||
	class="absolute bg-white w-[175px] z-[99999] rounded-lg shadow-md"
 | 
			
		||||
	class="absolute w-[175px] z-[99999] rounded-lg shadow-md"
 | 
			
		||||
	style={`top: ${y}px; left: ${x}px;`}
 | 
			
		||||
	use:clickOutside
 | 
			
		||||
	on:out-click={() => dispatch('clickoutside')}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
<button
 | 
			
		||||
	class:disabled={isDisabled}
 | 
			
		||||
	on:click={handleClick}
 | 
			
		||||
	class="bg-white hover:bg-immich-bg transition-all p-4 w-full text-left rounded-lg text-sm"
 | 
			
		||||
	class="bg-white hover:bg-gray-300 dark:text-immich-dark-bg transition-all p-4 w-full text-left rounded-lg text-sm"
 | 
			
		||||
>
 | 
			
		||||
	{#if text}
 | 
			
		||||
		{text}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
 | 
			
		||||
	const onScroll = () => {
 | 
			
		||||
		if (window.pageYOffset > 80) {
 | 
			
		||||
			appBarBorder = 'border border-gray-200 bg-gray-50';
 | 
			
		||||
			appBarBorder = 'border border-gray-200 bg-gray-50 dark:border-gray-600';
 | 
			
		||||
		} else {
 | 
			
		||||
			appBarBorder = 'bg-immich-bg border border-transparent';
 | 
			
		||||
		}
 | 
			
		||||
@@ -39,14 +39,13 @@
 | 
			
		||||
>
 | 
			
		||||
	<div
 | 
			
		||||
		id="asset-selection-app-bar"
 | 
			
		||||
		class={`flex justify-between ${appBarBorder} rounded-lg p-2 mx-2 mt-2 transition-all place-items-center ${tailwindClasses}`}
 | 
			
		||||
		class={`flex justify-between ${appBarBorder} rounded-lg p-2 mx-2 mt-2 transition-all place-items-center ${tailwindClasses} dark:bg-immich-dark-gray`}
 | 
			
		||||
	>
 | 
			
		||||
		<div class="flex place-items-center gap-6">
 | 
			
		||||
		<div class="flex place-items-center gap-6 dark:text-immich-dark-fg">
 | 
			
		||||
			<CircleIconButton
 | 
			
		||||
				on:click={() => dispatch('close-button-click')}
 | 
			
		||||
				logo={backIcon}
 | 
			
		||||
				backgroundColor={'transparent'}
 | 
			
		||||
				logoColor={'rgb(75 85 99)'}
 | 
			
		||||
				hoverColor={'#e2e7e9'}
 | 
			
		||||
				size={'24'}
 | 
			
		||||
			/>
 | 
			
		||||
 
 | 
			
		||||
@@ -136,7 +136,7 @@
 | 
			
		||||
	<div
 | 
			
		||||
		style:width={`${thumbnailSize}px`}
 | 
			
		||||
		style:height={`${thumbnailSize}px`}
 | 
			
		||||
		class={`bg-gray-100 relative select-none  ${getSize()} ${
 | 
			
		||||
		class={`bg-gray-100 dark:bg-immich-dark-gray relative select-none ${getSize()} ${
 | 
			
		||||
			disabled ? 'cursor-not-allowed' : 'hover:cursor-pointer'
 | 
			
		||||
		}`}
 | 
			
		||||
		on:mouseenter={handleMouseOverThumbnail}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
	import TrayArrowUp from 'svelte-material-icons/TrayArrowUp.svelte';
 | 
			
		||||
	import { clickOutside } from '../../utils/click-outside';
 | 
			
		||||
	import { api, UserResponseDto } from '@api';
 | 
			
		||||
	import ThemeButton from './theme-button.svelte';
 | 
			
		||||
 | 
			
		||||
	export let user: UserResponseDto;
 | 
			
		||||
	export let shouldShowUploadButton = true;
 | 
			
		||||
@@ -42,28 +43,35 @@
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<section id="dashboard-navbar" class="fixed w-screen  z-[100] bg-immich-bg text-sm">
 | 
			
		||||
	<div class="flex border-b place-items-center px-6 py-2 ">
 | 
			
		||||
<section
 | 
			
		||||
	id="dashboard-navbar"
 | 
			
		||||
	class="fixed w-screen  z-[100] bg-immich-bg dark:bg-immich-dark-bg text-sm"
 | 
			
		||||
>
 | 
			
		||||
	<div class="flex border-b dark:border-b-immich-dark-gray place-items-center px-6 py-2 ">
 | 
			
		||||
		<a
 | 
			
		||||
			data-sveltekit-prefetch
 | 
			
		||||
			class="flex gap-2 place-items-center hover:cursor-pointer"
 | 
			
		||||
			href="/photos"
 | 
			
		||||
		>
 | 
			
		||||
			<img src="/immich-logo.svg" alt="immich logo" height="35" width="35" />
 | 
			
		||||
			<h1 class="font-immich-title text-2xl text-immich-primary">IMMICH</h1>
 | 
			
		||||
			<h1 class="font-immich-title text-2xl text-immich-primary dark:text-immich-dark-primary">
 | 
			
		||||
				IMMICH
 | 
			
		||||
			</h1>
 | 
			
		||||
		</a>
 | 
			
		||||
		<div class="flex-1 ml-24">
 | 
			
		||||
			<input
 | 
			
		||||
				class="w-[50%] border rounded-md bg-gray-200 px-8 py-4"
 | 
			
		||||
				class="w-[50%] rounded-md bg-gray-200 dark:bg-immich-dark-gray  px-8 py-4"
 | 
			
		||||
				placeholder="Search - Coming soon"
 | 
			
		||||
			/>
 | 
			
		||||
		</div>
 | 
			
		||||
		<section class="flex gap-4 place-items-center">
 | 
			
		||||
			<ThemeButton />
 | 
			
		||||
 | 
			
		||||
			{#if $page.url.pathname !== '/admin' && shouldShowUploadButton}
 | 
			
		||||
				<button
 | 
			
		||||
					in:fly={{ x: 50, duration: 250 }}
 | 
			
		||||
					on:click={() => dispatch('uploadClicked')}
 | 
			
		||||
					class="immich-text-button"
 | 
			
		||||
					class="immich-text-button dark:hover:bg-immich-dark-primary/25 dark:text-immich-dark-fg"
 | 
			
		||||
				>
 | 
			
		||||
					<TrayArrowUp size="20" />
 | 
			
		||||
					<span> Upload </span>
 | 
			
		||||
@@ -73,8 +81,9 @@
 | 
			
		||||
			{#if user.isAdmin}
 | 
			
		||||
				<a data-sveltekit-prefetch href={`admin`}>
 | 
			
		||||
					<button
 | 
			
		||||
						class={`flex place-items-center place-content-center gap-2 hover:bg-immich-primary/5 p-2 rounded-lg font-medium ${
 | 
			
		||||
							$page.url.pathname == '/admin' && 'text-immich-primary underline'
 | 
			
		||||
						class={`flex place-items-center place-content-center gap-2 hover:bg-immich-primary/5  dark:hover:bg-immich-dark-primary/25 dark:text-immich-dark-fg p-2 rounded-lg font-medium ${
 | 
			
		||||
							$page.url.pathname == '/admin' &&
 | 
			
		||||
							'text-immich-primary dark:immich-dark-primary underline'
 | 
			
		||||
						}`}>Administration</button
 | 
			
		||||
					>
 | 
			
		||||
				</a>
 | 
			
		||||
@@ -87,7 +96,7 @@
 | 
			
		||||
				on:click={showAccountInfoPanel}
 | 
			
		||||
			>
 | 
			
		||||
				<button
 | 
			
		||||
					class="flex place-items-center place-content-center rounded-full bg-immich-primary/80 h-12 w-12 text-gray-100 hover:bg-immich-primary"
 | 
			
		||||
					class="flex place-items-center place-content-center rounded-full bg-immich-primary hover:bg-immich-primary/80 h-12 w-12 text-gray-100 dark:text-immich-dark-bg dark:bg-immich-dark-primary"
 | 
			
		||||
				>
 | 
			
		||||
					{#if shouldShowProfileImage}
 | 
			
		||||
						<img
 | 
			
		||||
@@ -104,7 +113,7 @@
 | 
			
		||||
					<div
 | 
			
		||||
						in:fade={{ delay: 500, duration: 150 }}
 | 
			
		||||
						out:fade={{ delay: 200, duration: 150 }}
 | 
			
		||||
						class="absolute -bottom-12 right-5 border bg-gray-500 text-[12px] text-gray-100 p-2 rounded-md shadow-md"
 | 
			
		||||
						class="absolute -bottom-12 right-5 border bg-gray-500 dark:bg-immich-dark-gray text-[12px] text-gray-100 p-2 rounded-md shadow-md dark:border-immich-dark-gray"
 | 
			
		||||
					>
 | 
			
		||||
						<p>{user.firstName} {user.lastName}</p>
 | 
			
		||||
						<p>{user.email}</p>
 | 
			
		||||
@@ -119,13 +128,13 @@
 | 
			
		||||
			in:fade={{ duration: 100 }}
 | 
			
		||||
			out:fade={{ duration: 100 }}
 | 
			
		||||
			id="account-info-panel"
 | 
			
		||||
			class="absolute right-[25px] top-[75px] bg-white shadow-lg rounded-2xl w-[360px] text-center z-[100]"
 | 
			
		||||
			class="absolute right-[25px] top-[75px] bg-immich-bg dark:bg-immich-dark-gray dark:border dark:border-immich-dark-gray shadow-lg rounded-2xl w-[360px] text-center z-[100]"
 | 
			
		||||
			use:clickOutside
 | 
			
		||||
			on:out-click={() => (shouldShowAccountInfoPanel = false)}
 | 
			
		||||
		>
 | 
			
		||||
			<div class="flex place-items-center place-content-center mt-6">
 | 
			
		||||
				<button
 | 
			
		||||
					class="flex place-items-center place-content-center rounded-full bg-immich-primary/80 h-20 w-20 text-gray-100 hover:bg-immich-primary"
 | 
			
		||||
					class="flex place-items-center place-content-center rounded-full bg-immich-primary dark:bg-immich-dark-primary dark:immich-dark-primary/80 h-20 w-20 text-gray-100 hover:bg-immich-primary dark:text-immich-dark-bg"
 | 
			
		||||
				>
 | 
			
		||||
					{#if shouldShowProfileImage}
 | 
			
		||||
						<img
 | 
			
		||||
@@ -141,20 +150,21 @@
 | 
			
		||||
				</button>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<p class="text-lg text-immich-primary font-medium mt-4">
 | 
			
		||||
			<p class="text-lg text-immich-primary dark:text-immich-dark-primary font-medium mt-4">
 | 
			
		||||
				{user.firstName}
 | 
			
		||||
				{user.lastName}
 | 
			
		||||
			</p>
 | 
			
		||||
 | 
			
		||||
			<p class="text-sm text-gray-500">{user.email}</p>
 | 
			
		||||
			<p class="text-sm text-gray-500 dark:text-immich-dark-fg">{user.email}</p>
 | 
			
		||||
 | 
			
		||||
			<div class="my-4">
 | 
			
		||||
				<hr />
 | 
			
		||||
				<hr class="dark:border-immich-dark-bg" />
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="mb-6">
 | 
			
		||||
				<button class="border rounded-3xl px-6 py-2 hover:bg-gray-50" on:click={logOut}
 | 
			
		||||
					>Sign Out</button
 | 
			
		||||
				<button
 | 
			
		||||
					class="border rounded-3xl px-6 py-2 hover:bg-gray-50 dark:border-immich-dark-gray dark:bg-gray-300 dark:hover:bg-immich-dark-primary"
 | 
			
		||||
					on:click={logOut}>Sign Out</button
 | 
			
		||||
				>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,7 @@
 | 
			
		||||
>
 | 
			
		||||
	{#if isHover}
 | 
			
		||||
		<div
 | 
			
		||||
			class="border-b-2 border-immich-primary w-[100px] right-0 pr-6 py-1 text-sm pl-1 font-medium absolute bg-white z-50 pointer-events-none rounded-tl-md shadow-lg"
 | 
			
		||||
			class="border-b-2 border-immich-primary dark:border-immich-dark-primary w-[100px] right-0 pr-6 py-1 text-sm pl-1 font-medium absolute bg-immich-bg dark:bg-immich-dark-gray z-50 pointer-events-none rounded-tl-md shadow-lg dark:text-immich-dark-fg"
 | 
			
		||||
			style:top={currentMouseYLocation + 'px'}
 | 
			
		||||
		>
 | 
			
		||||
			{hoveredDate?.toLocaleString('default', { month: 'short' })}
 | 
			
		||||
@@ -120,7 +120,7 @@
 | 
			
		||||
	<!-- Scroll Position Indicator Line -->
 | 
			
		||||
	{#if !isDragging}
 | 
			
		||||
		<div
 | 
			
		||||
			class="absolute right-0 w-10 h-[2px] bg-immich-primary"
 | 
			
		||||
			class="absolute right-0 w-10 h-[2px] bg-immich-primary dark:bg-immich-dark-primary"
 | 
			
		||||
			style:top={scrollbarPosition + 'px'}
 | 
			
		||||
		/>
 | 
			
		||||
	{/if}
 | 
			
		||||
@@ -139,7 +139,7 @@
 | 
			
		||||
				{#if segment.height > 8}
 | 
			
		||||
					<div
 | 
			
		||||
						aria-label={segment.timeGroup + ' ' + segment.count}
 | 
			
		||||
						class="absolute right-0 pr-5 z-10 text-xs font-medium"
 | 
			
		||||
						class="absolute right-0 pr-5 z-10 text-xs font-medium dark:text-immich-dark-fg"
 | 
			
		||||
					>
 | 
			
		||||
						{groupDate.getFullYear()}
 | 
			
		||||
					</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,11 @@
 | 
			
		||||
 | 
			
		||||
<div
 | 
			
		||||
	on:click={onButtonClicked}
 | 
			
		||||
	class={`flex gap-4 place-items-center pl-5 py-3 rounded-tr-full rounded-br-full hover:bg-gray-200 hover:text-immich-primary hover:cursor-pointer
 | 
			
		||||
    ${isSelected && 'bg-immich-primary/10 text-immich-primary hover:bg-immich-primary/25'}
 | 
			
		||||
	class={`flex gap-4 place-items-center pl-5 py-3 rounded-tr-full rounded-br-full hover:bg-immich-gray dark:hover:bg-immich-dark-gray hover:text-immich-primary dark:text-immich-dark-fg dark:hover:text-immich-dark-primary hover:cursor-pointer
 | 
			
		||||
    ${
 | 
			
		||||
			isSelected &&
 | 
			
		||||
			'bg-immich-primary/10 dark:bg-immich-dark-primary/10 text-immich-primary dark:text-[#adcbfa] hover:bg-immich-primary/25'
 | 
			
		||||
		}
 | 
			
		||||
  `}
 | 
			
		||||
>
 | 
			
		||||
	<svelte:component this={logo} size="24" />
 | 
			
		||||
 
 | 
			
		||||
@@ -52,8 +52,7 @@
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<section id="sidebar" class="flex flex-col gap-1 pt-8 pr-6">
 | 
			
		||||
	<!-- {domCount} -->
 | 
			
		||||
<section id="sidebar" class="flex flex-col gap-1 pt-8 pr-6 bg-immich-bg dark:bg-immich-dark-bg">
 | 
			
		||||
	<a
 | 
			
		||||
		data-sveltekit-prefetch
 | 
			
		||||
		data-sveltekit-noscroll
 | 
			
		||||
@@ -127,7 +126,7 @@
 | 
			
		||||
			{/if}
 | 
			
		||||
		</div>
 | 
			
		||||
	</a>
 | 
			
		||||
	<div class="text-xs ml-5 my-4">
 | 
			
		||||
	<div class="text-xs ml-5 my-4 dark:text-immich-dark-fg">
 | 
			
		||||
		<p>LIBRARY</p>
 | 
			
		||||
	</div>
 | 
			
		||||
	<a data-sveltekit-prefetch href={$page.routeId !== 'albums' ? `/albums` : null} class="relative">
 | 
			
		||||
 
 | 
			
		||||
@@ -46,18 +46,18 @@
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div>
 | 
			
		||||
<div class="dark:text-immich-dark-fg">
 | 
			
		||||
	<div class="storage-status grid grid-cols-[64px_auto]">
 | 
			
		||||
		<div class="pl-5 pr-6 text-immich-primary">
 | 
			
		||||
		<div class="pl-5 pr-6 text-immich-primary dark:text-immich-dark-primary">
 | 
			
		||||
			<Cloud size={'24'} />
 | 
			
		||||
		</div>
 | 
			
		||||
		<div>
 | 
			
		||||
			<p class="text-sm font-medium text-immich-primary">Storage</p>
 | 
			
		||||
			<p class="text-sm font-medium text-immich-primary dark:text-immich-dark-primary">Storage</p>
 | 
			
		||||
			{#if serverInfo}
 | 
			
		||||
				<div class="w-full bg-gray-200 rounded-full h-[7px] dark:bg-gray-700 my-2">
 | 
			
		||||
					<!-- style={`width: ${$downloadAssets[fileName]}%`} -->
 | 
			
		||||
					<div
 | 
			
		||||
						class="bg-immich-primary h-[7px] rounded-full"
 | 
			
		||||
						class="bg-immich-primary dark:bg-immich-dark-primary h-[7px] rounded-full"
 | 
			
		||||
						style={`width: ${getStorageUsagePercentage()}%`}
 | 
			
		||||
					/>
 | 
			
		||||
				</div>
 | 
			
		||||
@@ -70,21 +70,21 @@
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div>
 | 
			
		||||
		<hr class="ml-5 my-4" />
 | 
			
		||||
		<hr class="ml-5 my-4 dark:border-immich-dark-gray" />
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="server-status grid grid-cols-[64px_auto]">
 | 
			
		||||
		<div class="pl-5 pr-6 text-immich-primary">
 | 
			
		||||
		<div class="pl-5 pr-6 text-immich-primary dark:text-immich-dark-primary">
 | 
			
		||||
			<Dns size={'24'} />
 | 
			
		||||
		</div>
 | 
			
		||||
 | 
			
		||||
		<div class="text-xs ">
 | 
			
		||||
			<p class="text-sm font-medium text-immich-primary">Server</p>
 | 
			
		||||
			<p class="text-sm font-medium text-immich-primary dark:text-immich-dark-primary">Server</p>
 | 
			
		||||
 | 
			
		||||
			<div class="flex justify-items-center justify-between mt-2 ">
 | 
			
		||||
				<p>Status</p>
 | 
			
		||||
 | 
			
		||||
				{#if isServerOk}
 | 
			
		||||
					<p class="font-medium text-immich-primary">Online</p>
 | 
			
		||||
					<p class="font-medium text-immich-primary dark:text-immich-dark-primary">Online</p>
 | 
			
		||||
				{:else}
 | 
			
		||||
					<p class="font-medium text-red-500">Offline</p>
 | 
			
		||||
				{/if}
 | 
			
		||||
@@ -92,7 +92,7 @@
 | 
			
		||||
 | 
			
		||||
			<div class="flex justify-items-center justify-between mt-2 ">
 | 
			
		||||
				<p>Version</p>
 | 
			
		||||
				<p class="font-medium text-immich-primary">{serverVersion}</p>
 | 
			
		||||
				<p class="font-medium text-immich-primary dark:text-immich-dark-primary">{serverVersion}</p>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										77
									
								
								web/src/lib/components/shared-components/theme-button.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								web/src/lib/components/shared-components/theme-button.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	import { onMount } from 'svelte';
 | 
			
		||||
 | 
			
		||||
	let toggleButton: HTMLElement;
 | 
			
		||||
 | 
			
		||||
	onMount(() => {
 | 
			
		||||
		var themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
 | 
			
		||||
		var themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
 | 
			
		||||
 | 
			
		||||
		// Change the icons inside the button based on previous settings
 | 
			
		||||
		if (
 | 
			
		||||
			localStorage.getItem('color-theme') === 'dark' ||
 | 
			
		||||
			(!('color-theme' in localStorage) &&
 | 
			
		||||
				window.matchMedia('(prefers-color-scheme: dark)').matches)
 | 
			
		||||
		) {
 | 
			
		||||
			themeToggleLightIcon?.classList.remove('hidden');
 | 
			
		||||
		} else {
 | 
			
		||||
			themeToggleDarkIcon?.classList.remove('hidden');
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const toggleTheme = () => {
 | 
			
		||||
		var themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
 | 
			
		||||
		var themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
 | 
			
		||||
		// toggle icons inside button
 | 
			
		||||
		themeToggleDarkIcon?.classList.toggle('hidden');
 | 
			
		||||
		themeToggleLightIcon?.classList.toggle('hidden');
 | 
			
		||||
 | 
			
		||||
		// if set via local storage previously
 | 
			
		||||
		if (localStorage.getItem('color-theme')) {
 | 
			
		||||
			if (localStorage.getItem('color-theme') === 'light') {
 | 
			
		||||
				document.documentElement.classList.add('dark');
 | 
			
		||||
				localStorage.setItem('color-theme', 'dark');
 | 
			
		||||
			} else {
 | 
			
		||||
				document.documentElement.classList.remove('dark');
 | 
			
		||||
				localStorage.setItem('color-theme', 'light');
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if (document.documentElement.classList.contains('dark')) {
 | 
			
		||||
				document.documentElement.classList.remove('dark');
 | 
			
		||||
				localStorage.setItem('color-theme', 'light');
 | 
			
		||||
			} else {
 | 
			
		||||
				document.documentElement.classList.add('dark');
 | 
			
		||||
				localStorage.setItem('color-theme', 'dark');
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<button
 | 
			
		||||
	bind:this={toggleButton}
 | 
			
		||||
	on:click={toggleTheme}
 | 
			
		||||
	id="theme-toggle"
 | 
			
		||||
	type="button"
 | 
			
		||||
	class="text-gray-500 dark:text-immich-dark-primary hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none  rounded-lg text-sm p-2.5"
 | 
			
		||||
>
 | 
			
		||||
	<svg
 | 
			
		||||
		id="theme-toggle-dark-icon"
 | 
			
		||||
		class="hidden w-6 h-6"
 | 
			
		||||
		fill="currentColor"
 | 
			
		||||
		viewBox="0 0 20 20"
 | 
			
		||||
		xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
		><path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" /></svg
 | 
			
		||||
	>
 | 
			
		||||
	<svg
 | 
			
		||||
		id="theme-toggle-light-icon"
 | 
			
		||||
		class="hidden w-6 h-6"
 | 
			
		||||
		fill="currentColor"
 | 
			
		||||
		viewBox="0 0 20 20"
 | 
			
		||||
		xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
		><path
 | 
			
		||||
			d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
 | 
			
		||||
			fill-rule="evenodd"
 | 
			
		||||
			clip-rule="evenodd"
 | 
			
		||||
		/></svg
 | 
			
		||||
	>
 | 
			
		||||
</button>
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div
 | 
			
		||||
	class="flex min-w-[550px] border-b border-gray-300 place-items-center py-4  gap-6 transition-all hover:border-immich-primary"
 | 
			
		||||
	class="flex min-w-[550px] border-b border-gray-300 dark:border-immich-dark-gray place-items-center py-4  gap-6 transition-all hover:border-immich-primary dark:hover:border-immich-dark-primary"
 | 
			
		||||
>
 | 
			
		||||
	<div>
 | 
			
		||||
		{#await loadImageData(album.albumThumbnailAssetId)}
 | 
			
		||||
@@ -46,13 +46,16 @@
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div>
 | 
			
		||||
		<p class="font-medium text-gray-800">{album.albumName}</p>
 | 
			
		||||
		<p class="font-medium text-gray-800 dark:text-immich-dark-primary">{album.albumName}</p>
 | 
			
		||||
 | 
			
		||||
		{#await getAlbumOwnerInfo() then albumOwner}
 | 
			
		||||
			{#if user.email == albumOwner.email}
 | 
			
		||||
				<p class="text-xs text-gray-600">Owned</p>
 | 
			
		||||
				<p class="text-xs text-gray-600 dark:text-immich-dark-fg">Owned</p>
 | 
			
		||||
			{:else}
 | 
			
		||||
				<p class="text-xs text-gray-600">Shared by {albumOwner.firstName} {albumOwner.lastName}</p>
 | 
			
		||||
				<p class="text-xs text-gray-600 dark:text-immich-dark-fg">
 | 
			
		||||
					Shared by {albumOwner.firstName}
 | 
			
		||||
					{albumOwner.lastName}
 | 
			
		||||
				</p>
 | 
			
		||||
			{/if}
 | 
			
		||||
		{/await}
 | 
			
		||||
	</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,10 @@
 | 
			
		||||
	let localVersion: string;
 | 
			
		||||
	let remoteVersion: string;
 | 
			
		||||
	let showNavigationLoadingBar = false;
 | 
			
		||||
	let canShow = false;
 | 
			
		||||
 | 
			
		||||
	onMount(async () => {
 | 
			
		||||
		checkUserTheme();
 | 
			
		||||
		const res = await checkAppVersion();
 | 
			
		||||
 | 
			
		||||
		shouldShowAnnouncement = res.shouldShowAnnouncement;
 | 
			
		||||
@@ -24,6 +26,21 @@
 | 
			
		||||
		remoteVersion = res.remoteVersion ?? 'unknown';
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const checkUserTheme = () => {
 | 
			
		||||
		// On page load or when changing themes, best to add inline in `head` to avoid FOUC
 | 
			
		||||
		if (
 | 
			
		||||
			localStorage.getItem('color-theme') === 'dark' ||
 | 
			
		||||
			(!('color-theme' in localStorage) &&
 | 
			
		||||
				window.matchMedia('(prefers-color-scheme: dark)').matches)
 | 
			
		||||
		) {
 | 
			
		||||
			document.documentElement.classList.add('dark');
 | 
			
		||||
		} else {
 | 
			
		||||
			document.documentElement.classList.remove('dark');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		canShow = true;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	beforeNavigate(() => {
 | 
			
		||||
		showNavigationLoadingBar = true;
 | 
			
		||||
	});
 | 
			
		||||
@@ -34,7 +51,7 @@
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<main>
 | 
			
		||||
	<!-- {#key $page.url} -->
 | 
			
		||||
	{#if canShow}
 | 
			
		||||
		<div in:fade={{ duration: 100 }}>
 | 
			
		||||
			{#if showNavigationLoadingBar}
 | 
			
		||||
				<NavigationLoadingBar />
 | 
			
		||||
@@ -53,5 +70,5 @@
 | 
			
		||||
				/>
 | 
			
		||||
			{/if}
 | 
			
		||||
		</div>
 | 
			
		||||
	<!-- {/key} -->
 | 
			
		||||
	{/if}
 | 
			
		||||
</main>
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,13 @@
 | 
			
		||||
		<div class="flex place-items-center place-content-center ">
 | 
			
		||||
			<img class="text-center" src="immich-logo.svg" height="200" width="200" alt="immich-logo" />
 | 
			
		||||
		</div>
 | 
			
		||||
		<h1 class="text-4xl text-immich-primary font-bold font-immich-title">Welcome to IMMICH Web</h1>
 | 
			
		||||
		<h1
 | 
			
		||||
			class="text-4xl text-immich-primary dark:text-immich-dark-primary font-bold font-immich-title"
 | 
			
		||||
		>
 | 
			
		||||
			Welcome to IMMICH Web
 | 
			
		||||
		</h1>
 | 
			
		||||
		<button
 | 
			
		||||
			class="border px-4 py-2 rounded-md bg-immich-primary hover:bg-immich-primary/75 text-white font-bold w-[200px]"
 | 
			
		||||
			class="border px-4 py-4 rounded-md bg-immich-primary dark:bg-immich-dark-primary dark:text-immich-dark-gray dark:border-immich-dark-gray hover:bg-immich-primary/75 text-white font-bold w-[200px]"
 | 
			
		||||
			on:click={onGettingStartedClicked}
 | 
			
		||||
			>Getting Started
 | 
			
		||||
		</button>
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	onMount(() => {
 | 
			
		||||
		selectedAction = AdminSideBarSelection.JOBS;
 | 
			
		||||
		selectedAction = AdminSideBarSelection.USER_MANAGEMENT;
 | 
			
		||||
		getServerStats();
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
@@ -147,8 +147,10 @@
 | 
			
		||||
	</section>
 | 
			
		||||
	<section class="overflow-y-auto relative">
 | 
			
		||||
		<div id="setting-title" class="pt-10 fixed w-full z-50">
 | 
			
		||||
			<h1 class="text-lg ml-8 mb-4 text-immich-primary font-medium">{selectedAction}</h1>
 | 
			
		||||
			<hr />
 | 
			
		||||
			<h1 class="text-lg ml-8 mb-4 text-immich-primary dark:text-immich-dark-primary font-medium">
 | 
			
		||||
				{selectedAction}
 | 
			
		||||
			</h1>
 | 
			
		||||
			<hr class="dark:border-immich-dark-gray" />
 | 
			
		||||
		</div>
 | 
			
		||||
 | 
			
		||||
		<section id="setting-content" class="relative pt-[85px] flex place-content-center">
 | 
			
		||||
 
 | 
			
		||||
@@ -42,20 +42,28 @@
 | 
			
		||||
	<NavigationBar user={data.user} shouldShowUploadButton={false} />
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
<section class="grid grid-cols-[250px_auto] relative pt-[72px] h-screen bg-immich-bg ">
 | 
			
		||||
<section
 | 
			
		||||
	class="grid grid-cols-[250px_auto] relative pt-[72px] h-screen bg-immich-bg  dark:bg-immich-dark-bg"
 | 
			
		||||
>
 | 
			
		||||
	<SideBar />
 | 
			
		||||
 | 
			
		||||
	<!-- Main Section -->
 | 
			
		||||
 | 
			
		||||
	<section class="overflow-y-auto relative immich-scrollbar">
 | 
			
		||||
		<section id="album-content" class="relative pt-8 pl-4 mb-12 bg-immich-bg">
 | 
			
		||||
			<div class="px-4 flex justify-between place-items-center">
 | 
			
		||||
		<section
 | 
			
		||||
			id="album-content"
 | 
			
		||||
			class="relative pt-8 pl-4 mb-12 bg-immich-bg dark:bg-immich-dark-bg"
 | 
			
		||||
		>
 | 
			
		||||
			<div class="px-4 flex justify-between place-items-center dark:text-immich-dark-fg">
 | 
			
		||||
				<div>
 | 
			
		||||
					<p class="font-medium">Albums</p>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<div>
 | 
			
		||||
					<button on:click={handleCreateAlbum} class="immich-text-button text-sm">
 | 
			
		||||
					<button
 | 
			
		||||
						on:click={handleCreateAlbum}
 | 
			
		||||
						class="immich-text-button text-sm dark:hover:bg-immich-dark-primary/25 dark:text-immich-dark-fg"
 | 
			
		||||
					>
 | 
			
		||||
						<span>
 | 
			
		||||
							<PlusBoxOutline size="18" />
 | 
			
		||||
						</span>
 | 
			
		||||
@@ -65,7 +73,7 @@
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="my-4">
 | 
			
		||||
				<hr />
 | 
			
		||||
				<hr class="dark:border-immich-dark-gray" />
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<!-- Album Card -->
 | 
			
		||||
@@ -85,11 +93,11 @@
 | 
			
		||||
			<!-- Empty Message -->
 | 
			
		||||
			{#if $albums.length === 0}
 | 
			
		||||
				<div
 | 
			
		||||
					class="border p-5 w-[50%] m-auto mt-10 bg-gray-50 rounded-3xl flex flex-col place-content-center place-items-center"
 | 
			
		||||
					class="border dark:border-immich-dark-gray p-5 w-[50%] m-auto mt-10 bg-gray-50 dark:bg-immich-dark-gray rounded-3xl flex flex-col place-content-center place-items-center"
 | 
			
		||||
				>
 | 
			
		||||
					<img src="/empty-1.svg" alt="Empty shared album" width="500" />
 | 
			
		||||
 | 
			
		||||
					<p class="text-center text-immich-text-gray-500">
 | 
			
		||||
					<p class="text-center text-immich-text-gray-500 dark:text-immich-dark-fg">
 | 
			
		||||
						Create an album to organize your photos and videos
 | 
			
		||||
					</p>
 | 
			
		||||
				</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,9 @@
 | 
			
		||||
			tailwindClasses={'bg-white shadow-md'}
 | 
			
		||||
		>
 | 
			
		||||
			<svelte:fragment slot="leading">
 | 
			
		||||
				<p class="font-medium text-immich-primary">Selected {$selectedAssets.size}</p>
 | 
			
		||||
				<p class="font-medium text-immich-primary dark:text-immich-dark-primary">
 | 
			
		||||
					Selected {$selectedAssets.size}
 | 
			
		||||
				</p>
 | 
			
		||||
			</svelte:fragment>
 | 
			
		||||
			<svelte:fragment slot="trailing">
 | 
			
		||||
				<CircleIconButton
 | 
			
		||||
@@ -83,7 +85,9 @@
 | 
			
		||||
	{/if}
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
<section class="grid grid-cols-[250px_auto] relative pt-[72px] h-screen bg-immich-bg">
 | 
			
		||||
<section
 | 
			
		||||
	class="grid grid-cols-[250px_auto] relative pt-[72px] h-screen bg-immich-bg dark:bg-immich-dark-bg"
 | 
			
		||||
>
 | 
			
		||||
	<SideBar />
 | 
			
		||||
	<AssetGrid />
 | 
			
		||||
</section>
 | 
			
		||||
 
 | 
			
		||||
@@ -39,13 +39,18 @@
 | 
			
		||||
	<NavigationBar user={data.user} shouldShowUploadButton={false} />
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
<section class="grid grid-cols-[250px_auto] relative pt-[72px] h-screen bg-immich-bg">
 | 
			
		||||
<section
 | 
			
		||||
	class="grid grid-cols-[250px_auto] relative pt-[72px] h-screen bg-immich-bg dark:bg-immich-dark-bg"
 | 
			
		||||
>
 | 
			
		||||
	<SideBar />
 | 
			
		||||
 | 
			
		||||
	<section class="overflow-y-auto relative">
 | 
			
		||||
		<section id="album-content" class="relative pt-8 pl-4 mb-12 bg-immich-bg">
 | 
			
		||||
		<section
 | 
			
		||||
			id="album-content"
 | 
			
		||||
			class="relative pt-8 pl-4 mb-12 bg-immich-bg dark:bg-immich-dark-bg"
 | 
			
		||||
		>
 | 
			
		||||
			<!-- Main Section -->
 | 
			
		||||
			<div class="px-4 flex justify-between place-items-center">
 | 
			
		||||
			<div class="px-4 flex justify-between place-items-center dark:text-immich-dark-fg">
 | 
			
		||||
				<div>
 | 
			
		||||
					<p class="font-medium">Sharing</p>
 | 
			
		||||
				</div>
 | 
			
		||||
@@ -53,7 +58,7 @@
 | 
			
		||||
				<div>
 | 
			
		||||
					<button
 | 
			
		||||
						on:click={createSharedAlbum}
 | 
			
		||||
						class="flex place-items-center gap-1 text-sm hover:bg-immich-primary/5 p-2 rounded-lg font-medium hover:text-gray-700"
 | 
			
		||||
						class="flex place-items-center gap-1 text-sm hover:bg-immich-primary/5 p-2 rounded-lg font-medium hover:text-gray-700 dark:hover:bg-immich-dark-primary/25 dark:text-immich-dark-fg"
 | 
			
		||||
					>
 | 
			
		||||
						<span>
 | 
			
		||||
							<PlusBoxOutline size="18" />
 | 
			
		||||
@@ -64,7 +69,7 @@
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="my-4">
 | 
			
		||||
				<hr />
 | 
			
		||||
				<hr class="dark:border-immich-dark-gray" />
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<!-- Share Album List -->
 | 
			
		||||
@@ -79,7 +84,7 @@
 | 
			
		||||
			<!-- Empty List -->
 | 
			
		||||
			{#if data.sharedAlbums.length === 0}
 | 
			
		||||
				<div
 | 
			
		||||
					class="border p-5 w-[50%] m-auto mt-10 bg-gray-50 rounded-3xl flex flex-col place-content-center place-items-center"
 | 
			
		||||
					class="border dark:border-immich-dark-gray p-5 w-[50%] m-auto mt-10 bg-gray-50 dark:bg-immich-dark-gray rounded-3xl flex flex-col place-content-center place-items-center dark:text-immich-dark-fg"
 | 
			
		||||
				>
 | 
			
		||||
					<img src="/empty-2.svg" alt="Empty shared album" width="500" />
 | 
			
		||||
					<p class="text-center text-immich-text-gray-500">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,20 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
	content: ['./src/**/*.{html,js,svelte,ts}'],
 | 
			
		||||
	darkMode: 'class',
 | 
			
		||||
	theme: {
 | 
			
		||||
		extend: {
 | 
			
		||||
			colors: {
 | 
			
		||||
				// Light Theme
 | 
			
		||||
				'immich-primary': '#4250af',
 | 
			
		||||
				'immich-bg': 'white',
 | 
			
		||||
				'immich-fg': 'black',
 | 
			
		||||
				'immich-gray': '#F6F6F4'
 | 
			
		||||
				// 'immich-bg': '#121212',
 | 
			
		||||
				// 'immich-fg': '#D0D0D0',
 | 
			
		||||
				'immich-gray': '#F6F6F4',
 | 
			
		||||
 | 
			
		||||
				// Dark Theme
 | 
			
		||||
				'immich-dark-primary': '#adcbfa',
 | 
			
		||||
				'immich-dark-bg': 'black',
 | 
			
		||||
				'immich-dark-fg': '#e5e7eb',
 | 
			
		||||
				'immich-dark-gray': '#212121'
 | 
			
		||||
			},
 | 
			
		||||
			fontFamily: {
 | 
			
		||||
				'immich-title': ['Snowburst One', 'cursive']
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user