Browse Source

feat(web) dark mode (#867)

Alex 2 years ago
parent
commit
f94176a910
39 changed files with 364 additions and 188 deletions
  1. 3 3
      web/src/app.css
  2. 2 2
      web/src/app.html
  3. 10 8
      web/src/lib/components/admin-page/jobs/job-tile.svelte
  4. 9 5
      web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte
  5. 8 6
      web/src/lib/components/admin-page/server-stats/stats-card.svelte
  6. 9 5
      web/src/lib/components/admin-page/user-management.svelte
  7. 6 8
      web/src/lib/components/album-page/album-card.svelte
  8. 13 9
      web/src/lib/components/album-page/album-viewer.svelte
  9. 6 6
      web/src/lib/components/album-page/asset-selection.svelte
  10. 3 4
      web/src/lib/components/album-page/share-info-modal.svelte
  11. 5 5
      web/src/lib/components/album-page/user-selection-modal.svelte
  12. 1 1
      web/src/lib/components/asset-viewer/asset-viewer.svelte
  13. 7 7
      web/src/lib/components/asset-viewer/detail-panel.svelte
  14. 10 4
      web/src/lib/components/forms/admin-registration-form.svelte
  15. 10 4
      web/src/lib/components/forms/change-password-form.svelte
  16. 10 4
      web/src/lib/components/forms/create-user-form.svelte
  17. 11 6
      web/src/lib/components/forms/edit-user-form.svelte
  18. 6 4
      web/src/lib/components/forms/login-form.svelte
  19. 3 1
      web/src/lib/components/photos-page/asset-date-group.svelte
  20. 1 1
      web/src/lib/components/shared-components/base-modal.svelte
  21. 2 3
      web/src/lib/components/shared-components/circle-icon-button.svelte
  22. 1 1
      web/src/lib/components/shared-components/context-menu/context-menu.svelte
  23. 1 1
      web/src/lib/components/shared-components/context-menu/menu-option.svelte
  24. 4 5
      web/src/lib/components/shared-components/control-app-bar.svelte
  25. 1 1
      web/src/lib/components/shared-components/immich-thumbnail.svelte
  26. 26 16
      web/src/lib/components/shared-components/navigation-bar.svelte
  27. 3 3
      web/src/lib/components/shared-components/scrollbar/scrollbar.svelte
  28. 6 3
      web/src/lib/components/shared-components/side-bar/side-bar-button.svelte
  29. 2 3
      web/src/lib/components/shared-components/side-bar/side-bar.svelte
  30. 12 12
      web/src/lib/components/shared-components/status-box.svelte
  31. 77 0
      web/src/lib/components/shared-components/theme-button.svelte
  32. 7 4
      web/src/lib/components/sharing-page/shared-album-list-tile.svelte
  33. 37 20
      web/src/routes/+layout.svelte
  34. 6 2
      web/src/routes/+page.svelte
  35. 5 3
      web/src/routes/admin/+page.svelte
  36. 15 7
      web/src/routes/albums/+page.svelte
  37. 6 2
      web/src/routes/photos/+page.svelte
  38. 11 6
      web/src/routes/sharing/+page.svelte
  39. 9 3
      web/tailwind.config.cjs

+ 3 - 3
web/src/app.css

@@ -59,15 +59,15 @@ input:focus-visible {
 
 
 @layer utilities {
 @layer utilities {
 	.immich-form-input {
 	.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 {
 	.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 {
 	.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 {
 	.immich-text-button {

+ 2 - 2
web/src/app.html

@@ -1,5 +1,5 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html lang="en">
+<html lang="en" class="dark">
 	<head>
 	<head>
 		<meta charset="utf-8" />
 		<meta charset="utf-8" />
 		<link rel="icon" href="%sveltekit.assets%/favicon.png" />
 		<link rel="icon" href="%sveltekit.assets%/favicon.png" />
@@ -7,7 +7,7 @@
 		%sveltekit.head%
 		%sveltekit.head%
 	</head>
 	</head>
 
 
-	<body>
+	<body class="bg-immich-bg dark:bg-immich-dark-bg">
 		<div>%sveltekit.body%</div>
 		<div>%sveltekit.body%</div>
 	</body>
 	</body>
 </html>
 </html>

+ 10 - 8
web/src/lib/components/admin-page/jobs/job-tile.svelte

@@ -11,17 +11,17 @@
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
 </script>
 </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%]">
 	<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 />
 			<slot />
 		</p>
 		</p>
 		<table class="text-left w-full mt-5">
 		<table class="text-left w-full mt-5">
 			<!-- table header -->
 			<!-- table header -->
 			<thead
 			<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">
 				<tr class="flex w-full place-items-center">
 					<th class="text-center w-1/3 font-medium text-sm">Status</th>
 					<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>
 					<th class="text-center w-1/3 font-medium text-sm">Waiting</th>
 				</tr>
 				</tr>
 			</thead>
 			</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">{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">{activeJobCount}</td>
 					<td class="text-sm px-2 w-1/3 text-ellipsis">{waitingJobCount}</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">
 	<div class="w-[30%] flex place-items-center place-content-end">
 		<button
 		<button
 			on:click={() => dispatch('click')}
 			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}
 			disabled={jobStatus}
 		>
 		>
 			{#if jobStatus}
 			{#if jobStatus}

+ 9 - 5
web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte

@@ -22,7 +22,7 @@
 
 
 <div class="flex flex-col gap-5">
 <div class="flex flex-col gap-5">
 	<div>
 	<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">
 		<div class="flex mt-5 justify-between">
 			<StatsCard logo={CameraIris} title={'PHOTOS'} value={stats.photos.toString()} />
 			<StatsCard logo={CameraIris} title={'PHOTOS'} value={stats.photos.toString()} />
@@ -33,9 +33,11 @@
 	</div>
 	</div>
 
 
 	<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">
 		<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">
 				<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">User</th>
 					<th class="text-center w-1/5 font-medium text-sm">Photos</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>
 					<th class="text-center w-1/5 font-medium text-sm">Size</th>
 				</tr>
 				</tr>
 			</thead>
 			</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}
 				{#each stats.usageByUser as user, i}
 					<tr
 					<tr
 						class={`text-center flex place-items-center w-full h-[50px] ${
 						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>
 						<td class="text-sm px-2 w-1/5 text-ellipsis">{getFullName(user.userId)}</td>

+ 8 - 6
web/src/lib/components/admin-page/server-stats/stats-card.svelte

@@ -17,15 +17,17 @@
 	};
 	};
 </script>
 </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>
 
 
 	<div class="relative text-center font-mono font-semibold text-2xl">
 	<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}
 		{#if unit}
 			<span class="absolute -top-5 right-2 text-base font-light text-gray-400">{unit}</span>
 			<span class="absolute -top-5 right-2 text-base font-light text-gray-400">{unit}</span>

+ 9 - 5
web/src/lib/components/admin-page/user-management.svelte

@@ -9,7 +9,9 @@
 </script>
 </script>
 
 
 <table class="text-left w-full my-5">
 <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">
 		<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">Email</th>
 			<th class="text-center w-1/4 font-medium text-sm">First name</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>
 			<th class="text-center w-1/4 font-medium text-sm">Edit</th>
 		</tr>
 		</tr>
 	</thead>
 	</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}
 		{#each allUsers as user, i}
 			<tr
 			<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>
 				<td class="text-sm px-4 w-1/4 text-ellipsis">{user.email}</td>
@@ -32,7 +36,7 @@
 						on:click={() => {
 						on:click={() => {
 							dispatch('edit-user', { user });
 							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
 						><PencilOutline size="20" /></button
 					></td
 					></td
 				>
 				>

+ 6 - 8
web/src/lib/components/album-page/album-card.svelte

@@ -60,12 +60,7 @@
 		on:click|stopPropagation|preventDefault={showAlbumContextMenu}
 		on:click|stopPropagation|preventDefault={showAlbumContextMenu}
 		data-testid="context-button-parent"
 		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>
 
 
 	<div class={`h-[275px] w-[275px] z-[-1]`}>
 	<div class={`h-[275px] w-[275px] z-[-1]`}>
@@ -78,11 +73,14 @@
 	</div>
 	</div>
 
 
 	<div class="mt-4">
 	<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}
 			{album.albumName}
 		</p>
 		</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>
 			<p>{album.assetCount} items</p>
 
 
 			{#if album.shared}
 			{#if album.shared}

+ 13 - 9
web/src/lib/components/album-page/album-viewer.svelte

@@ -331,7 +331,7 @@
 	};
 	};
 </script>
 </script>
 
 
-<section class="bg-immich-bg">
+<section class="bg-immich-bg dark:bg-immich-dark-bg">
 	<!-- Multiselection mode app bar -->
 	<!-- Multiselection mode app bar -->
 	{#if isMultiSelectionMode}
 	{#if isMultiSelectionMode}
 		<ControlAppBar
 		<ControlAppBar
@@ -340,7 +340,9 @@
 			tailwindClasses={'bg-white shadow-md'}
 			tailwindClasses={'bg-white shadow-md'}
 		>
 		>
 			<svelte:fragment slot="leading">
 			<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>
 			<svelte:fragment slot="trailing">
 			<svelte:fragment slot="trailing">
 				{#if isOwned}
 				{#if isOwned}
@@ -386,7 +388,7 @@
 					<button
 					<button
 						disabled={album.assetCount == 0}
 						disabled={album.assetCount == 0}
 						on:click={() => (isShowShareUserSelection = true)}
 						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
 						><span class="px-2">Share</span></button
 					>
 					>
 				{/if}
 				{/if}
@@ -404,9 +406,9 @@
 			}}
 			}}
 			on:focus={() => (isEditingTitle = true)}
 			on:focus={() => (isEditingTitle = true)}
 			on:blur={() => (isEditingTitle = false)}
 			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'
 				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"
 			type="text"
 			bind:value={album.albumName}
 			bind:value={album.albumName}
 			disabled={!isOwned}
 			disabled={!isOwned}
@@ -468,13 +470,15 @@
 			<!-- Album is empty - Show asset selectection buttons -->
 			<!-- Album is empty - Show asset selectection buttons -->
 			<section id="empty-album" class=" mt-[200px] flex place-content-center place-items-center">
 			<section id="empty-album" class=" mt-[200px] flex place-content-center place-items-center">
 				<div class="w-[300px]">
 				<div class="w-[300px]">
-					<p class="text-xs">ADD PHOTOS</p>
+					<p class="text-xs dark:text-immich-dark-fg">ADD PHOTOS</p>
 					<button
 					<button
 						on:click={() => (isShowAssetSelection = true)}
 						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>
 					</button>
 				</div>
 				</div>
 			</section>
 			</section>

+ 6 - 6
web/src/lib/components/album-page/asset-selection.svelte

@@ -70,7 +70,7 @@
 
 
 <section
 <section
 	transition:fly={{ y: 500, duration: 100, easing: quintOut }}
 	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
 	<ControlAppBar
 		on:close-button-click={() => {
 		on:close-button-click={() => {
@@ -80,28 +80,28 @@
 	>
 	>
 		<svelte:fragment slot="leading">
 		<svelte:fragment slot="leading">
 			{#if $selectedAssets.size == 0}
 			{#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}
 			{:else}
-				<p class="text-lg">{$selectedAssets.size} selected</p>
+				<p class="text-lg dark:text-immich-dark-fg">{$selectedAssets.size} selected</p>
 			{/if}
 			{/if}
 		</svelte:fragment>
 		</svelte:fragment>
 
 
 		<svelte:fragment slot="trailing">
 		<svelte:fragment slot="trailing">
 			<button
 			<button
 				on:click={() => openFileUploadDialog(UploadType.ALBUM)}
 				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
 				Select from computer
 			</button>
 			</button>
 			<button
 			<button
 				disabled={$selectedAssets.size === 0}
 				disabled={$selectedAssets.size === 0}
 				on:click={addSelectedAssets}
 				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
 				><span class="px-2">Done</span></button
 			>
 			>
 		</svelte:fragment>
 		</svelte:fragment>
 	</ControlAppBar>
 	</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} />
 		<AssetGrid isAlbumSelectionMode={true} />
 	</section>
 	</section>
 </section>
 </section>

+ 3 - 4
web/src/lib/components/album-page/share-info-modal.svelte

@@ -68,14 +68,14 @@
 <BaseModal on:close={() => dispatch('close')}>
 <BaseModal on:close={() => dispatch('close')}>
 	<svelte:fragment slot="title">
 	<svelte:fragment slot="title">
 		<span class="flex gap-2 place-items-center">
 		<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>
 		</span>
 	</svelte:fragment>
 	</svelte:fragment>
 
 
 	<section class="max-h-[400px] overflow-y-auto immich-scrollbar pb-4">
 	<section class="max-h-[400px] overflow-y-auto immich-scrollbar pb-4">
 		{#each album.sharedUsers as user}
 		{#each album.sharedUsers as user}
 			<div
 			<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">
 				<div class="flex gap-4 place-items-center">
 					<CircleAvatar {user} />
 					<CircleAvatar {user} />
@@ -88,14 +88,13 @@
 							on:click={() => showContextMenu(user.id)}
 							on:click={() => showContextMenu(user.id)}
 							logo={DotsVertical}
 							logo={DotsVertical}
 							backgroundColor={'transparent'}
 							backgroundColor={'transparent'}
-							logoColor={'#5f6368'}
 							hoverColor={'#e2e7e9'}
 							hoverColor={'#e2e7e9'}
 							size={'20'}
 							size={'20'}
 						/>
 						/>
 					{:else if user.id == currentUser?.id}
 					{:else if user.id == currentUser?.id}
 						<button
 						<button
 							on:click={() => removeUser('me')}
 							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
 							>Leave</button
 						>
 						>
 					{/if}
 					{/if}

+ 5 - 5
web/src/lib/components/album-page/user-selection-modal.svelte

@@ -38,7 +38,7 @@
 	<svelte:fragment slot="title">
 	<svelte:fragment slot="title">
 		<span class="flex gap-2 place-items-center">
 		<span class="flex gap-2 place-items-center">
 			<img src="/immich-logo.svg" width="24" alt="Immich" />
 			<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>
 		</span>
 	</svelte:fragment>
 	</svelte:fragment>
 
 
@@ -51,7 +51,7 @@
 					{#key user.id}
 					{#key user.id}
 						<button
 						<button
 							on:click={() => deselectUser(user)}
 							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} />
 							<CircleAvatar size={28} {user} />
 							<p class="text-xs font-medium">{user.firstName} {user.lastName}</p>
 							<p class="text-xs font-medium">{user.firstName} {user.lastName}</p>
@@ -68,11 +68,11 @@
 				{#each users as user}
 				{#each users as user}
 					<button
 					<button
 						on:click={() => selectUser(user)}
 						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)}
 						{#if selectedUsers.includes(user)}
 							<span
 							<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
 								>✓</span
 							>
 							>
 						{:else}
 						{:else}
@@ -80,7 +80,7 @@
 						{/if}
 						{/if}
 
 
 						<div class="text-left">
 						<div class="text-left">
-							<p class="text-immich-fg">
+							<p class="text-immich-fg dark:text-immich-dark-fg">
 								{user.firstName}
 								{user.firstName}
 								{user.lastName}
 								{user.lastName}
 							</p>
 							</p>

+ 1 - 1
web/src/lib/components/asset-viewer/asset-viewer.svelte

@@ -207,7 +207,7 @@
 		<div
 		<div
 			transition:fly={{ duration: 150 }}
 			transition:fly={{ duration: 150 }}
 			id="detail-panel"
 			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"
 			translate="yes"
 		>
 		>
 			<DetailPanel {asset} albums={appearsInAlbums} on:close={() => (isShowDetail = false)} />
 			<DetailPanel {asset} albums={appearsInAlbums} on:close={() => (isShowDetail = false)} />

+ 7 - 7
web/src/lib/components/asset-viewer/detail-panel.svelte

@@ -97,16 +97,16 @@
 	};
 	};
 </script>
 </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">
 	<div class="flex place-items-center gap-2">
 		<button
 		<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')}
 			on:click={() => dispatch('close')}
 		>
 		>
-			<Close size="24" color="#232323" />
+			<Close size="24" />
 		</button>
 		</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>
 
 
 	<div class="px-4 py-4">
 	<div class="px-4 py-4">
@@ -202,10 +202,10 @@
 	<div class="h-[360px] w-full" id="map" />
 	<div class="h-[360px] w-full" id="map" />
 </div>
 </div>
 
 
-<section class="p-2">
+<section class="p-2 dark:text-immich-dark-fg">
 	<div class="px-4 py-4">
 	<div class="px-4 py-4">
 		{#if albums.length > 0}
 		{#if albums.length > 0}
-			<p class="text-sm pb-4">APPEARS IN</p>
+			<p class="text-sm pb-4 ">APPEARS IN</p>
 		{/if}
 		{/if}
 		{#each albums as album}
 		{#each albums as album}
 			<a data-sveltekit-prefetch href={`/albums/${album.id}`}>
 			<a data-sveltekit-prefetch href={`/albums/${album.id}`}>
@@ -219,7 +219,7 @@
 					</div>
 					</div>
 
 
 					<div class="mt-auto mb-auto">
 					<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">
 						<div class="flex gap-2 text-sm">
 							<p>{album.assetCount} items</p>
 							<p>{album.assetCount} items</p>
 							{#if album.shared}
 							{#if album.shared}

+ 10 - 4
web/src/lib/components/forms/admin-registration-form.svelte

@@ -51,11 +51,17 @@
 	}
 	}
 </script>
 </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">
 	<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" />
 		<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
 			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.
 			responsible for administrative tasks, and additional users will be created by you.
 		</p>
 		</p>
@@ -117,7 +123,7 @@
 		<div class="flex w-full">
 		<div class="flex w-full">
 			<button
 			<button
 				type="submit"
 				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
 				>Sign Up</button
 			>
 			>
 		</div>
 		</div>

+ 10 - 4
web/src/lib/components/forms/change-password-form.svelte

@@ -43,12 +43,18 @@
 	}
 	}
 </script>
 </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">
 	<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" />
 		<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}
 			Hi {user.firstName}
 			{user.lastName} ({user.email}),
 			{user.lastName} ({user.email}),
 			<br />
 			<br />
@@ -93,7 +99,7 @@
 		<div class="flex w-full">
 		<div class="flex w-full">
 			<button
 			<button
 				type="submit"
 				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
 				>Change Password</button
 			>
 			>
 		</div>
 		</div>

+ 10 - 4
web/src/lib/components/forms/create-user-form.svelte

@@ -53,11 +53,17 @@
 	}
 	}
 </script>
 </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">
 	<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" />
 		<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
 			Please provide your user with the password, they will have to change it on their first sign
 			in.
 			in.
 		</p>
 		</p>
@@ -113,7 +119,7 @@
 		<div class="flex w-full">
 		<div class="flex w-full">
 			<button
 			<button
 				type="submit"
 				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
 				>Create
 			</button>
 			</button>
 		</div>
 		</div>

+ 11 - 6
web/src/lib/components/forms/edit-user-form.svelte

@@ -65,11 +65,16 @@
 	};
 	};
 </script>
 </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>
 	</div>
 
 
 	<form on:submit|preventDefault={editUser} autocomplete="off">
 	<form on:submit|preventDefault={editUser} autocomplete="off">
@@ -124,7 +129,7 @@
 			</button>
 			</button>
 			<button
 			<button
 				type="submit"
 				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
 				>Confirm
 			</button>
 			</button>
 		</div>
 		</div>

+ 6 - 4
web/src/lib/components/forms/login-form.svelte

@@ -32,15 +32,17 @@
 	};
 	};
 </script>
 </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">
 	<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" />
 		<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>
 	</div>
 
 
 	{#if loginPageMessage}
 	{#if loginPageMessage}
 		<p
 		<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}
 			{@html loginPageMessage}
 		</p>
 		</p>
@@ -78,7 +80,7 @@
 		<div class="flex w-full">
 		<div class="flex w-full">
 			<button
 			<button
 				type="submit"
 				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
 				>Login</button
 			>
 			>
 		</div>
 		</div>

+ 3 - 1
web/src/lib/components/photos-page/asset-date-group.svelte

@@ -115,7 +115,9 @@
 			on:mouseleave={() => (isMouseOverGroup = false)}
 			on:mouseleave={() => (isMouseOverGroup = false)}
 		>
 		>
 			<!-- Date group title -->
 			<!-- 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)}
 				{#if (hoveredDateGroup == dateGroupTitle && isMouseOverGroup) || $selectedGroup.has(dateGroupTitle)}
 					<div
 					<div
 						transition:fly={{ x: -24, duration: 200, opacity: 0.5 }}
 						transition:fly={{ x: -24, duration: 200, opacity: 0.5 }}

+ 1 - 1
web/src/lib/components/shared-components/base-modal.svelte

@@ -36,7 +36,7 @@
 	<div
 	<div
 		use:clickOutside
 		use:clickOutside
 		on:out-click={() => dispatch('close')}
 		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 class="flex justify-between place-items-center p-5">
 			<div>
 			<div>

+ 2 - 3
web/src/lib/components/shared-components/circle-icon-button.svelte

@@ -9,7 +9,6 @@
 	export let logo: any;
 	export let logo: any;
 	export let backgroundColor = 'transparent';
 	export let backgroundColor = 'transparent';
 	export let hoverColor = '#e2e7e9';
 	export let hoverColor = '#e2e7e9';
-	export let logoColor = '#5f6368';
 	export let size = '24';
 	export let size = '24';
 	export let title = '';
 	export let title = '';
 	let iconButton: HTMLButtonElement;
 	let iconButton: HTMLButtonElement;
@@ -26,10 +25,10 @@
 <button
 <button
 	{title}
 	{title}
 	bind:this={iconButton}
 	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 })}
 	on:click={(mouseEvent) => dispatch('click', { mouseEvent })}
 >
 >
-	<svelte:component this={logo} {size} color={logoColor} />
+	<svelte:component this={logo} {size} />
 </button>
 </button>
 
 
 <style>
 <style>

+ 1 - 1
web/src/lib/components/shared-components/context-menu/context-menu.svelte

@@ -32,7 +32,7 @@
 <div
 <div
 	transition:slide={{ duration: 200, easing: quintOut }}
 	transition:slide={{ duration: 200, easing: quintOut }}
 	bind:this={menuEl}
 	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;`}
 	style={`top: ${y}px; left: ${x}px;`}
 	use:clickOutside
 	use:clickOutside
 	on:out-click={() => dispatch('clickoutside')}
 	on:out-click={() => dispatch('clickoutside')}

+ 1 - 1
web/src/lib/components/shared-components/context-menu/menu-option.svelte

@@ -16,7 +16,7 @@
 <button
 <button
 	class:disabled={isDisabled}
 	class:disabled={isDisabled}
 	on:click={handleClick}
 	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}
 	{#if text}
 		{text}
 		{text}

+ 4 - 5
web/src/lib/components/shared-components/control-app-bar.svelte

@@ -14,7 +14,7 @@
 
 
 	const onScroll = () => {
 	const onScroll = () => {
 		if (window.pageYOffset > 80) {
 		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 {
 		} else {
 			appBarBorder = 'bg-immich-bg border border-transparent';
 			appBarBorder = 'bg-immich-bg border border-transparent';
 		}
 		}
@@ -39,14 +39,13 @@
 >
 >
 	<div
 	<div
 		id="asset-selection-app-bar"
 		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
 			<CircleIconButton
 				on:click={() => dispatch('close-button-click')}
 				on:click={() => dispatch('close-button-click')}
 				logo={backIcon}
 				logo={backIcon}
 				backgroundColor={'transparent'}
 				backgroundColor={'transparent'}
-				logoColor={'rgb(75 85 99)'}
 				hoverColor={'#e2e7e9'}
 				hoverColor={'#e2e7e9'}
 				size={'24'}
 				size={'24'}
 			/>
 			/>
@@ -54,7 +53,7 @@
 			<slot name="leading" />
 			<slot name="leading" />
 		</div>
 		</div>
 
 
-		<div class="flex place-items-center gap-1 mr-4">
+		<div class="flex place-items-center gap-1 mr-4 ">
 			<slot name="trailing" />
 			<slot name="trailing" />
 		</div>
 		</div>
 	</div>
 	</div>

+ 1 - 1
web/src/lib/components/shared-components/immich-thumbnail.svelte

@@ -136,7 +136,7 @@
 	<div
 	<div
 		style:width={`${thumbnailSize}px`}
 		style:width={`${thumbnailSize}px`}
 		style:height={`${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'
 			disabled ? 'cursor-not-allowed' : 'hover:cursor-pointer'
 		}`}
 		}`}
 		on:mouseenter={handleMouseOverThumbnail}
 		on:mouseenter={handleMouseOverThumbnail}

+ 26 - 16
web/src/lib/components/shared-components/navigation-bar.svelte

@@ -6,6 +6,7 @@
 	import TrayArrowUp from 'svelte-material-icons/TrayArrowUp.svelte';
 	import TrayArrowUp from 'svelte-material-icons/TrayArrowUp.svelte';
 	import { clickOutside } from '../../utils/click-outside';
 	import { clickOutside } from '../../utils/click-outside';
 	import { api, UserResponseDto } from '@api';
 	import { api, UserResponseDto } from '@api';
+	import ThemeButton from './theme-button.svelte';
 
 
 	export let user: UserResponseDto;
 	export let user: UserResponseDto;
 	export let shouldShowUploadButton = true;
 	export let shouldShowUploadButton = true;
@@ -42,28 +43,35 @@
 	};
 	};
 </script>
 </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
 		<a
 			data-sveltekit-prefetch
 			data-sveltekit-prefetch
 			class="flex gap-2 place-items-center hover:cursor-pointer"
 			class="flex gap-2 place-items-center hover:cursor-pointer"
 			href="/photos"
 			href="/photos"
 		>
 		>
 			<img src="/immich-logo.svg" alt="immich logo" height="35" width="35" />
 			<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>
 		</a>
 		<div class="flex-1 ml-24">
 		<div class="flex-1 ml-24">
 			<input
 			<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"
 				placeholder="Search - Coming soon"
 			/>
 			/>
 		</div>
 		</div>
 		<section class="flex gap-4 place-items-center">
 		<section class="flex gap-4 place-items-center">
+			<ThemeButton />
+
 			{#if $page.url.pathname !== '/admin' && shouldShowUploadButton}
 			{#if $page.url.pathname !== '/admin' && shouldShowUploadButton}
 				<button
 				<button
 					in:fly={{ x: 50, duration: 250 }}
 					in:fly={{ x: 50, duration: 250 }}
 					on:click={() => dispatch('uploadClicked')}
 					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" />
 					<TrayArrowUp size="20" />
 					<span> Upload </span>
 					<span> Upload </span>
@@ -73,8 +81,9 @@
 			{#if user.isAdmin}
 			{#if user.isAdmin}
 				<a data-sveltekit-prefetch href={`admin`}>
 				<a data-sveltekit-prefetch href={`admin`}>
 					<button
 					<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
 						}`}>Administration</button
 					>
 					>
 				</a>
 				</a>
@@ -87,7 +96,7 @@
 				on:click={showAccountInfoPanel}
 				on:click={showAccountInfoPanel}
 			>
 			>
 				<button
 				<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}
 					{#if shouldShowProfileImage}
 						<img
 						<img
@@ -104,7 +113,7 @@
 					<div
 					<div
 						in:fade={{ delay: 500, duration: 150 }}
 						in:fade={{ delay: 500, duration: 150 }}
 						out:fade={{ delay: 200, 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.firstName} {user.lastName}</p>
 						<p>{user.email}</p>
 						<p>{user.email}</p>
@@ -119,13 +128,13 @@
 			in:fade={{ duration: 100 }}
 			in:fade={{ duration: 100 }}
 			out:fade={{ duration: 100 }}
 			out:fade={{ duration: 100 }}
 			id="account-info-panel"
 			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
 			use:clickOutside
 			on:out-click={() => (shouldShowAccountInfoPanel = false)}
 			on:out-click={() => (shouldShowAccountInfoPanel = false)}
 		>
 		>
 			<div class="flex place-items-center place-content-center mt-6">
 			<div class="flex place-items-center place-content-center mt-6">
 				<button
 				<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}
 					{#if shouldShowProfileImage}
 						<img
 						<img
@@ -141,20 +150,21 @@
 				</button>
 				</button>
 			</div>
 			</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.firstName}
 				{user.lastName}
 				{user.lastName}
 			</p>
 			</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">
 			<div class="my-4">
-				<hr />
+				<hr class="dark:border-immich-dark-bg" />
 			</div>
 			</div>
 
 
 			<div class="mb-6">
 			<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>
 		</div>
 		</div>

+ 3 - 3
web/src/lib/components/shared-components/scrollbar/scrollbar.svelte

@@ -109,7 +109,7 @@
 >
 >
 	{#if isHover}
 	{#if isHover}
 		<div
 		<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'}
 			style:top={currentMouseYLocation + 'px'}
 		>
 		>
 			{hoveredDate?.toLocaleString('default', { month: 'short' })}
 			{hoveredDate?.toLocaleString('default', { month: 'short' })}
@@ -120,7 +120,7 @@
 	<!-- Scroll Position Indicator Line -->
 	<!-- Scroll Position Indicator Line -->
 	{#if !isDragging}
 	{#if !isDragging}
 		<div
 		<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'}
 			style:top={scrollbarPosition + 'px'}
 		/>
 		/>
 	{/if}
 	{/if}
@@ -139,7 +139,7 @@
 				{#if segment.height > 8}
 				{#if segment.height > 8}
 					<div
 					<div
 						aria-label={segment.timeGroup + ' ' + segment.count}
 						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()}
 						{groupDate.getFullYear()}
 					</div>
 					</div>

+ 6 - 3
web/src/lib/components/shared-components/side-bar/side-bar-button.svelte

@@ -23,10 +23,13 @@
 
 
 <div
 <div
 	on:click={onButtonClicked}
 	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" />
 	<svelte:component this={logo} size="24" />
-	<p class="font-medium text-sm">{title}</p>
+	<p class="font-medium text-sm ">{title}</p>
 </div>
 </div>

+ 2 - 3
web/src/lib/components/shared-components/side-bar/side-bar.svelte

@@ -52,8 +52,7 @@
 	};
 	};
 </script>
 </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
 	<a
 		data-sveltekit-prefetch
 		data-sveltekit-prefetch
 		data-sveltekit-noscroll
 		data-sveltekit-noscroll
@@ -127,7 +126,7 @@
 			{/if}
 			{/if}
 		</div>
 		</div>
 	</a>
 	</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>
 		<p>LIBRARY</p>
 	</div>
 	</div>
 	<a data-sveltekit-prefetch href={$page.routeId !== 'albums' ? `/albums` : null} class="relative">
 	<a data-sveltekit-prefetch href={$page.routeId !== 'albums' ? `/albums` : null} class="relative">

+ 12 - 12
web/src/lib/components/shared-components/status-box.svelte

@@ -46,18 +46,18 @@
 	};
 	};
 </script>
 </script>
 
 
-<div>
+<div class="dark:text-immich-dark-fg">
 	<div class="storage-status grid grid-cols-[64px_auto]">
 	<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'} />
 			<Cloud size={'24'} />
 		</div>
 		</div>
 		<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}
 			{#if serverInfo}
 				<div class="w-full bg-gray-200 rounded-full h-[7px] dark:bg-gray-700 my-2">
 				<div class="w-full bg-gray-200 rounded-full h-[7px] dark:bg-gray-700 my-2">
 					<!-- style={`width: ${$downloadAssets[fileName]}%`} -->
 					<!-- style={`width: ${$downloadAssets[fileName]}%`} -->
 					<div
 					<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()}%`}
 						style={`width: ${getStorageUsagePercentage()}%`}
 					/>
 					/>
 				</div>
 				</div>
@@ -70,29 +70,29 @@
 		</div>
 		</div>
 	</div>
 	</div>
 	<div>
 	<div>
-		<hr class="ml-5 my-4" />
+		<hr class="ml-5 my-4 dark:border-immich-dark-gray" />
 	</div>
 	</div>
 	<div class="server-status grid grid-cols-[64px_auto]">
 	<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'} />
 			<Dns size={'24'} />
 		</div>
 		</div>
 
 
-		<div class="text-xs">
-			<p class="text-sm font-medium text-immich-primary">Server</p>
+		<div class="text-xs ">
+			<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">
+			<div class="flex justify-items-center justify-between mt-2 ">
 				<p>Status</p>
 				<p>Status</p>
 
 
 				{#if isServerOk}
 				{#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}
 				{:else}
 					<p class="font-medium text-red-500">Offline</p>
 					<p class="font-medium text-red-500">Offline</p>
 				{/if}
 				{/if}
 			</div>
 			</div>
 
 
-			<div class="flex justify-items-center justify-between mt-2">
+			<div class="flex justify-items-center justify-between mt-2 ">
 				<p>Version</p>
 				<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>
 		</div>
 	</div>
 	</div>

+ 77 - 0
web/src/lib/components/shared-components/theme-button.svelte

@@ -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>

+ 7 - 4
web/src/lib/components/sharing-page/shared-album-list-tile.svelte

@@ -26,7 +26,7 @@
 </script>
 </script>
 
 
 <div
 <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>
 	<div>
 		{#await loadImageData(album.albumThumbnailAssetId)}
 		{#await loadImageData(album.albumThumbnailAssetId)}
@@ -46,13 +46,16 @@
 	</div>
 	</div>
 
 
 	<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}
 		{#await getAlbumOwnerInfo() then albumOwner}
 			{#if user.email == albumOwner.email}
 			{#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}
 			{: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}
 			{/if}
 		{/await}
 		{/await}
 	</div>
 	</div>

+ 37 - 20
web/src/routes/+layout.svelte

@@ -15,8 +15,10 @@
 	let localVersion: string;
 	let localVersion: string;
 	let remoteVersion: string;
 	let remoteVersion: string;
 	let showNavigationLoadingBar = false;
 	let showNavigationLoadingBar = false;
+	let canShow = false;
 
 
 	onMount(async () => {
 	onMount(async () => {
+		checkUserTheme();
 		const res = await checkAppVersion();
 		const res = await checkAppVersion();
 
 
 		shouldShowAnnouncement = res.shouldShowAnnouncement;
 		shouldShowAnnouncement = res.shouldShowAnnouncement;
@@ -24,6 +26,21 @@
 		remoteVersion = res.remoteVersion ?? 'unknown';
 		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(() => {
 	beforeNavigate(() => {
 		showNavigationLoadingBar = true;
 		showNavigationLoadingBar = true;
 	});
 	});
@@ -34,24 +51,24 @@
 </script>
 </script>
 
 
 <main>
 <main>
-	<!-- {#key $page.url} -->
-	<div in:fade={{ duration: 100 }}>
-		{#if showNavigationLoadingBar}
-			<NavigationLoadingBar />
-		{/if}
-
-		<slot />
-
-		<DownloadPanel />
-		<UploadPanel />
-		<NotificationList />
-		{#if shouldShowAnnouncement}
-			<AnnouncementBox
-				{localVersion}
-				{remoteVersion}
-				on:close={() => (shouldShowAnnouncement = false)}
-			/>
-		{/if}
-	</div>
-	<!-- {/key} -->
+	{#if canShow}
+		<div in:fade={{ duration: 100 }}>
+			{#if showNavigationLoadingBar}
+				<NavigationLoadingBar />
+			{/if}
+
+			<slot />
+
+			<DownloadPanel />
+			<UploadPanel />
+			<NotificationList />
+			{#if shouldShowAnnouncement}
+				<AnnouncementBox
+					{localVersion}
+					{remoteVersion}
+					on:close={() => (shouldShowAnnouncement = false)}
+				/>
+			{/if}
+		</div>
+	{/if}
 </main>
 </main>

+ 6 - 2
web/src/routes/+page.svelte

@@ -19,9 +19,13 @@
 		<div class="flex place-items-center place-content-center ">
 		<div class="flex place-items-center place-content-center ">
 			<img class="text-center" src="immich-logo.svg" height="200" width="200" alt="immich-logo" />
 			<img class="text-center" src="immich-logo.svg" height="200" width="200" alt="immich-logo" />
 		</div>
 		</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
 		<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}
 			on:click={onGettingStartedClicked}
 			>Getting Started
 			>Getting Started
 		</button>
 		</button>

+ 5 - 3
web/src/routes/admin/+page.svelte

@@ -33,7 +33,7 @@
 	};
 	};
 
 
 	onMount(() => {
 	onMount(() => {
-		selectedAction = AdminSideBarSelection.JOBS;
+		selectedAction = AdminSideBarSelection.USER_MANAGEMENT;
 		getServerStats();
 		getServerStats();
 	});
 	});
 
 
@@ -147,8 +147,10 @@
 	</section>
 	</section>
 	<section class="overflow-y-auto relative">
 	<section class="overflow-y-auto relative">
 		<div id="setting-title" class="pt-10 fixed w-full z-50">
 		<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>
 		</div>
 
 
 		<section id="setting-content" class="relative pt-[85px] flex place-content-center">
 		<section id="setting-content" class="relative pt-[85px] flex place-content-center">

+ 15 - 7
web/src/routes/albums/+page.svelte

@@ -42,20 +42,28 @@
 	<NavigationBar user={data.user} shouldShowUploadButton={false} />
 	<NavigationBar user={data.user} shouldShowUploadButton={false} />
 </section>
 </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 />
 	<SideBar />
 
 
 	<!-- Main Section -->
 	<!-- Main Section -->
 
 
 	<section class="overflow-y-auto relative immich-scrollbar">
 	<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>
 				<div>
 					<p class="font-medium">Albums</p>
 					<p class="font-medium">Albums</p>
 				</div>
 				</div>
 
 
 				<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>
 						<span>
 							<PlusBoxOutline size="18" />
 							<PlusBoxOutline size="18" />
 						</span>
 						</span>
@@ -65,7 +73,7 @@
 			</div>
 			</div>
 
 
 			<div class="my-4">
 			<div class="my-4">
-				<hr />
+				<hr class="dark:border-immich-dark-gray" />
 			</div>
 			</div>
 
 
 			<!-- Album Card -->
 			<!-- Album Card -->
@@ -85,11 +93,11 @@
 			<!-- Empty Message -->
 			<!-- Empty Message -->
 			{#if $albums.length === 0}
 			{#if $albums.length === 0}
 				<div
 				<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" />
 					<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
 						Create an album to organize your photos and videos
 					</p>
 					</p>
 				</div>
 				</div>

+ 6 - 2
web/src/routes/photos/+page.svelte

@@ -65,7 +65,9 @@
 			tailwindClasses={'bg-white shadow-md'}
 			tailwindClasses={'bg-white shadow-md'}
 		>
 		>
 			<svelte:fragment slot="leading">
 			<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>
 			<svelte:fragment slot="trailing">
 			<svelte:fragment slot="trailing">
 				<CircleIconButton
 				<CircleIconButton
@@ -83,7 +85,9 @@
 	{/if}
 	{/if}
 </section>
 </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 />
 	<SideBar />
 	<AssetGrid />
 	<AssetGrid />
 </section>
 </section>

+ 11 - 6
web/src/routes/sharing/+page.svelte

@@ -39,13 +39,18 @@
 	<NavigationBar user={data.user} shouldShowUploadButton={false} />
 	<NavigationBar user={data.user} shouldShowUploadButton={false} />
 </section>
 </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 />
 	<SideBar />
 
 
 	<section class="overflow-y-auto relative">
 	<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 -->
 			<!-- 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>
 				<div>
 					<p class="font-medium">Sharing</p>
 					<p class="font-medium">Sharing</p>
 				</div>
 				</div>
@@ -53,7 +58,7 @@
 				<div>
 				<div>
 					<button
 					<button
 						on:click={createSharedAlbum}
 						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>
 						<span>
 							<PlusBoxOutline size="18" />
 							<PlusBoxOutline size="18" />
@@ -64,7 +69,7 @@
 			</div>
 			</div>
 
 
 			<div class="my-4">
 			<div class="my-4">
-				<hr />
+				<hr class="dark:border-immich-dark-gray" />
 			</div>
 			</div>
 
 
 			<!-- Share Album List -->
 			<!-- Share Album List -->
@@ -79,7 +84,7 @@
 			<!-- Empty List -->
 			<!-- Empty List -->
 			{#if data.sharedAlbums.length === 0}
 			{#if data.sharedAlbums.length === 0}
 				<div
 				<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" />
 					<img src="/empty-2.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">

+ 9 - 3
web/tailwind.config.cjs

@@ -1,14 +1,20 @@
 module.exports = {
 module.exports = {
 	content: ['./src/**/*.{html,js,svelte,ts}'],
 	content: ['./src/**/*.{html,js,svelte,ts}'],
+	darkMode: 'class',
 	theme: {
 	theme: {
 		extend: {
 		extend: {
 			colors: {
 			colors: {
+				// Light Theme
 				'immich-primary': '#4250af',
 				'immich-primary': '#4250af',
 				'immich-bg': 'white',
 				'immich-bg': 'white',
 				'immich-fg': 'black',
 				'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: {
 			fontFamily: {
 				'immich-title': ['Snowburst One', 'cursive']
 				'immich-title': ['Snowburst One', 'cursive']