0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-21 00:52:43 -05:00

feat(web): search albums (#7322)

* feat: search albums

* pr feedback

* fix: comparison

* pr feedback

* simplify

* chore: more compact album padding

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
martin 2024-02-22 15:04:43 +01:00 committed by GitHub
parent e3cccba78c
commit 75947ab6c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 26 additions and 16 deletions

View file

@ -1,12 +1,13 @@
<script lang="ts"> <script lang="ts">
import { mdiClose, mdiMagnify } from '@mdi/js'; import { mdiClose, mdiMagnify } from '@mdi/js';
import Icon from '../elements/icon.svelte'; import Icon from './icon.svelte';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import type { SearchOptions } from '$lib/utils/dipatch'; import type { SearchOptions } from '$lib/utils/dipatch';
import LoadingSpinner from '../shared-components/loading-spinner.svelte'; import LoadingSpinner from '../shared-components/loading-spinner.svelte';
export let name: string; export let name: string;
export let isSearchingPeople: boolean; export let isSearching: boolean;
export let placeholder: string;
const dispatch = createEventDispatcher<{ search: SearchOptions; reset: void }>(); const dispatch = createEventDispatcher<{ search: SearchOptions; reset: void }>();
@ -27,11 +28,11 @@
autofocus autofocus
class="w-full gap-2 bg-gray-100 dark:bg-gray-700 dark:text-white" class="w-full gap-2 bg-gray-100 dark:bg-gray-700 dark:text-white"
type="text" type="text"
placeholder="Search names" {placeholder}
bind:value={name} bind:value={name}
on:input={() => dispatch('search', { force: false })} on:input={() => dispatch('search', { force: false })}
/> />
{#if isSearchingPeople} {#if isSearching}
<div class="flex place-items-center"> <div class="flex place-items-center">
<LoadingSpinner /> <LoadingSpinner />
</div> </div>

View file

@ -5,7 +5,7 @@
import { searchPerson, type PersonResponseDto } from '@immich/sdk'; import { searchPerson, type PersonResponseDto } from '@immich/sdk';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import FaceThumbnail from './face-thumbnail.svelte'; import FaceThumbnail from './face-thumbnail.svelte';
import SearchBar from './search-bar.svelte'; import SearchBar from '../elements/search-bar.svelte';
export let screenHeight: number; export let screenHeight: number;
export let people: PersonResponseDto[]; export let people: PersonResponseDto[];
@ -55,7 +55,8 @@
<div class=" w-40 sm:w-48 md:w-96 h-14 mb-8"> <div class=" w-40 sm:w-48 md:w-96 h-14 mb-8">
<SearchBar <SearchBar
bind:name bind:name
{isSearchingPeople} isSearching={isSearchingPeople}
placeholder="Search people"
on:reset={() => { on:reset={() => {
people = peopleCopy; people = peopleCopy;
}} }}

View file

@ -11,7 +11,7 @@
export let scrollbar = true; export let scrollbar = true;
export let admin = false; export let admin = false;
$: scrollbarClass = scrollbar ? 'immich-scrollbar p-4 pb-8' : 'scrollbar-hidden'; $: scrollbarClass = scrollbar ? 'immich-scrollbar p-2 pb-8' : 'scrollbar-hidden';
$: hasTitleClass = title ? 'top-16 h-[calc(100%-theme(spacing.16))]' : 'top-0 h-full'; $: hasTitleClass = title ? 'top-16 h-[calc(100%-theme(spacing.16))]' : 'top-0 h-full';
</script> </script>

View file

@ -43,11 +43,13 @@
import { flip } from 'svelte/animate'; import { flip } from 'svelte/animate';
import type { PageData } from './$types'; import type { PageData } from './$types';
import { useAlbums } from './albums.bloc'; import { useAlbums } from './albums.bloc';
import SearchBar from '$lib/components/elements/search-bar.svelte';
export let data: PageData; export let data: PageData;
let shouldShowEditUserForm = false; let shouldShowEditUserForm = false;
let selectedAlbum: AlbumResponseDto; let selectedAlbum: AlbumResponseDto;
let searchAlbum = '';
let sortByOptions: Record<string, Sort> = { let sortByOptions: Record<string, Sort> = {
albumTitle: { albumTitle: {
@ -180,6 +182,8 @@
} }
} }
$: albumsFiltered = $albums.filter((album) => album.albumName.toLowerCase().includes(searchAlbum.toLowerCase()));
const searchSort = (searched: string): Sort => { const searchSort = (searched: string): Sort => {
for (const key in sortByOptions) { for (const key in sortByOptions) {
if (sortByOptions[key].title === searched) { if (sortByOptions[key].title === searched) {
@ -243,6 +247,9 @@
<UserPageLayout title={data.meta.title}> <UserPageLayout title={data.meta.title}>
<div class="flex place-items-center gap-2" slot="buttons"> <div class="flex place-items-center gap-2" slot="buttons">
<div class="hidden lg:block lg:w-40 xl:w-60 2xl:w-80 h-10">
<SearchBar placeholder="Search albums" bind:name={searchAlbum} isSearching={false} />
</div>
<LinkButton on:click={handleCreateAlbum}> <LinkButton on:click={handleCreateAlbum}>
<div class="flex place-items-center gap-2 text-sm"> <div class="flex place-items-center gap-2 text-sm">
<Icon path={mdiPlusBoxOutline} size="18" /> <Icon path={mdiPlusBoxOutline} size="18" />
@ -285,7 +292,7 @@
<!-- Album Card --> <!-- Album Card -->
{#if $albumViewSettings.view === AlbumViewMode.Cover} {#if $albumViewSettings.view === AlbumViewMode.Cover}
<div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))]"> <div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))]">
{#each $albums as album, index (album.id)} {#each albumsFiltered as album, index (album.id)}
<a data-sveltekit-preload-data="hover" href="{AppRoute.ALBUMS}/{album.id}" animate:flip={{ duration: 200 }}> <a data-sveltekit-preload-data="hover" href="{AppRoute.ALBUMS}/{album.id}" animate:flip={{ duration: 200 }}>
<AlbumCard <AlbumCard
preload={index < 20} preload={index < 20}
@ -296,7 +303,7 @@
{/each} {/each}
</div> </div>
{:else if $albumViewSettings.view === AlbumViewMode.List} {:else if $albumViewSettings.view === AlbumViewMode.List}
<table class="mt-5 w-full text-left"> <table class="mt-2 w-full text-left">
<thead <thead
class="mb-4 flex h-12 w-full rounded-md border bg-gray-50 text-immich-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-primary" class="mb-4 flex h-12 w-full rounded-md border bg-gray-50 text-immich-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-primary"
> >
@ -310,7 +317,7 @@
<tbody <tbody
class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray dark:text-immich-dark-fg" class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray dark:text-immich-dark-fg"
> >
{#each $albums as album (album.id)} {#each albumsFiltered as album (album.id)}
<tr <tr
class="flex h-[50px] w-full place-items-center border-[3px] border-transparent p-2 text-center odd:bg-immich-gray even:bg-immich-bg hover:cursor-pointer hover:border-immich-primary/75 odd:dark:bg-immich-dark-gray/75 even:dark:bg-immich-dark-gray/50 dark:hover:border-immich-dark-primary/75 md:p-5" class="flex h-[50px] w-full place-items-center border-[3px] border-transparent p-2 text-center odd:bg-immich-gray even:bg-immich-bg hover:cursor-pointer hover:border-immich-primary/75 odd:dark:bg-immich-dark-gray/75 even:dark:bg-immich-dark-gray/50 dark:hover:border-immich-dark-primary/75 md:p-5"
on:click={() => goto(`${AppRoute.ALBUMS}/${album.id}`)} on:click={() => goto(`${AppRoute.ALBUMS}/${album.id}`)}

View file

@ -603,7 +603,7 @@
<input <input
on:keydown={(e) => e.key === 'Enter' && titleInput.blur()} on:keydown={(e) => e.key === 'Enter' && titleInput.blur()}
on:blur={handleUpdateName} on:blur={handleUpdateName}
class="w-[99%] border-b-2 border-transparent text-6xl text-immich-primary outline-none transition-all dark:text-immich-dark-primary {isOwned 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-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" : '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" type="text"
@ -616,7 +616,7 @@
<!-- ALBUM SUMMARY --> <!-- ALBUM SUMMARY -->
{#if album.assetCount > 0} {#if album.assetCount > 0}
<span class="my-4 flex gap-2 text-sm font-medium text-gray-500" data-testid="album-details"> <span class="my-2 flex gap-2 text-sm font-medium text-gray-500" data-testid="album-details">
<p class="">{getDateRange()}</p> <p class="">{getDateRange()}</p>
<p>·</p> <p>·</p>
<p>{album.assetCount} items</p> <p>{album.assetCount} items</p>
@ -625,7 +625,7 @@
<!-- ALBUM SHARING --> <!-- ALBUM SHARING -->
{#if album.sharedUsers.length > 0 || (album.hasSharedLink && isOwned)} {#if album.sharedUsers.length > 0 || (album.hasSharedLink && isOwned)}
<div class="my-6 flex gap-x-1"> <div class="my-3 flex gap-x-1">
<!-- link --> <!-- link -->
{#if album.hasSharedLink && isOwned} {#if album.hasSharedLink && isOwned}
<CircleIconButton <CircleIconButton
@ -664,7 +664,7 @@
<!-- ALBUM DESCRIPTION --> <!-- ALBUM DESCRIPTION -->
{#if isOwned} {#if isOwned}
<textarea <textarea
class="w-full resize-none overflow-hidden 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" class="w-full mt-2 resize-none overflow-hidden 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:this={textArea} bind:this={textArea}
bind:value={description} bind:value={description}
on:input={() => autoGrowHeight(textArea)} on:input={() => autoGrowHeight(textArea)}

View file

@ -8,7 +8,7 @@
import Icon from '$lib/components/elements/icon.svelte'; import Icon from '$lib/components/elements/icon.svelte';
import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte'; import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte';
import PeopleCard from '$lib/components/faces-page/people-card.svelte'; import PeopleCard from '$lib/components/faces-page/people-card.svelte';
import SearchBar from '$lib/components/faces-page/search-bar.svelte'; import SearchBar from '$lib/components/elements/search-bar.svelte';
import SetBirthDateModal from '$lib/components/faces-page/set-birth-date-modal.svelte'; import SetBirthDateModal from '$lib/components/faces-page/set-birth-date-modal.svelte';
import ShowHide from '$lib/components/faces-page/show-hide.svelte'; import ShowHide from '$lib/components/faces-page/show-hide.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte'; import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
@ -441,7 +441,8 @@
<div class="w-40 lg:w-80 h-10"> <div class="w-40 lg:w-80 h-10">
<SearchBar <SearchBar
bind:name={searchName} bind:name={searchName}
{isSearchingPeople} isSearching={isSearchingPeople}
placeholder="Search people"
on:reset={() => { on:reset={() => {
searchedPeople = []; searchedPeople = [];
}} }}