mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
chore: upgrade to tailwind v4 (#18353)
This commit is contained in:
parent
c411c1472a
commit
56156b97e7
1302
web/package-lock.json
generated
1302
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,7 @@
|
||||
"dependencies": {
|
||||
"@formatjs/icu-messageformat-parser": "^2.9.8",
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@immich/ui": "^0.21.1",
|
||||
"@immich/ui": "^0.22.0",
|
||||
"@mapbox/mapbox-gl-rtl-text": "0.2.3",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@photo-sphere-viewer/core": "^5.11.5",
|
||||
@ -52,6 +52,7 @@
|
||||
"svelte-i18n": "^4.0.1",
|
||||
"svelte-maplibre": "^1.0.0",
|
||||
"svelte-persisted-store": "^0.12.0",
|
||||
"tabbable": "^6.2.0",
|
||||
"thumbhash": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -63,6 +64,8 @@
|
||||
"@sveltejs/enhanced-img": "^0.5.0",
|
||||
"@sveltejs/kit": "^2.15.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@tailwindcss/postcss": "^4.1.7",
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"@testing-library/jest-dom": "^6.4.2",
|
||||
"@testing-library/svelte": "^5.2.6",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
@ -89,7 +92,7 @@
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
"svelte": "^5.25.3",
|
||||
"svelte-check": "^4.1.5",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tailwindcss": "^4.1.7",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.28.0",
|
||||
|
@ -1,6 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
};
|
||||
|
200
web/src/app.css
200
web/src/app.css
@ -1,6 +1,32 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import 'tailwindcss';
|
||||
@import '@immich/ui/theme/default.css';
|
||||
|
||||
@config '../tailwind.config.js';
|
||||
|
||||
@utility immich-form-input {
|
||||
@apply rounded-xl bg-slate-200 px-3 py-3 text-sm focus:border-immich-primary disabled:cursor-not-allowed disabled:bg-gray-400 disabled:text-gray-100 dark:bg-gray-600 dark:text-immich-dark-fg dark:disabled:bg-gray-800 dark:disabled:text-gray-200;
|
||||
}
|
||||
|
||||
@utility immich-form-label {
|
||||
@apply font-medium text-gray-500 dark:text-gray-300;
|
||||
}
|
||||
|
||||
@utility immich-scrollbar {
|
||||
/* width */
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
@utility scrollbar-hidden {
|
||||
/* Hidden scrollbar */
|
||||
/* width */
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
@utility scrollbar-stable {
|
||||
scrollbar-gutter: stable both-edges;
|
||||
}
|
||||
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
@ -21,107 +47,97 @@
|
||||
--immich-dark-success: 56 142 60;
|
||||
--immich-dark-warning: 245 124 0;
|
||||
}
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('$lib/assets/fonts/overpass/Overpass.ttf') format('truetype-variations');
|
||||
font-weight: 1 999;
|
||||
font-style: normal;
|
||||
ascent-override: 106.25%;
|
||||
size-adjust: 106.25%;
|
||||
}
|
||||
*,
|
||||
::after,
|
||||
::before,
|
||||
::backdrop,
|
||||
::file-selector-button {
|
||||
border-color: rgb(var(--immich-ui-default-border));
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass Mono';
|
||||
src: url('$lib/assets/fonts/overpass/OverpassMono.ttf') format('truetype-variations');
|
||||
font-weight: 1 999;
|
||||
font-style: monospace;
|
||||
ascent-override: 106.25%;
|
||||
size-adjust: 106.25%;
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: 'Overpass', sans-serif;
|
||||
/* Used by layouts to ensure proper spacing between navbar and content */
|
||||
--navbar-height: calc(theme(spacing.18) + 4px);
|
||||
--navbar-height-md: calc(theme(spacing.18) + 4px - 14px);
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
:root:not(.dark) {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
html::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
html::-webkit-scrollbar-thumb {
|
||||
background: rgba(85, 86, 87, 0.408);
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
html::-webkit-scrollbar-thumb:hover {
|
||||
background: #4250afad;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: #3a3a3a;
|
||||
}
|
||||
|
||||
input:focus-visible {
|
||||
outline-offset: 0px !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.text-white-shadow {
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.icon-white-drop-shadow {
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.8));
|
||||
button:not(:disabled),
|
||||
[role='button']:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.immich-form-input {
|
||||
@apply rounded-xl bg-slate-200 px-3 py-3 text-sm focus:border-immich-primary disabled:cursor-not-allowed disabled:bg-gray-400 disabled:text-gray-100 dark:bg-gray-600 dark:text-immich-dark-fg dark:disabled:bg-gray-800 dark:disabled:text-gray-200;
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('$lib/assets/fonts/overpass/Overpass.ttf') format('truetype-variations');
|
||||
font-weight: 1 999;
|
||||
font-style: normal;
|
||||
ascent-override: 106.25%;
|
||||
size-adjust: 106.25%;
|
||||
}
|
||||
|
||||
.immich-form-label {
|
||||
@apply font-medium text-gray-500 dark:text-gray-300;
|
||||
@font-face {
|
||||
font-family: 'Overpass Mono';
|
||||
src: url('$lib/assets/fonts/overpass/OverpassMono.ttf') format('truetype-variations');
|
||||
font-weight: 1 999;
|
||||
font-style: monospace;
|
||||
ascent-override: 106.25%;
|
||||
size-adjust: 106.25%;
|
||||
}
|
||||
|
||||
/* width */
|
||||
.immich-scrollbar {
|
||||
scrollbar-width: thin;
|
||||
:root {
|
||||
font-family: 'Overpass', sans-serif;
|
||||
/* Used by layouts to ensure proper spacing between navbar and content */
|
||||
--navbar-height: calc(4.5rem + 4px);
|
||||
--navbar-height-md: calc(4.5rem + 4px - 14px);
|
||||
}
|
||||
|
||||
/* Hidden scrollbar */
|
||||
/* width */
|
||||
.scrollbar-hidden {
|
||||
scrollbar-width: none;
|
||||
:root.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
.scrollbar-stable {
|
||||
scrollbar-gutter: stable both-edges;
|
||||
:root:not(.dark) {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
html::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
html::-webkit-scrollbar-thumb {
|
||||
background: rgba(85, 86, 87, 0.408);
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
html::-webkit-scrollbar-thumb:hover {
|
||||
background: #4250afad;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: #3a3a3a;
|
||||
}
|
||||
|
||||
input:focus-visible {
|
||||
outline-offset: 0px !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.text-white-shadow {
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.icon-white-drop-shadow {
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.8));
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,7 @@
|
||||
</head>
|
||||
|
||||
<noscript
|
||||
class="absolute z-[1000] flex h-screen w-screen place-content-center place-items-center bg-immich-bg dark:bg-immich-dark-bg dark:text-immich-dark-fg"
|
||||
class="absolute z-1000 flex h-screen w-screen place-content-center place-items-center bg-immich-bg dark:bg-immich-dark-bg dark:text-immich-dark-fg"
|
||||
>
|
||||
To use Immich, you must enable JavaScript or use a JavaScript compatible browser.
|
||||
</noscript>
|
||||
|
@ -51,11 +51,7 @@
|
||||
class="w-full text-start mt-2 pt-2 pe-2 pb-2 rounded-md transition-colors cursor-pointer dark:text-immich-dark-fg hover:text-immich-primary dark:hover:text-immich-dark-primary hover:bg-subtle dark:hover:bg-immich-dark-gray"
|
||||
aria-expanded={!isCollapsed}
|
||||
>
|
||||
<Icon
|
||||
path={mdiChevronRight}
|
||||
size="24"
|
||||
class="inline-block -mt-2.5 transition-all duration-[250ms] {iconRotation}"
|
||||
/>
|
||||
<Icon path={mdiChevronRight} size="24" class="inline-block -mt-2.5 transition-all duration-250 {iconRotation}" />
|
||||
<span class="font-bold text-3xl text-black dark:text-white">{group.name}</span>
|
||||
<span class="ms-1.5">({$t('albums_count', { values: { count: albums.length } })})</span>
|
||||
</button>
|
||||
|
@ -58,7 +58,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<main class="relative h-dvh overflow-hidden px-2 md:px-6 max-md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)]">
|
||||
<main class="relative h-dvh overflow-hidden px-2 md:px-6 max-md:pt-(--navbar-height-md) pt-(--navbar-height)">
|
||||
<AssetGrid enableRouting={true} {album} {assetStore} {assetInteraction}>
|
||||
<section class="pt-8 md:pt-24 px-2 md:px-0">
|
||||
<!-- ALBUM TITLE -->
|
||||
|
@ -56,7 +56,7 @@
|
||||
<Icon
|
||||
path={mdiChevronRight}
|
||||
size="20"
|
||||
class="inline-block -mt-2 transition-all duration-[250ms] {iconRotation}"
|
||||
class="inline-block -mt-2 transition-all duration-250 {iconRotation}"
|
||||
/>
|
||||
<span class="font-bold text-2xl">{albumGroup.name}</span>
|
||||
<span class="ms-1.5">
|
||||
|
@ -108,7 +108,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex h-16 place-items-center justify-between bg-gradient-to-b from-black/40 px-3 transition-transform duration-200"
|
||||
class="flex h-16 place-items-center justify-between bg-linear-to-b from-black/40 px-3 transition-transform duration-200"
|
||||
>
|
||||
<div class="text-white">
|
||||
{#if showCloseButton}
|
||||
|
@ -216,7 +216,7 @@
|
||||
slow: ??ms
|
||||
-->
|
||||
<div
|
||||
class={['group absolute top-[0px] bottom-[0px]', { 'cursor-not-allowed': disabled, 'cursor-pointer': !disabled }]}
|
||||
class={['group absolute -top-[0px] -bottom-[0px]', { 'cursor-not-allowed': disabled, 'cursor-pointer': !disabled }]}
|
||||
style:width="inherit"
|
||||
style:height="inherit"
|
||||
onmouseenter={onMouseEnter}
|
||||
@ -266,7 +266,7 @@
|
||||
{#if !usingMobileDevice && !disabled}
|
||||
<div
|
||||
class={[
|
||||
'absolute h-full w-full bg-gradient-to-b from-black/25 via-[transparent_25%] opacity-0 transition-opacity group-hover:opacity-100',
|
||||
'absolute h-full w-full bg-linear-to-b from-black/25 via-[transparent_25%] opacity-0 transition-opacity group-hover:opacity-100',
|
||||
{ 'rounded-xl': selected },
|
||||
]}
|
||||
></div>
|
||||
@ -279,7 +279,7 @@
|
||||
<!-- Outline on focus -->
|
||||
<div
|
||||
class={[
|
||||
'absolute size-full group-focus-visible:outline outline-4 -outline-offset-4 outline-immich-primary',
|
||||
'absolute size-full group-focus-visible:outline-immich-primary focus:outline-4 -outline-offset-4 outline-immich-primary',
|
||||
{ 'rounded-xl': selected },
|
||||
]}
|
||||
></div>
|
||||
|
@ -108,7 +108,7 @@
|
||||
{#if showMenu}
|
||||
<div
|
||||
transition:fly={{ y: -30, duration: 250 }}
|
||||
class="text-sm font-medium z-[1] absolute flex min-w-[250px] max-h-[70vh] overflow-y-auto immich-scrollbar flex-col rounded-2xl bg-gray-100 py-2 text-black shadow-lg dark:bg-gray-700 dark:text-white {className} {getAlignClass(
|
||||
class="text-sm font-medium z-1 absolute flex min-w-[250px] max-h-[70vh] overflow-y-auto immich-scrollbar flex-col rounded-2xl bg-gray-100 py-2 text-black shadow-lg dark:bg-gray-700 dark:text-white {className} {getAlignClass(
|
||||
position,
|
||||
)}"
|
||||
>
|
||||
@ -117,7 +117,7 @@
|
||||
{@const buttonStyle = renderedOption.disabled ? '' : 'transition-all hover:bg-gray-300 dark:hover:bg-gray-800'}
|
||||
<button
|
||||
type="button"
|
||||
class="grid grid-cols-[36px,1fr] place-items-center p-2 disabled:opacity-40 {buttonStyle}"
|
||||
class="grid grid-cols-[36px_1fr] place-items-center p-2 disabled:opacity-40 {buttonStyle}"
|
||||
disabled={renderedOption.disabled}
|
||||
onclick={() => !renderedOption.disabled && handleSelectOption(option)}
|
||||
>
|
||||
|
@ -15,7 +15,7 @@
|
||||
</script>
|
||||
|
||||
<fieldset
|
||||
class="dark:bg-immich-dark-gray flex h-full rounded-2xl bg-gray-200 ring-gray-400 has-[:focus-visible]:ring dark:ring-gray-600"
|
||||
class="dark:bg-immich-dark-gray flex h-full rounded-2xl bg-gray-200 ring-gray-400 has-focus-visible:ring dark:ring-gray-600"
|
||||
>
|
||||
<legend class="sr-only">{label}</legend>
|
||||
{#each filters as filter, index (`${id}-${index}`)}
|
||||
|
@ -10,7 +10,7 @@
|
||||
let { id, label, name, value, group = $bindable(undefined) }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="radio" {name} {id} {value} class="focus-visible:ring" bind:group />
|
||||
<label for={id}>{label}</label>
|
||||
</div>
|
||||
|
@ -62,7 +62,7 @@
|
||||
</a>
|
||||
|
||||
{#if showVerticalDots}
|
||||
<div class="absolute top-2 end-2 z-[1]">
|
||||
<div class="absolute top-2 end-2 z-1">
|
||||
<ButtonContextMenu
|
||||
buttonClass="icon-white-drop-shadow focus:opacity-100 {showVerticalDots ? 'opacity-100' : 'opacity-0'}"
|
||||
color="opaque"
|
||||
|
@ -54,7 +54,7 @@
|
||||
<AlbumCover {album} class="h-[200px] w-[200px] m-4 shadow-lg" />
|
||||
</div>
|
||||
|
||||
<div class="flex-grow">
|
||||
<div class="grow">
|
||||
<div class="m-4 flex flex-col gap-2">
|
||||
<label class="immich-form-label" for="name">{$t('name')}</label>
|
||||
<input class="immich-form-input" id="name" type="text" bind:value={albumName} />
|
||||
|
@ -12,7 +12,11 @@
|
||||
|
||||
<section class="min-w-dvw flex min-h-dvh items-center justify-center relative">
|
||||
<div class="absolute -z-10 w-full h-full flex place-items-center place-content-center">
|
||||
<img src={immichLogo} class="max-w-screen-md mx-auto h-full mb-2 antialiased overflow-hidden" alt="Immich logo" />
|
||||
<img
|
||||
src={immichLogo}
|
||||
class="max-w-(--breakpoint-md) mx-auto h-full mb-2 antialiased overflow-hidden"
|
||||
alt="Immich logo"
|
||||
/>
|
||||
<div
|
||||
class="w-full h-[99%] absolute start-0 top-0 backdrop-blur-[200px] bg-transparent dark:bg-immich-dark-bg/20"
|
||||
></div>
|
||||
|
@ -36,7 +36,7 @@
|
||||
}: Props = $props();
|
||||
|
||||
let scrollbarClass = $derived(scrollbar ? 'immich-scrollbar p-2' : 'scrollbar-hidden');
|
||||
let hasTitleClass = $derived(title ? 'top-16 h-[calc(100%-theme(spacing.16))]' : 'top-0 h-full');
|
||||
let hasTitleClass = $derived(title ? 'top-16 h-[calc(100%-(--spacing(16)))]' : 'top-0 h-full');
|
||||
</script>
|
||||
|
||||
<header>
|
||||
@ -48,10 +48,10 @@
|
||||
</header>
|
||||
<div
|
||||
tabindex="-1"
|
||||
class="relative z-0 grid grid-cols-[theme(spacing.0)_auto] overflow-hidden sidebar:grid-cols-[theme(spacing.64)_auto]
|
||||
class="relative z-0 grid grid-cols-[--spacing(0)_auto] overflow-hidden sidebar:grid-cols-[--spacing(64)_auto]
|
||||
{hideNavbar ? 'h-dvh' : 'h-[calc(100dvh-var(--navbar-height))]'}
|
||||
{hideNavbar ? 'pt-[var(--navbar-height)]' : ''}
|
||||
{hideNavbar ? 'max-md:pt-[var(--navbar-height-md)]' : ''}"
|
||||
{hideNavbar ? 'pt-(--navbar-height)' : ''}
|
||||
{hideNavbar ? 'max-md:pt-(--navbar-height-md)' : ''}"
|
||||
>
|
||||
{#if sidebar}
|
||||
{@render sidebar()}
|
||||
|
@ -406,7 +406,7 @@
|
||||
<!-- Viewer -->
|
||||
<section class="overflow-hidden pt-32 md:pt-20" bind:clientHeight={viewerHeight}>
|
||||
<div
|
||||
class="ms-[-100%] box-border flex h-[calc(100vh_-_224px)] md:h-[calc(100vh_-_180px)] w-[300%] items-center justify-center gap-10 overflow-hidden"
|
||||
class="ms-[-100%] box-border flex h-[calc(100vh-224px)] md:h-[calc(100vh-180px)] w-[300%] items-center justify-center gap-10 overflow-hidden"
|
||||
>
|
||||
<!-- PREVIOUS MEMORY -->
|
||||
<div class="h-1/2 w-[20vw] rounded-2xl {current.previousMemory ? 'opacity-25 hover:opacity-70' : 'opacity-0'}">
|
||||
|
@ -47,7 +47,7 @@
|
||||
{#if canScrollLeft || canScrollRight}
|
||||
<div class="sticky start-0">
|
||||
{#if canScrollLeft}
|
||||
<div class="absolute start-4 top-[6rem]" transition:fade={{ duration: 200 }}>
|
||||
<div class="absolute start-4 top-24" transition:fade={{ duration: 200 }}>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-full border border-gray-500 bg-gray-100 p-2 text-gray-500 opacity-50 hover:opacity-100"
|
||||
@ -60,7 +60,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if canScrollRight}
|
||||
<div class="absolute end-4 top-[6rem]" transition:fade={{ duration: 200 }}>
|
||||
<div class="absolute end-4 top-24" transition:fade={{ duration: 200 }}>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-full border border-gray-500 bg-gray-100 p-2 text-gray-500 opacity-50 hover:opacity-100"
|
||||
@ -77,7 +77,7 @@
|
||||
<div class="inline-block" use:resizeObserver={({ width }) => (innerWidth = width)}>
|
||||
{#each memoryStore.memories as memory (memory.id)}
|
||||
<a
|
||||
class="memory-card relative me-2 md:me-4 last:me-0 inline-block aspect-[3/4] md:aspect-[4/3] max-md:h-[150px] xl:aspect-video h-[215px] rounded-xl"
|
||||
class="memory-card relative me-2 md:me-4 last:me-0 inline-block aspect-3/4 md:aspect-4/3 max-md:h-[150px] xl:aspect-video h-[215px] rounded-xl"
|
||||
href="{AppRoute.MEMORY}?{QueryParameter.ID}={memory.assets[0].id}"
|
||||
>
|
||||
<img
|
||||
@ -87,7 +87,7 @@
|
||||
draggable="false"
|
||||
/>
|
||||
<div
|
||||
class="absolute start-0 top-0 h-full w-full rounded-xl bg-gradient-to-t from-black/40 via-transparent to-transparent transition-all hover:bg-black/20"
|
||||
class="absolute start-0 top-0 h-full w-full rounded-xl bg-linear-to-t from-black/40 via-transparent to-transparent transition-all hover:bg-black/20"
|
||||
></div>
|
||||
<p class="absolute bottom-2 start-4 text-lg text-white max-md:text-sm">
|
||||
{$memoryLaneTitle(memory)}
|
||||
|
@ -28,11 +28,7 @@
|
||||
class="w-fit mt-2 pt-2 pe-2 mb-2 dark:text-immich-dark-fg"
|
||||
aria-expanded={!isCollapsed}
|
||||
>
|
||||
<Icon
|
||||
path={mdiChevronRight}
|
||||
size="24"
|
||||
class="inline-block -mt-2.5 transition-all duration-[250ms] {iconRotation}"
|
||||
/>
|
||||
<Icon path={mdiChevronRight} size="24" class="inline-block -mt-2.5 transition-all duration-250 {iconRotation}" />
|
||||
<span class="font-bold text-3xl text-black dark:text-white">{group.name}</span>
|
||||
<span class="ms-1.5">({$t('places_count', { values: { count: places.length } })})</span>
|
||||
</button>
|
||||
|
@ -112,7 +112,7 @@
|
||||
{/each}
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white">
|
||||
<div class="flex min-h-[calc(66vh-11rem)] w-full place-content-center items-center dark:text-white">
|
||||
<div class="flex flex-col content-center items-center text-center">
|
||||
<Icon path={mdiMapMarkerOff} size="3.5em" />
|
||||
<p class="mt-5 text-3xl font-medium">{$t('no_places')}</p>
|
||||
|
@ -277,7 +277,7 @@
|
||||
class:!rounded-b-none={isOpen && dropdownDirection === 'bottom'}
|
||||
class:!rounded-t-none={isOpen && dropdownDirection === 'top'}
|
||||
class:cursor-pointer={!isActive}
|
||||
class="immich-form-input text-sm w-full !pe-12 transition-all"
|
||||
class="immich-form-input text-sm w-full pe-12! transition-all"
|
||||
id={inputId}
|
||||
onfocus={activate}
|
||||
oninput={onInput}
|
||||
@ -341,7 +341,7 @@
|
||||
role="listbox"
|
||||
id={listboxId}
|
||||
transition:fly={{ duration: 250 }}
|
||||
class="fixed z-[1] text-start text-sm w-full overflow-y-auto bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-900"
|
||||
class="fixed z-1 text-start text-sm w-full overflow-y-auto bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-900"
|
||||
class:rounded-b-xl={dropdownDirection === 'bottom'}
|
||||
class:rounded-t-xl={dropdownDirection === 'top'}
|
||||
class:shadow={dropdownDirection === 'bottom'}
|
||||
|
@ -73,7 +73,7 @@
|
||||
bind:this={menuElement}
|
||||
class="{isVisible
|
||||
? 'max-h-dvh'
|
||||
: 'max-h-0'} flex flex-col transition-all duration-[250ms] ease-in-out outline-none overflow-auto"
|
||||
: 'max-h-0'} flex flex-col transition-all duration-250 ease-in-out outline-none overflow-auto"
|
||||
role="menu"
|
||||
tabindex="-1"
|
||||
>
|
||||
|
@ -66,7 +66,7 @@
|
||||
let buttonClass = $derived(forceDark ? 'hover:text-immich-dark-gray' : undefined);
|
||||
</script>
|
||||
|
||||
<div in:fly={{ y: 10, duration: 200 }} class="absolute top-0 w-full bg-transparent z-[1]">
|
||||
<div in:fly={{ y: 10, duration: 200 }} class="absolute top-0 w-full bg-transparent z-1">
|
||||
<nav
|
||||
id="asset-selection-app-bar"
|
||||
class={[
|
||||
|
@ -52,17 +52,17 @@
|
||||
$effect(() => {
|
||||
switch (width) {
|
||||
case 'extra-wide': {
|
||||
modalWidth = 'w-[56rem]';
|
||||
modalWidth = 'w-4xl';
|
||||
break;
|
||||
}
|
||||
|
||||
case 'wide': {
|
||||
modalWidth = 'w-[48rem]';
|
||||
modalWidth = 'w-3xl';
|
||||
break;
|
||||
}
|
||||
|
||||
case 'narrow': {
|
||||
modalWidth = 'w-[28rem]';
|
||||
modalWidth = 'w-md';
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -497,7 +497,7 @@
|
||||
/>
|
||||
{#if showAssetName && !isTimelineAsset(currentAsset)}
|
||||
<div
|
||||
class="absolute text-center p-1 text-xs font-mono font-semibold w-full bottom-0 bg-gradient-to-t bg-slate-50/75 overflow-clip text-ellipsis whitespace-pre-wrap"
|
||||
class="absolute text-center p-1 text-xs font-mono font-semibold w-full bottom-0 bg-linear-to-t bg-slate-50/75 overflow-clip text-ellipsis whitespace-pre-wrap"
|
||||
>
|
||||
{currentAsset.originalFileName}
|
||||
</div>
|
||||
|
@ -25,7 +25,7 @@
|
||||
in:fade={{ duration: 100 }}
|
||||
out:fade={{ duration: 100 }}
|
||||
id="account-info-panel"
|
||||
class="absolute z-[1] end-[25px] top-[75px] w-[min(360px,100vw-50px)] rounded-3xl bg-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray"
|
||||
class="absolute z-1 end-[25px] top-[75px] w-[min(360px,100vw-50px)] rounded-3xl bg-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray"
|
||||
use:focusTrap
|
||||
>
|
||||
<div
|
||||
|
@ -51,13 +51,10 @@
|
||||
|
||||
<svelte:window bind:innerWidth />
|
||||
|
||||
<nav
|
||||
id="dashboard-navbar"
|
||||
class="max-md:h-[var(--navbar-height-md)] h-[var(--navbar-height)] w-dvw text-sm overflow-hidden"
|
||||
>
|
||||
<nav id="dashboard-navbar" class="max-md:h-(--navbar-height-md) h-(--navbar-height) w-dvw text-sm overflow-hidden">
|
||||
<SkipLink text={$t('skip_to_content')} />
|
||||
<div
|
||||
class="grid h-full grid-cols-[theme(spacing.32)_auto] items-center py-2 sidebar:grid-cols-[theme(spacing.64)_auto] {noBorder
|
||||
class="grid h-full grid-cols-[--spacing(32)_auto] items-center py-2 sidebar:grid-cols-[--spacing(64)_auto] {noBorder
|
||||
? ''
|
||||
: 'border-b'}"
|
||||
>
|
||||
|
@ -39,7 +39,7 @@
|
||||
in:fade={{ duration: 100 }}
|
||||
out:fade={{ duration: 100 }}
|
||||
id="notification-panel"
|
||||
class="absolute right-[25px] top-[70px] z-[1] w-[min(360px,100vw-50px)] rounded-3xl bg-gray-100 border border-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray text-light"
|
||||
class="absolute right-[25px] top-[70px] z-1 w-[min(360px,100vw-50px)] rounded-3xl bg-gray-100 border border-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray text-light"
|
||||
use:focusTrap
|
||||
>
|
||||
<Stack class="max-h-[500px]">
|
||||
|
@ -19,7 +19,7 @@
|
||||
<div class="relative w-full">
|
||||
<input
|
||||
{...rest}
|
||||
class="immich-form-input w-full !pe-12"
|
||||
class="immich-form-input w-full pe-12!"
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
{required}
|
||||
value={password}
|
||||
|
@ -446,7 +446,7 @@
|
||||
aria-valuemax={toScrollY(1)}
|
||||
aria-valuemin={toScrollY(0)}
|
||||
data-id="immich-scrubbable-scrollbar"
|
||||
class="absolute end-0 z-[1] select-none hover:cursor-row-resize"
|
||||
class="absolute end-0 z-1 select-none hover:cursor-row-resize"
|
||||
style:padding-top={PADDING_TOP + 'px'}
|
||||
style:padding-bottom={PADDING_BOTTOM + 'px'}
|
||||
style:width
|
||||
@ -483,7 +483,7 @@
|
||||
out:fade={{ duration: 200 }}
|
||||
>
|
||||
<Icon path={mdiPlay} size="20" class="-rotate-90 relative top-[9px] -end-[2px]" />
|
||||
<Icon path={mdiPlay} size="20" class="rotate-90 relative top-[1px] -end-[2px]" />
|
||||
<Icon path={mdiPlay} size="20" class="rotate-90 relative top-px -end-[2px]" />
|
||||
{#if (assetStore.scrolling && scrollHoverLabel) || isHover || isDragging}
|
||||
<p
|
||||
transition:fade={{ duration: 200 }}
|
||||
@ -521,7 +521,7 @@
|
||||
data-label={segments.at(0)?.dateFormatted}
|
||||
>
|
||||
{#if relativeTopOffset > 6}
|
||||
<div class="absolute end-[0.75rem] h-[4px] w-[4px] rounded-full bg-gray-300"></div>
|
||||
<div class="absolute end-3 h-[4px] w-[4px] rounded-full bg-gray-300"></div>
|
||||
{/if}
|
||||
</div>
|
||||
<!-- Time Segment -->
|
||||
@ -535,12 +535,12 @@
|
||||
>
|
||||
{#if !usingMobileDevice}
|
||||
{#if segment.hasLabel}
|
||||
<div class="absolute end-[1.25rem] top-[-16px] text-[12px] dark:text-immich-dark-fg font-immich-mono">
|
||||
<div class="absolute end-5 top-[-16px] text-[12px] dark:text-immich-dark-fg font-immich-mono">
|
||||
{segment.date.year}
|
||||
</div>
|
||||
{/if}
|
||||
{#if segment.hasDot}
|
||||
<div class="absolute end-[0.75rem] bottom-0 h-[4px] w-[4px] rounded-full bg-gray-300"></div>
|
||||
<div class="absolute end-3 bottom-0 h-[4px] w-[4px] rounded-full bg-gray-300"></div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@
|
||||
{#if queryType === 'smart'}
|
||||
<label for="context-input" class="immich-form-label">{$t('search_by_context')}</label>
|
||||
<input
|
||||
class="immich-form-input hover:cursor-text w-full !mt-1"
|
||||
class="immich-form-input hover:cursor-text w-full mt-1!"
|
||||
type="text"
|
||||
id="context-input"
|
||||
name="context"
|
||||
@ -44,7 +44,7 @@
|
||||
{:else if queryType === 'metadata'}
|
||||
<label for="file-name-input" class="immich-form-label">{$t('search_by_filename')}</label>
|
||||
<input
|
||||
class="immich-form-input hover:cursor-text w-full !mt-1"
|
||||
class="immich-form-input hover:cursor-text w-full mt-1!"
|
||||
type="text"
|
||||
id="file-name-input"
|
||||
name="file-name"
|
||||
@ -55,7 +55,7 @@
|
||||
{:else if queryType === 'description'}
|
||||
<label for="description-input" class="immich-form-label">{$t('search_by_description')}</label>
|
||||
<input
|
||||
class="immich-form-input hover:cursor-text w-full !mt-1"
|
||||
class="immich-form-input hover:cursor-text w-full mt-1!"
|
||||
type="text"
|
||||
id="description-input"
|
||||
name="description"
|
||||
|
@ -70,7 +70,7 @@
|
||||
: 'text-immich-fg dark:text-immich-bg'}"
|
||||
/>
|
||||
<select
|
||||
class="immich-form-input w-full appearance-none row-start-1 col-start-1 !pe-6"
|
||||
class="immich-form-input w-full appearance-none row-start-1 col-start-1 pe-6!"
|
||||
{disabled}
|
||||
aria-describedby={desc ? `${name}-desc` : undefined}
|
||||
{name}
|
||||
|
@ -31,7 +31,7 @@
|
||||
<a
|
||||
href={getLink(path)}
|
||||
title={value}
|
||||
class={`flex flex-grow place-items-center ps-2 py-1 text-sm rounded-lg hover:bg-slate-200 dark:hover:bg-slate-800 hover:font-semibold ${isTarget ? 'bg-slate-100 dark:bg-slate-700 font-semibold text-immich-primary dark:text-immich-dark-primary' : 'dark:text-gray-200'}`}
|
||||
class={`flex grow place-items-center ps-2 py-1 text-sm rounded-lg hover:bg-slate-200 dark:hover:bg-slate-800 hover:font-semibold ${isTarget ? 'bg-slate-100 dark:bg-slate-700 font-semibold text-immich-primary dark:text-immich-dark-primary' : 'dark:text-gray-200'}`}
|
||||
data-sveltekit-keepfocus
|
||||
>
|
||||
<button type="button" {onclick} class={Object.values(tree).length === 0 ? 'invisible' : ''}>
|
||||
|
@ -35,7 +35,7 @@
|
||||
id="sidebar"
|
||||
aria-label={ariaLabel}
|
||||
tabindex="-1"
|
||||
class="immich-scrollbar relative z-[1] w-0 sidebar:w-[16rem] overflow-y-auto overflow-x-hidden pt-8 transition-all duration-200 bg-light"
|
||||
class="immich-scrollbar relative z-1 w-0 sidebar:w-[16rem] overflow-y-auto overflow-x-hidden pt-8 transition-all duration-200 bg-light"
|
||||
class:shadow-2xl={isExpanded}
|
||||
class:dark:border-e-immich-dark-gray={isExpanded}
|
||||
class:border-r={isExpanded}
|
||||
|
@ -113,7 +113,7 @@
|
||||
]}
|
||||
/>
|
||||
|
||||
<div class="pt-4 rounded-3xl border dark:border-2 border-gray-300 dark:border-gray-700 max-w-[54rem] mx-auto mb-16">
|
||||
<div class="pt-4 rounded-3xl border dark:border-2 border-gray-300 dark:border-gray-700 max-w-216 mx-auto mb-16">
|
||||
<div class="flex flex-wrap gap-y-6 mb-4 px-6 w-full place-content-end justify-between">
|
||||
<!-- MARK ALL BUTTONS -->
|
||||
<div class="flex text-xs text-black">
|
||||
|
@ -91,7 +91,7 @@
|
||||
</div>
|
||||
|
||||
<!-- <UserAvatar {user} size="md" /> -->
|
||||
<div class="text-start flex-grow">
|
||||
<div class="text-start grow">
|
||||
<p class="text-immich-fg dark:text-immich-dark-fg">
|
||||
{user.name}
|
||||
</p>
|
||||
@ -133,7 +133,7 @@
|
||||
class="flex w-full place-items-center gap-4 p-4"
|
||||
>
|
||||
<UserAvatar {user} size="md" />
|
||||
<div class="text-start flex-grow">
|
||||
<div class="text-start grow">
|
||||
<p class="text-immich-fg dark:text-immich-dark-fg">
|
||||
{user.name}
|
||||
</p>
|
||||
|
@ -168,7 +168,7 @@
|
||||
<Modal icon={mdiTune} size="giant" title={$t('search_options')} {onClose}>
|
||||
<ModalBody>
|
||||
<form id={formId} autocomplete="off" {onsubmit} {onreset}>
|
||||
<div class="space-y-10 pb-10" tabindex="-1">
|
||||
<div class="flex flex-col gap-4 pb-10" tabindex="-1">
|
||||
<!-- PEOPLE -->
|
||||
<SearchPeopleSection bind:selectedPeople={filter.personIds} />
|
||||
|
||||
|
@ -597,7 +597,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<main class="relative h-dvh overflow-hidden px-6 max-md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)]">
|
||||
<main class="relative h-dvh overflow-hidden px-6 max-md:pt-(--navbar-height-md) pt-(--navbar-height)">
|
||||
<AssetGrid
|
||||
enableRouting={viewMode === AlbumPageViewMode.SELECT_ASSETS ? false : true}
|
||||
{album}
|
||||
@ -699,7 +699,7 @@
|
||||
</AssetGrid>
|
||||
|
||||
{#if showActivityStatus}
|
||||
<div class="absolute z-[2] bottom-0 end-0 mb-6 me-6 justify-self-end">
|
||||
<div class="absolute z-2 bottom-0 end-0 mb-6 me-6 justify-self-end">
|
||||
<ActivityStatus
|
||||
disabled={!album.isActivityEnabled}
|
||||
isLiked={activityManager.isLiked}
|
||||
@ -716,7 +716,7 @@
|
||||
<div
|
||||
transition:fly={{ duration: 150 }}
|
||||
id="activity-panel"
|
||||
class="z-[2] w-[360px] md:w-[460px] overflow-y-auto transition-all dark:border-l dark:border-s-immich-dark-gray"
|
||||
class="z-2 w-[360px] md:w-[460px] overflow-y-auto transition-all dark:border-l dark:border-s-immich-dark-gray"
|
||||
translate="yes"
|
||||
>
|
||||
<ActivityViewer
|
||||
|
@ -153,7 +153,7 @@
|
||||
|
||||
<Breadcrumbs {pathSegments} icon={mdiFolderHome} title={$t('folders')} getLink={getLinkForPath} />
|
||||
|
||||
<section class="mt-2 h-[calc(100%-theme(spacing.20))] overflow-auto immich-scrollbar">
|
||||
<section class="mt-2 h-[calc(100%-(--spacing(20)))] overflow-auto immich-scrollbar">
|
||||
<TreeItemThumbnails items={currentTreeItems} icon={mdiFolder} onClick={handleNavigateToFolder} />
|
||||
|
||||
<!-- Assets -->
|
||||
|
@ -387,7 +387,7 @@
|
||||
{/snippet}
|
||||
</PeopleInfiniteScroll>
|
||||
{:else}
|
||||
<div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white">
|
||||
<div class="flex min-h-[calc(66vh-11rem)] w-full place-content-center items-center dark:text-white">
|
||||
<div class="flex flex-col content-center items-center text-center">
|
||||
<Icon path={mdiAccountOff} size="3.5em" />
|
||||
<p class="mt-5 text-3xl font-medium max-w-lg line-clamp-2 overflow-hidden">
|
||||
|
@ -362,7 +362,7 @@
|
||||
</script>
|
||||
|
||||
<main
|
||||
class="relative z-0 h-dvh overflow-hidden tall:ms-4 md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)]"
|
||||
class="relative z-0 h-dvh overflow-hidden tall:ms-4 md:pt-(--navbar-height-md) pt-(--navbar-height)"
|
||||
use:scrollMemoryClearer={{
|
||||
routeStartsWith: AppRoute.PEOPLE,
|
||||
beforeClear: () => {
|
||||
|
@ -366,7 +366,7 @@
|
||||
pageHeaderOffset={54}
|
||||
/>
|
||||
{:else if !isLoading}
|
||||
<div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white">
|
||||
<div class="flex min-h-[calc(66vh-11rem)] w-full place-content-center items-center dark:text-white">
|
||||
<div class="flex flex-col content-center items-center text-center">
|
||||
<Icon path={mdiImageOffOutline} size="3.5em" />
|
||||
<p class="mt-5 text-3xl font-medium">{$t('no_results')}</p>
|
||||
|
@ -59,7 +59,7 @@
|
||||
</svelte:head>
|
||||
{#if passwordRequired}
|
||||
<main
|
||||
class="relative h-dvh overflow-hidden px-6 max-md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)] sm:px-12 md:px-24 lg:px-40"
|
||||
class="relative h-dvh overflow-hidden px-6 max-md:pt-(--navbar-height-md) pt-(--navbar-height) sm:px-12 md:px-24 lg:px-40"
|
||||
>
|
||||
<div class="flex flex-col items-center justify-center mt-20">
|
||||
<div class="text-2xl font-bold text-immich-primary dark:text-immich-dark-primary">{$t('password_required')}</div>
|
||||
|
@ -178,7 +178,7 @@
|
||||
|
||||
<Breadcrumbs {pathSegments} icon={mdiTagMultiple} title={$t('tags')} {getLink} />
|
||||
|
||||
<section class="mt-2 h-[calc(100%-theme(spacing.20))] overflow-auto immich-scrollbar">
|
||||
<section class="mt-2 h-[calc(100%-(--spacing(20)))] overflow-auto immich-scrollbar">
|
||||
{#if tag}
|
||||
<AssetGrid enableRouting={true} {assetStore} {assetInteraction} removeAction={AssetAction.UNARCHIVE}>
|
||||
{#snippet empty()}
|
||||
|
@ -16,7 +16,6 @@
|
||||
import { copyToClipboard } from '$lib/utils';
|
||||
import { isAssetViewerRoute } from '$lib/utils/navigation';
|
||||
import { setTranslations } from '@immich/ui';
|
||||
import '@immich/ui/theme/default.css';
|
||||
import { onMount, type Snippet } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { run } from 'svelte/legacy';
|
||||
|
@ -1,8 +1,5 @@
|
||||
import { tailwindConfig } from '@immich/ui/theme/default.js';
|
||||
import plugin from 'tailwindcss/plugin';
|
||||
|
||||
const { colors, borderColor } = tailwindConfig();
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
@ -10,7 +7,6 @@ export default {
|
||||
'./node_modules/@immich/ui/dist/**/*.{svelte,js}',
|
||||
'../../ui/src/**/*.{html,js,svelte,ts}',
|
||||
],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
@ -31,10 +27,7 @@ export default {
|
||||
'immich-dark-error': 'rgb(var(--immich-dark-error) / <alpha-value>)',
|
||||
'immich-dark-success': 'rgb(var(--immich-dark-success) / <alpha-value>)',
|
||||
'immich-dark-warning': 'rgb(var(--immich-dark-warning) / <alpha-value>)',
|
||||
|
||||
...colors,
|
||||
},
|
||||
borderColor,
|
||||
fontFamily: {
|
||||
'immich-mono': ['Overpass Mono', 'monospace'],
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { enhancedImages } from '@sveltejs/enhanced-img';
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import { svelteTesting } from '@testing-library/svelte/vite';
|
||||
import path from 'node:path';
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
@ -36,6 +37,7 @@ export default defineConfig({
|
||||
},
|
||||
plugins: [
|
||||
enhancedImages(),
|
||||
tailwindcss(),
|
||||
sveltekit(),
|
||||
process.env.BUILD_STATS === 'true'
|
||||
? visualizer({
|
||||
|
Loading…
x
Reference in New Issue
Block a user