From 72ce81f0c2d49eb5e3845f23161ad69b83cf7810 Mon Sep 17 00:00:00 2001 From: Ben <45583362+ben-basten@users.noreply.github.com> Date: Mon, 29 Apr 2024 21:17:22 +0000 Subject: [PATCH 1/7] feat(web,a11y): replace IconButton with CircleIconButton (#9153) * feat(web,a11y): replace IconButton with CircleIconButton * wip: cleanup * wip: bring back viewbox * fix: add label to search bar --- .../components/album-page/album-card.svelte | 15 ++-- .../buttons/circle-icon-button.svelte | 8 +- .../elements/buttons/icon-button.svelte | 14 ---- .../components/faces-page/people-card.svelte | 25 +++--- .../components/faces-page/show-hide.svelte | 4 +- .../shared-components/combobox.svelte | 6 +- .../navigation-bar/navigation-bar.svelte | 10 +-- .../search-bar/search-bar.svelte | 84 ++++++++----------- .../shared-components/theme-button.svelte | 14 ++-- web/src/routes/(user)/people/+page.svelte | 6 +- .../routes/(user)/user-settings/+page.svelte | 11 +-- 11 files changed, 85 insertions(+), 112 deletions(-) delete mode 100644 web/src/lib/components/elements/buttons/icon-button.svelte diff --git a/web/src/lib/components/album-page/album-card.svelte b/web/src/lib/components/album-page/album-card.svelte index a4dc9aaa6b22ce..9dce0b739d0fdf 100644 --- a/web/src/lib/components/album-page/album-card.svelte +++ b/web/src/lib/components/album-page/album-card.svelte @@ -1,13 +1,12 @@ - - - - diff --git a/web/src/lib/components/faces-page/people-card.svelte b/web/src/lib/components/faces-page/people-card.svelte index e8287991bbd3d2..8daac796d8173d 100644 --- a/web/src/lib/components/faces-page/people-card.svelte +++ b/web/src/lib/components/faces-page/people-card.svelte @@ -1,5 +1,4 @@ {#if !$colorTheme.system} - - {#if $colorTheme.value === Theme.LIGHT} - - {:else} - - {/if} - + {/if} diff --git a/web/src/routes/(user)/people/+page.svelte b/web/src/routes/(user)/people/+page.svelte index 2451f118c94e11..864bc9f6e06724 100644 --- a/web/src/routes/(user)/people/+page.svelte +++ b/web/src/routes/(user)/people/+page.svelte @@ -3,7 +3,6 @@ import { page } from '$app/stores'; import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte'; import Button from '$lib/components/elements/buttons/button.svelte'; - import IconButton from '$lib/components/elements/buttons/icon-button.svelte'; import Icon from '$lib/components/elements/icon.svelte'; import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte'; import PeopleCard from '$lib/components/faces-page/people-card.svelte'; @@ -41,6 +40,7 @@ import type { PageData } from './$types'; import { locale } from '$lib/stores/preferences.store'; import { clearQueryParam } from '$lib/utils/navigation'; + import LinkButton from '$lib/components/elements/buttons/link-button.svelte'; export let data: PageData; @@ -429,12 +429,12 @@ /> - (selectHidden = !selectHidden)}> + (selectHidden = !selectHidden)}>

Show & hide people

-
+ {/if} diff --git a/web/src/routes/(user)/user-settings/+page.svelte b/web/src/routes/(user)/user-settings/+page.svelte index d23ecda446c45e..76e19ff19761e4 100644 --- a/web/src/routes/(user)/user-settings/+page.svelte +++ b/web/src/routes/(user)/user-settings/+page.svelte @@ -1,11 +1,10 @@
dispatch('search', { force: false })} /> - {#if isSearching} + {#if showLoadingSpinner}
diff --git a/web/src/lib/components/faces-page/assign-face-side-panel.svelte b/web/src/lib/components/faces-page/assign-face-side-panel.svelte index 7f48a9eae83f0a..a329b3e4ed26de 100644 --- a/web/src/lib/components/faces-page/assign-face-side-panel.svelte +++ b/web/src/lib/components/faces-page/assign-face-side-panel.svelte @@ -1,16 +1,9 @@
- {#if isShowLoadingSearch}
@@ -227,56 +192,31 @@

All people

- {#if searchName == ''} - {#each allPeople as person (person.id)} - {#if person.id !== editedPerson.id} -
- -
- {/if} - {/each} - {:else} - {#each searchedPeople as person (person.id)} - {#if person.id !== editedPerson.id} -
- -
- {/if} - {/each} - {/if} + {#each showPeople as person (person.id)} + {#if person.id !== editedPerson.id} +
+ +
+ {/if} + {/each}
diff --git a/web/src/lib/components/faces-page/edit-name-input.svelte b/web/src/lib/components/faces-page/edit-name-input.svelte index f01ecd67e7453d..f650e54d452bed 100644 --- a/web/src/lib/components/faces-page/edit-name-input.svelte +++ b/web/src/lib/components/faces-page/edit-name-input.svelte @@ -1,29 +1,23 @@
0 ? 'rounded-t-lg dark:border-immich-dark-gray' : 'rounded-lg'} bg-gray-100 p-2 dark:bg-gray-700" > @@ -33,13 +27,13 @@ autocomplete="off" on:submit|preventDefault={() => dispatch('change', name)} > - dispatch('input')} + diff --git a/web/src/lib/components/faces-page/people-list.svelte b/web/src/lib/components/faces-page/people-list.svelte index 5edf20899b4d51..ac3201e98b2f20 100644 --- a/web/src/lib/components/faces-page/people-list.svelte +++ b/web/src/lib/components/faces-page/people-list.svelte @@ -1,11 +1,8 @@
- { - people = peopleCopy; - }} - on:search={({ detail }) => searchPeople(detail.force ?? false)} + bind:searchName={name} + bind:searchedPeopleLocal={people} + onReset={() => (people = peopleCopy)} />
@@ -69,7 +38,7 @@ style:max-height={screenHeight - 400 + 'px'} >
- {#each people as person (person.id)} + {#each showPeople as person (person.id)} { diff --git a/web/src/lib/components/faces-page/people-search.svelte b/web/src/lib/components/faces-page/people-search.svelte new file mode 100644 index 00000000000000..3a9f28d5fbce99 --- /dev/null +++ b/web/src/lib/components/faces-page/people-search.svelte @@ -0,0 +1,100 @@ + + +{#if type === 'searchBar'} + handleSearch(detail.force ?? false)} + /> +{:else} + handleSearch(false)} + use:initInput + /> +{/if} diff --git a/web/src/lib/components/shared-components/change-location.svelte b/web/src/lib/components/shared-components/change-location.svelte index 57b2aabb490b2b..e9a2b01307de67 100644 --- a/web/src/lib/components/shared-components/change-location.svelte +++ b/web/src/lib/components/shared-components/change-location.svelte @@ -23,7 +23,7 @@ let suggestedPlaces: PlacesResponseDto[] = []; let searchWord: string; let latestSearchTimeout: number; - let showSpinner = false; + let showLoadingSpinner = false; let suggestionContainer: HTMLDivElement; let hideSuggestion = false; let addClipMapMarker: (long: number, lat: number) => void; @@ -74,14 +74,14 @@ if (latestSearchTimeout) { clearTimeout(latestSearchTimeout); } - showSpinner = true; + showLoadingSpinner = true; const searchTimeout = window.setTimeout(() => { searchPlaces({ name: searchWord }) .then((searchResult) => { // skip result when a newer search is happening if (latestSearchTimeout === searchTimeout) { places = searchResult; - showSpinner = false; + showLoadingSpinner = false; } }) .catch((error) => { @@ -89,7 +89,7 @@ if (latestSearchTimeout === searchTimeout) { places = []; handleError(error, "Can't search places"); - showSpinner = false; + showLoadingSpinner = false; } }); }, timeDebounceOnSearch); @@ -121,7 +121,7 @@ { suggestedPlaces = []; }} diff --git a/web/src/lib/components/shared-components/search-bar/search-people-section.svelte b/web/src/lib/components/shared-components/search-bar/search-people-section.svelte index b97016396a69e4..a0f476de14f981 100644 --- a/web/src/lib/components/shared-components/search-bar/search-people-section.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-people-section.svelte @@ -56,7 +56,7 @@

PEOPLE

- +
diff --git a/web/src/lib/utils/navigation.ts b/web/src/lib/utils/navigation.ts index e5cb25793e7746..356ea888a41bd8 100644 --- a/web/src/lib/utils/navigation.ts +++ b/web/src/lib/utils/navigation.ts @@ -81,6 +81,6 @@ export function navigate(change: T): Promise { export const clearQueryParam = async (queryParam: string, url: URL) => { if (url.searchParams.has(queryParam)) { url.searchParams.delete(queryParam); - await goto(url); + await goto(url, { keepFocus: true }); } }; diff --git a/web/src/routes/(user)/albums/+page.svelte b/web/src/routes/(user)/albums/+page.svelte index 5fe0691b16a0b4..7369779ab3beaa 100644 --- a/web/src/routes/(user)/albums/+page.svelte +++ b/web/src/routes/(user)/albums/+page.svelte @@ -29,7 +29,7 @@ />
- +
diff --git a/web/src/routes/(user)/people/+page.svelte b/web/src/routes/(user)/people/+page.svelte index 864bc9f6e06724..d4eb6e17420a0d 100644 --- a/web/src/routes/(user)/people/+page.svelte +++ b/web/src/routes/(user)/people/+page.svelte @@ -6,7 +6,6 @@ import Icon from '$lib/components/elements/icon.svelte'; import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte'; import PeopleCard from '$lib/components/faces-page/people-card.svelte'; - import SearchBar from '$lib/components/elements/search-bar.svelte'; import SetBirthDateModal from '$lib/components/faces-page/set-birth-date-modal.svelte'; import ShowHide from '$lib/components/faces-page/show-hide.svelte'; import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte'; @@ -15,16 +14,9 @@ notificationController, NotificationType, } from '$lib/components/shared-components/notification/notification'; - import { - ActionQueryParameterValue, - AppRoute, - maximumLengthSearchPeople, - QueryParameter, - timeBeforeShowLoadingSpinner, - } from '$lib/constants'; + import { ActionQueryParameterValue, AppRoute, QueryParameter } from '$lib/constants'; import { getPeopleThumbnailUrl } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; - import { searchNameLocal } from '$lib/utils/person'; import { shortcut } from '$lib/utils/shortcut'; import { getPerson, @@ -40,6 +32,7 @@ import type { PageData } from './$types'; import { locale } from '$lib/stores/preferences.store'; import { clearQueryParam } from '$lib/utils/navigation'; + import SearchPeople from '$lib/components/faces-page/people-search.svelte'; import LinkButton from '$lib/components/elements/buttons/link-button.svelte'; export let data: PageData; @@ -52,10 +45,7 @@ let initialHiddenValues: Record = {}; let eyeColorMap: Record = {}; - let searchedPeople: PersonResponseDto[] = []; let searchName = ''; - let searchWord: string; - let isSearchingPeople = false; let showLoadingSpinner = false; let toggleVisibility = false; @@ -68,29 +58,31 @@ let personMerge2: PersonResponseDto; let potentialMergePeople: PersonResponseDto[] = []; let edittingPerson: PersonResponseDto | null = null; + let searchedPeopleLocal: PersonResponseDto[] = []; + let handleSearchPeople: (force?: boolean, name?: string) => Promise; let innerHeight: number; for (const person of people) { initialHiddenValues[person.id] = person.isHidden; } - - $: searchedPeopleLocal = searchName ? searchNameLocal(searchName, searchedPeople, maximumLengthSearchPeople) : []; - + $: showPeople = searchName ? searchedPeopleLocal : people.filter((person) => !person.isHidden); $: countVisiblePeople = countTotalPeople - countHiddenPeople; onMount(async () => { const getSearchedPeople = $page.url.searchParams.get(QueryParameter.SEARCHED_PEOPLE); if (getSearchedPeople) { searchName = getSearchedPeople; - await handleSearchPeople(true); + await handleSearchPeople(true, searchName); } }); - const handleSearch = async (force: boolean) => { - $page.url.searchParams.set(QueryParameter.SEARCHED_PEOPLE, searchName); - await goto($page.url, { keepFocus: true }); - await handleSearchPeople(force); + const handleSearch = async () => { + const getSearchedPeople = $page.url.searchParams.get(QueryParameter.SEARCHED_PEOPLE); + if (getSearchedPeople !== searchName) { + $page.url.searchParams.set(QueryParameter.SEARCHED_PEOPLE, searchName); + await goto($page.url, { keepFocus: true }); + } }; const handleCloseClick = () => { @@ -278,28 +270,6 @@ ); }; - const handleSearchPeople = async (force: boolean) => { - if (searchName === '') { - await clearQueryParam(QueryParameter.SEARCHED_PEOPLE, $page.url); - return; - } - if (!force && people.length < maximumLengthSearchPeople && searchName.startsWith(searchWord)) { - return; - } - - const timeout = setTimeout(() => (isSearchingPeople = true), timeBeforeShowLoadingSpinner); - try { - searchedPeople = await searchPerson({ name: searchName, withHidden: false }); - searchWord = searchName; - } catch (error) { - handleError(error, "Can't search people"); - } finally { - clearTimeout(timeout); - } - - isSearchingPeople = false; - }; - const submitNameChange = async () => { potentialMergePeople = []; showChangeNameModal = false; @@ -393,7 +363,6 @@ }; const onResetSearchBar = async () => { - searchedPeople = []; await clearQueryParam(QueryParameter.SEARCHED_PEOPLE, $page.url); }; @@ -420,12 +389,14 @@
@@ -441,31 +412,16 @@ {#if countVisiblePeople > 0 && (!searchName || searchedPeopleLocal.length > 0)}
- {#if searchName} - {#each searchedPeopleLocal as person, index (person.id)} - handleChangeName(person)} - on:set-birth-date={() => handleSetBirthDate(person)} - on:merge-people={() => handleMergePeople(person)} - on:hide-person={() => handleHidePerson(person)} - /> - {/each} - {:else} - {#each people as person, index (person.id)} - {#if !person.isHidden} - handleChangeName(person)} - on:set-birth-date={() => handleSetBirthDate(person)} - on:merge-people={() => handleMergePeople(person)} - on:hide-person={() => handleHidePerson(person)} - /> - {/if} - {/each} - {/if} + {#each showPeople as person, index (person.id)} + handleChangeName(person)} + on:set-birth-date={() => handleSetBirthDate(person)} + on:merge-people={() => handleMergePeople(person)} + on:hide-person={() => handleHidePerson(person)} + /> + {/each}
{:else}
diff --git a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 3c5c199444461e..356cbe0df28a02 100644 --- a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -26,7 +26,7 @@ NotificationType, notificationController, } from '$lib/components/shared-components/notification/notification'; - import { AppRoute, QueryParameter, maximumLengthSearchPeople, timeBeforeShowLoadingSpinner } from '$lib/constants'; + import { AppRoute, QueryParameter } from '$lib/constants'; import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store'; import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { AssetStore } from '$lib/stores/assets.store'; @@ -35,7 +35,6 @@ import { clickOutside } from '$lib/utils/click-outside'; import { handleError } from '$lib/utils/handle-error'; import { isExternalUrl } from '$lib/utils/navigation'; - import { searchNameLocal } from '$lib/utils/person'; import { getPersonStatistics, mergePerson, @@ -103,37 +102,12 @@ * However, it needs to make a new api request if searching 'r' returns 20 names (arbitrary value, the limit sent back by the server). * or if the new search word starts with another word / letter **/ - let searchWord: string; let isSearchingPeople = false; let suggestionContainer: HTMLDivElement; - const searchPeople = async () => { - if ((people.length < maximumLengthSearchPeople && name.startsWith(searchWord)) || name === '') { - return; - } - const timeout = setTimeout(() => (isSearchingPeople = true), timeBeforeShowLoadingSpinner); - try { - people = await searchPerson({ name }); - searchWord = name; - } catch (error) { - people = []; - handleError(error, "Can't search people"); - } finally { - clearTimeout(timeout); - } - - isSearchingPeople = false; - }; - $: isAllArchive = [...$selectedAssets].every((asset) => asset.isArchived); $: isAllFavorite = [...$selectedAssets].every((asset) => asset.isFavorite); - $: { - if (people) { - suggestedPeople = name ? searchNameLocal(name, people, 5, data.person.id) : []; - } - } - onMount(() => { const action = $page.url.searchParams.get(QueryParameter.ACTION); const getPreviousRoute = $page.url.searchParams.get(QueryParameter.PREVIOUS_ROUTE); @@ -480,10 +454,10 @@ {#if isEditingName} 0 || isSearchingPeople} + bind:suggestedPeople bind:name + bind:isSearchingPeople on:change={(event) => handleNameChange(event.detail)} - on:input={searchPeople} {thumbnailData} /> {:else} From 461f2595b50ce7e3e716e8c88d10631a74226301 Mon Sep 17 00:00:00 2001 From: Yoonjae Choi <123538138+uniqueeest@users.noreply.github.com> Date: Tue, 30 Apr 2024 06:59:32 +0900 Subject: [PATCH 3/7] fix(web): Prevent DELETE key from clearing DateInput in modal (#8846) * fix(web): Prevent DELETE key from clearing DateInput in modal (#8804) * chore: test prettier * fix: stop propagation * fix: stop propagation in modal * fix: remove unnecessary function and revise lint issue * chore: cleanup --------- Co-authored-by: Jason Rasmussen --- .../shared-components/change-date.svelte | 66 ++++++++----------- .../full-screen-modal.svelte | 1 + web/src/lib/utils/shortcut.ts | 2 +- 3 files changed, 31 insertions(+), 38 deletions(-) diff --git a/web/src/lib/components/shared-components/change-date.svelte b/web/src/lib/components/shared-components/change-date.svelte index e87f77ae52a516..0e53f0b2618445 100644 --- a/web/src/lib/components/shared-components/change-date.svelte +++ b/web/src/lib/components/shared-components/change-date.svelte @@ -53,43 +53,35 @@ dispatch('confirm', value); } }; - - const handleKeydown = (event: KeyboardEvent) => { - if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) { - event.stopPropagation(); - } - }; -
- -
-
- - -
-
- -
+ +
+
+ + +
+
+
- -
+
+
diff --git a/web/src/lib/components/shared-components/full-screen-modal.svelte b/web/src/lib/components/shared-components/full-screen-modal.svelte index a35a544d5bd106..176255ad09170d 100644 --- a/web/src/lib/components/shared-components/full-screen-modal.svelte +++ b/web/src/lib/components/shared-components/full-screen-modal.svelte @@ -45,6 +45,7 @@