Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web): better overall responsiveness #8776

Draft
wants to merge 53 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
6f70852
fix main layout overflow on some mobile browsers
Ethan13310 Apr 12, 2024
bad6274
prevent bouncing when overscrolling on touch devices
Ethan13310 Apr 12, 2024
287c920
add media breakpoint utils
Ethan13310 Apr 13, 2024
065a543
outclick event: dispatch source event
Ethan13310 Apr 13, 2024
6a54647
rework sidebar: better animations + now mobile-friendly
Ethan13310 Apr 13, 2024
642b3a6
fix map being stacked over the sidebar during its loading on ios safari
Ethan13310 Apr 13, 2024
08d47cd
outclick event is now correctly emitted on touch devices
Ethan13310 Apr 13, 2024
7793061
fix sidebar outclick handling on touch devices
Ethan13310 Apr 14, 2024
472c1df
fix (regression) status box not stuck to the bottom of the sidebar
Ethan13310 Apr 14, 2024
e25030b
fix page margins on small screens
Ethan13310 Apr 14, 2024
b879ee7
close sidebar when switching page
Ethan13310 Apr 14, 2024
4e4a12e
fix media breakpoint computation when a sudden width change occurs
Ethan13310 Apr 14, 2024
1d28ff7
update admin sidebar status box transition
Ethan13310 Apr 14, 2024
1461a9f
fix main section top padding
Ethan13310 Apr 14, 2024
c74fc56
update navbar buttons
Ethan13310 Apr 14, 2024
69691cb
prevent account info panel from overflowing on small screens
Ethan13310 Apr 14, 2024
32d47c3
navbar: move theme and admin buttons to account info panel on small s…
Ethan13310 Apr 14, 2024
e90948f
navbar: fix immich logo display
Ethan13310 Apr 14, 2024
17d1e41
display search bar in full width on small screens
Ethan13310 Apr 16, 2024
b3c78af
add minimal width to the search filter box
Ethan13310 Apr 17, 2024
c2155ae
fix linter
Ethan13310 Apr 17, 2024
5d0c03b
remove layout margin on map page on small screens
Ethan13310 Apr 20, 2024
74964d7
prevent dropdown from overflowing the screen
Ethan13310 Apr 20, 2024
b5c1ac5
make album cards smaller on small and medium screens
Ethan13310 Apr 20, 2024
0bf73cc
make dropdown breakpoint coherent with other buttons
Ethan13310 Apr 20, 2024
07ee8b5
update album list columns width
Ethan13310 Apr 20, 2024
b8546cd
update album controls
Ethan13310 Apr 21, 2024
3d35876
tweak search bar animation
Ethan13310 Apr 21, 2024
1c9a3fb
update sharing page buttons
Ethan13310 Apr 21, 2024
b0e2121
add input device realtime detection
Ethan13310 Apr 21, 2024
4411266
remove album card context menu button on touch devices
Ethan13310 Apr 21, 2024
e4656d1
fix hover glitches on touch screens
Ethan13310 Apr 21, 2024
1ef86a7
fix touch screen detection
Ethan13310 Apr 21, 2024
ce6ac9a
add more media breakpoints
Ethan13310 Apr 22, 2024
5a6224a
fix some glitches on small and very small screens
Ethan13310 Apr 22, 2024
f3281d6
album list view: change shown columns on smaller screens
Ethan13310 Apr 22, 2024
4d76276
allow dropdowns to be toggled
Ethan13310 Apr 22, 2024
77ed69c
make the scrollbar work with touch screens
Ethan13310 Apr 22, 2024
681649b
split user page layout to have a very minimal layout
Ethan13310 Apr 25, 2024
c7a5a82
remove small space between asset date group and header on the album view
Ethan13310 Apr 25, 2024
27d8648
use root layout on the album view page
Ethan13310 Apr 25, 2024
b6bff5b
fix autogrow still showing an scroll bar
Ethan13310 Apr 25, 2024
56105ef
add content editable div component
Ethan13310 Apr 25, 2024
1c2b087
use the content editable div component for album title and description
Ethan13310 Apr 25, 2024
542dda5
small symbol fix
Ethan13310 Apr 25, 2024
f97df72
fix formatting
Ethan13310 Apr 25, 2024
8db1849
always use small scrollbar on touch devices
Ethan13310 Apr 26, 2024
0e56612
remove map page title header on small screens
Ethan13310 Apr 27, 2024
c583118
prevent dropdowns from being larger than the screen
Ethan13310 Apr 27, 2024
a267714
reduce album header top margin on small screens
Ethan13310 Apr 27, 2024
1261bab
remove nav bar search button margin on small screens
Ethan13310 Apr 27, 2024
0b35249
fix media breakpoint store
Ethan13310 Apr 28, 2024
1634e79
add window viewport store
Ethan13310 Apr 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<!-- metadata:tags -->

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />
Expand Down
53 changes: 42 additions & 11 deletions web/src/lib/components/album-page/album-card-group.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,30 @@
{#if group}
<div class="grid">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<p on:click={() => toggleAlbumGroupCollapsing(group.id)} class="w-fit mt-2 pt-2 pr-2 mb-2 hover:cursor-pointer">
<Icon
path={mdiChevronRight}
size="24"
class="inline-block -mt-2.5 transition-all duration-[250ms] {iconRotation}"
/>
<span class="font-bold text-3xl text-black dark:text-white">{group.name}</span>
<span class="ml-1.5 dark:text-immich-dark-fg">({albums.length} {albums.length > 1 ? 'albums' : 'album'})</span>
</p>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
on:click={() => toggleAlbumGroupCollapsing(group.id)}
class="flex w-fit mt-2 pt-2 pr-2 mb-2 hover:cursor-pointer"
>
<div class="mt-2.5 mr-1">
<Icon
path={mdiChevronRight}
size="24"
class="inline-block -mt-2.5 transition-all duration-[250ms] {iconRotation}"
/>
</div>
<div>
<span class="font-bold text-2xl text-black dark:text-white mr-1.5">{group.name}</span>
<span class="dark:text-immich-dark-fg">({albums.length} {albums.length > 1 ? 'albums' : 'album'})</span>
</div>
</div>
<hr class="dark:border-immich-dark-gray" />
</div>
{/if}

<div class="mt-4">
{#if !isCollapsed}
<div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))] gap-y-4" transition:slide={{ duration: 300 }}>
<div class="grid album-grid" transition:slide={{ duration: 300 }}>
{#each albums as album, index (album.id)}
<a
data-sveltekit-preload-data="hover"
Expand All @@ -67,3 +74,27 @@
</div>
{/if}
</div>

<style lang="postcss">
.album-grid {
@apply gap-y-1 grid-cols-[repeat(auto-fill,minmax(7rem,1fr))];
}

@screen 2xs {
.album-grid {
@apply gap-y-1 grid-cols-[repeat(auto-fill,minmax(9rem,1fr))];
}
}

@screen sm {
.album-grid {
@apply gap-y-2 grid-cols-[repeat(auto-fill,minmax(11rem,1fr))];
}
}

@screen lg {
.album-grid {
@apply gap-y-4 grid-cols-[repeat(auto-fill,minmax(14rem,1fr))];
}
}
</style>
11 changes: 6 additions & 5 deletions web/src/lib/components/album-page/album-card.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { getShortDateRange } from '$lib/utils/date-time';
import IconButton from '$lib/components/elements/buttons/icon-button.svelte';
import AlbumCover from '$lib/components/album-page/album-cover.svelte';
import { isUserUsingMouse } from '$lib/stores/input-device.store';

export let album: AlbumResponseDto;
export let showOwner = false;
Expand All @@ -24,10 +25,10 @@
</script>

<div
class="group relative rounded-2xl border border-transparent p-5 hover:bg-gray-100 hover:border-gray-200 dark:hover:border-gray-800 dark:hover:bg-gray-900"
class="group relative rounded-2xl border border-transparent p-3 sm:p-4 lg:p-5 hover:bg-gray-100 hover:border-gray-200 dark:hover:border-gray-800 dark:hover:bg-gray-900"
data-testid="album-card"
>
{#if onShowContextMenu}
{#if onShowContextMenu && $isUserUsingMouse}
<div
id="icon-{album.id}"
class="absolute right-6 top-6 z-10 opacity-0 group-hover:opacity-100 focus-within:opacity-100"
Expand All @@ -43,20 +44,20 @@

<div class="mt-4">
<p
class="w-full leading-6 text-lg line-clamp-2 font-semibold text-black dark:text-white group-hover:text-immich-primary dark:group-hover:text-immich-dark-primary"
class="w-full leading-5 max-sm:mb-0.5 sm:leading-6 sm:text-lg line-clamp-2 font-semibold text-black dark:text-white group-hover:text-immich-primary dark:group-hover:text-immich-dark-primary"
data-testid="album-name"
title={album.albumName}
>
{album.albumName}
</p>

{#if showDateRange && album.startDate && album.endDate}
<p class="flex text-sm dark:text-immich-dark-fg capitalize">
<p class="flex text-xs sm:text-sm dark:text-immich-dark-fg capitalize">
{getShortDateRange(album.startDate, album.endDate)}
</p>
{/if}

<span class="flex gap-2 text-sm" data-testid="album-details">
<span class="flex gap-2 text-xs sm:text-sm" data-testid="album-details">
{#if showItemCount}
<p>
{album.assetCount.toLocaleString($locale)}
Expand Down
29 changes: 12 additions & 17 deletions web/src/lib/components/album-page/album-description.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<script lang="ts">
import { autoGrowHeight } from '$lib/utils/autogrow';
import { updateAlbumInfo } from '@immich/sdk';
import { handleError } from '$lib/utils/handle-error';
import { shortcut } from '$lib/utils/shortcut';
import ContentEditableDiv from '$lib/components/elements/content-editable-div.svelte';

export let id: string;
export let description: string;
Expand Down Expand Up @@ -30,21 +29,17 @@
};
</script>

{#if isOwned}
<textarea
class="w-full mt-2 resize-none text-black dark:text-white border-b-2 border-transparent border-gray-500 bg-transparent text-base outline-none transition-all focus:border-b-2 focus:border-immich-primary disabled:border-none dark:focus:border-immich-dark-primary hover:border-gray-400"
bind:value={newDescription}
on:input={(e) => autoGrowHeight(e.currentTarget)}
on:focusout={handleUpdateDescription}
use:autoGrowHeight
{#if isOwned || description}
<ContentEditableDiv
className="w-full mt-6 mb-7 pb-1 text-black dark:text-white border-b-2 border-transparent text-base outline-none
transition-all focus:border-b-2 focus:border-immich-primary dark:focus:border-immich-dark-primary
hover:border-gray-400 {isOwned ? '' : '!border-transparent'}"
on:blur={handleUpdateDescription}
bind:textContent={newDescription}
title="Edit album description"
placeholder="Add a description"
use:shortcut={{
shortcut: { key: 'Enter', ctrl: true },
onShortcut: (e) => e.currentTarget.blur(),
}}
disabled={!isOwned}
/>
{:else if description}
<p class="break-words whitespace-pre-line w-full text-black dark:text-white text-base">
{description}
</p>
{:else}
<div class="mb-7" />
{/if}
2 changes: 1 addition & 1 deletion web/src/lib/components/album-page/album-summary.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@

<span class="my-2 flex gap-2 text-sm font-medium text-gray-500" data-testid="album-details">
<p>{getDateRange(startDate, endDate)}</p>
<p>·</p>
<p></p>
<p>{album.assetCount} items</p>
</span>
27 changes: 13 additions & 14 deletions web/src/lib/components/album-page/album-title.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { updateAlbumInfo } from '@immich/sdk';
import { handleError } from '$lib/utils/handle-error';
import { shortcut } from '$lib/utils/shortcut';
import ContentEditableDiv from '$lib/components/elements/content-editable-div.svelte';

export let id: string;
export let albumName: string;
Expand All @@ -13,31 +13,30 @@
if (newAlbumName === albumName) {
return;
}

try {
await updateAlbumInfo({
id,
updateAlbumDto: {
albumName: newAlbumName,
},
});
albumName = newAlbumName;
} catch (error) {
handleError(error, 'Unable to update album name');
return;
handleError(error, 'Failed to update album name');
}
albumName = newAlbumName;
};
</script>

<input
use:shortcut={{ shortcut: { key: 'Enter' }, onShortcut: (e) => e.currentTarget.blur() }}
<ContentEditableDiv
className="w-full mt-2.5 mb-4 pb-2.5 text-4xl md:text-6xl border-b-2 border-transparent break-words
outline-none focus:outline-none transition-all text-immich-primary dark:text-immich-dark-primary
{isOwned ? 'hover:border-gray-400' : ''} focus:border-b-2 focus:border-immich-primary
dark:focus:border-immich-dark-primary"
on:blur={handleUpdateName}
class="w-[99%] mb-2 border-b-2 border-transparent text-6xl text-immich-primary outline-none transition-all dark:text-immich-dark-primary {isOwned
? 'hover:border-gray-400'
: 'hover:border-transparent'} bg-immich-bg focus:border-b-2 focus:border-immich-primary focus:outline-none dark:bg-immich-dark-bg dark:focus:border-immich-dark-primary dark:focus:bg-immich-dark-gray"
type="text"
bind:value={newAlbumName}
bind:textContent={newAlbumName}
title="Edit album title"
spellcheck={false}
placeholder={isOwned ? 'Add a Title' : 'Untitled Album'}
disabled={!isOwned}
title="Edit Title"
placeholder="Add a title"
nowrap
/>
100 changes: 75 additions & 25 deletions web/src/lib/components/album-page/albums-controls.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
import {
mdiArrowDownThin,
mdiArrowUpThin,
mdiFilterOutline,
mdiFolderArrowDownOutline,
mdiFolderArrowUpOutline,
mdiFolderRemoveOutline,
mdiFormatListBulletedSquare,
mdiMagnify,
mdiPlusBoxOutline,
mdiUnfoldLessHorizontal,
mdiUnfoldMoreHorizontal,
Expand All @@ -24,6 +26,9 @@
import {
type AlbumGroupOptionMetadata,
type AlbumSortOptionMetadata,
collapseAllAlbumGroups,
createAlbumAndRedirect,
expandAllAlbumGroups,
findGroupOptionMetadata,
findSortOptionMetadata,
getSelectedAlbumGroupOption,
Expand All @@ -32,8 +37,8 @@
} from '$lib/utils/album-utils';
import SearchBar from '$lib/components/elements/search-bar.svelte';
import GroupTab from '$lib/components/elements/group-tab.svelte';
import { createAlbumAndRedirect, collapseAllAlbumGroups, expandAllAlbumGroups } from '$lib/utils/album-utils';
import { fly } from 'svelte/transition';
import { currentMediaBreakpoint, MediaBreakpoint } from '$lib/stores/media-breakpoint.store';

export let albumGroups: string[];
export let searchQuery: string;
Expand Down Expand Up @@ -65,8 +70,13 @@
$albumViewSettings.view === AlbumViewMode.Cover ? AlbumViewMode.List : AlbumViewMode.Cover;
};

const closeSearchBar = () => {
isSearchBarOpen = false;
};

let selectedGroupOption: AlbumGroupOptionMetadata;
let groupIcon: string;
let isSearchBarOpen = false;

$: {
selectedGroupOption = findGroupOptionMetadata($albumViewSettings.groupBy);
Expand All @@ -75,6 +85,8 @@
}
}

$: showSearchBar = isSearchBarOpen || searchQuery || $currentMediaBreakpoint >= MediaBreakpoint.XL;

$: selectedSortOption = findSortOptionMetadata($albumViewSettings.sortBy);

$: {
Expand All @@ -89,8 +101,8 @@
$: sortIcon = $albumViewSettings.sortOrder === SortOrder.Desc ? mdiArrowDownThin : mdiArrowUpThin;
</script>

<!-- Filter Albums by Sharing Status (All, Owned, Shared) -->
<div class="hidden xl:block h-10">
<!-- VERY LARGE SCREENS: Filter Albums by Sharing Status (All, Owned, Shared) -->
<div class="hidden 2xl:block h-10">
<GroupTab
filters={Object.keys(AlbumFilter)}
selected={$albumViewSettings.filter}
Expand All @@ -99,8 +111,48 @@
</div>

<!-- Search Albums -->
<div class="hidden xl:block h-10 xl:w-60 2xl:w-80">
<SearchBar placeholder="Search albums" bind:name={searchQuery} isSearching={false} />
{#if $currentMediaBreakpoint >= MediaBreakpoint.XL}
<div class="h-10 w-48 2xl:w-60">
<SearchBar placeholder="Search albums" bind:name={searchQuery} isSearching={false} />
</div>
{:else if showSearchBar}
<div class="absolute left-0 right-0 z-10">
<div
class="ml-auto max-w-[700px]"
transition:fly={{
duration: 200,
}}
>
<SearchBar
placeholder="Search albums"
bind:name={searchQuery}
isSearching={false}
focus
on:blur={closeSearchBar}
on:submit={closeSearchBar}
/>
</div>
</div>
{:else}
<LinkButton on:click={() => (isSearchBarOpen = true)}>
<div class="flex">
<Icon path={mdiMagnify} size="18" />
</div>
</LinkButton>
{/if}

<!-- SMALL TO LARGE SCREENS: Filter Albums by Sharing Status -->
<div class="hidden 2xs:block 2xl:hidden">
<Dropdown
title="Filter albums"
options={Object.keys(AlbumFilter)}
selectedOption={$albumViewSettings.filter}
on:select={({ detail }) => ($albumViewSettings.filter = detail)}
render={(text) => ({
title: text,
icon: mdiFilterOutline,
})}
/>
</div>

<!-- Create Album -->
Expand Down Expand Up @@ -137,27 +189,25 @@
/>

{#if getSelectedAlbumGroupOption($albumViewSettings) !== AlbumGroupBy.None}
<span in:fly={{ x: -50, duration: 250 }}>
<!-- Expand Album Groups -->
<div class="hidden xl:flex gap-0">
<div class="block">
<LinkButton title="Expand all" on:click={() => expandAllAlbumGroups()}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiUnfoldMoreHorizontal} size="18" />
</div>
</LinkButton>
</div>

<!-- Collapse Album Groups -->
<div class="block">
<LinkButton title="Collapse all" on:click={() => collapseAllAlbumGroups(albumGroups)}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiUnfoldLessHorizontal} size="18" />
</div>
</LinkButton>
</div>
<!-- Expand Album Groups -->
<div class="hidden xl:flex gap-0">
<div class="block">
<LinkButton title="Expand all" on:click={() => expandAllAlbumGroups()}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiUnfoldMoreHorizontal} size="18" />
</div>
</LinkButton>
</div>
</span>

<!-- Collapse Album Groups -->
<div class="block">
<LinkButton title="Collapse all" on:click={() => collapseAllAlbumGroups(albumGroups)}>
<div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiUnfoldLessHorizontal} size="18" />
</div>
</LinkButton>
</div>
</div>
{/if}

<!-- Cover/List Display Toggle -->
Expand Down