diff --git a/src/components/albums/info/AlbumImages.tsx b/src/components/albums/info/AlbumImages.tsx index 5bd45b3..3bb99af 100644 --- a/src/components/albums/info/AlbumImages.tsx +++ b/src/components/albums/info/AlbumImages.tsx @@ -4,7 +4,7 @@ import { useConfig } from '@/contexts/ConfigContext'; import { IAlbum } from '@/types/album' import { IAsset } from '@/types/asset' import React, { useEffect, useMemo, useRef, useState } from 'react' -import { Hourglass } from 'lucide-react'; +import { ExternalLink, Hourglass } from 'lucide-react'; import { useRouter } from 'next/router'; import { CalendarArrowUp } from 'lucide-react'; import Lightbox from 'yet-another-react-lightbox'; @@ -12,6 +12,7 @@ import Captions from 'yet-another-react-lightbox/plugins/captions'; import LazyImage from '@/components/ui/lazy-image'; import Image from 'next/image'; import { Button } from "@/components/ui/button"; +import Link from "next/link"; interface AlbumImagesProps { album: IAlbum @@ -116,7 +117,7 @@ export default function AlbumImages({ album }: AlbumImagesProps) { ); return ( - <> +
setIndex(-1)} /> -
+
{images.map((image) => ( -
- + handleClick(images.indexOf(image))} /> + + + Open In Immich +
))}
@@ -154,6 +164,6 @@ export default function AlbumImages({ album }: AlbumImagesProps) { > Load More } - +
); } diff --git a/src/components/albums/info/AlbumPeople.tsx b/src/components/albums/info/AlbumPeople.tsx index ac2a719..2def649 100644 --- a/src/components/albums/info/AlbumPeople.tsx +++ b/src/components/albums/info/AlbumPeople.tsx @@ -16,6 +16,7 @@ import Image from 'next/image' import { PersonMergeDropdown } from '@/components/people/PersonMergeDropdown' import { Button } from '@/components/ui/button' import { updatePerson } from '@/handlers/api/people.handler' +import { Checkbox } from '@/components/ui/checkbox' interface AlbumPeopleProps { album: IAlbum @@ -98,104 +99,112 @@ export default function AlbumPeople({ album, onSelect }: AlbumPeopleProps) { } return ( - - -
- -
- -

People

-
-
-
- {selectedPerson ? ( - <> - -
-
- {selectedPerson.name} -
- {selectedPerson.name} -
-
- { - router.push({ - pathname, - query: { - ...query, - faceId: mergedPerson.id - } - }) - }} /> -
- -
- - ) : ( -
- {selectedPeople.length > 0 && ( - <> -

{selectedPeople.length} people selected

- - - )} - -
- )} - +
+ + {selectedPerson && ( +
+
+ {selectedPerson.name} + + + {selectedPerson.name || "No Name"} + +
+
+ { + router.push({ + pathname, + query: { + ...query, + faceId: mergedPerson.id + } + }) + }} /> +
- - {people.map((person) => ( - -
- { - if (selectionMode) { - handleBulkSelect(person.id) - } else { - onSelect(person.id) - } - }} - role="button" - className={ - cn("cursor-pointer h-16 w-16 min-w-16 rounded border-2", - !!person.name ? "border-blue-500" : "border-gray-500", - selectedPerson?.id === person.id ? "border-green-500" : "", - selectionMode ? "border-blue-500" : "", - selectedPeople.includes(person.id) ? "border-green-500" : "" - ) - } - src={PERSON_THUBNAIL_PATH(person.id)} alt={person.name} /> -

{person.numberOfPhotos}

-
-
- ))} -
- - + )} + + +
+

People

+ + {!selectedPerson && ( + + )} + {selectedPeople.length > 0 && ( +
+ +
+ )} +
+
+ {people.map((person) => ( +
{ + if (selectionMode) { + handleBulkSelect(person.id) + } else { + onSelect(person.id) + } + }} + > + {selectionMode && ( + handleBulkSelect(person.id)} + /> + )} + +
+

{person.name || "No Name"}

+

{person.numberOfPhotos} photos

+
+
+ ))} +
+
) } diff --git a/src/components/people/PersonMergeDropdown.tsx b/src/components/people/PersonMergeDropdown.tsx index 0de0fd5..4811c47 100644 --- a/src/components/people/PersonMergeDropdown.tsx +++ b/src/components/people/PersonMergeDropdown.tsx @@ -32,17 +32,20 @@ import { import { CaretDownIcon } from "@radix-ui/react-icons"; import FaceThumbnail from "./merge/FaceThumbnail"; import ErrorBlock from "../shared/ErrorBlock"; +import { cn } from "@/lib/utils"; interface PersonMergeDropdownProps { person: IPerson; onRemove?: (person: IPerson) => void; onComplete?: (mergedPerson: IPerson) => void; + triggerClassName?: string; } export function PersonMergeDropdown({ person, onRemove, onComplete, + triggerClassName, }: PersonMergeDropdownProps) { const [searchedPeople, setSearchedPeople] = useState(null); const [similarPeople, setSimilarPeople] = useState([]); @@ -222,113 +225,111 @@ export function PersonMergeDropdown({ }; return ( -
- - - - - - - - Merge {person.name ? person.name : "Untagged Person"} - - -
-

- {selectedPeople.length > 0 - ? `Merging ${selectedPeople.length} people to ${person.name}` - : "Search and select people to merge with"} -

- - - -

{primaryPerson?.name || "Untagged Person"}

- -
- - {[person, ...selectedPeople].map((person) => ( - setPrimaryPerson(person)} - className="flex gap-1" - > - - {person.name || "Untagged Person"} - - ))} - -
-
-
-
- { - handleSearch(e.target.value); - }} - /> - - {selectedPeople.length > 0 ? ( -
- {selectedPeople.map((person) => ( -
+ + + + + + + + Merge {person.name ? person.name : "Untagged Person"} + + +
+

+ {selectedPeople.length > 0 + ? `Merging ${selectedPeople.length} people to ${person.name}` + : "Search and select people to merge with"} +

+ + -

- {person.name ? person.name : Untagged person} -

- -
- ))} +

{primaryPerson?.name || "Untagged Person"}

+ + + + {[person, ...selectedPeople].map((person) => ( + setPrimaryPerson(person)} + className="flex gap-1" + > + + {person.name || "Untagged Person"} + + ))} + +
- ) : ( -
-

No Selections Yet

-
- )} + + + { + handleSearch(e.target.value); + }} + /> - {renderContent()} - - - - - -
-
+ {selectedPeople.length > 0 ? ( +
+ {selectedPeople.map((person) => ( +
+ +

+ {person.name ? person.name : Untagged person} +

+ +
+ ))} +
+ ) : ( +
+

No Selections Yet

+
+ )} + + {renderContent()} + + + + + + ); } diff --git a/src/pages/albums/[albumId].tsx b/src/pages/albums/[albumId].tsx index af2f13a..d529562 100644 --- a/src/pages/albums/[albumId].tsx +++ b/src/pages/albums/[albumId].tsx @@ -78,7 +78,7 @@ export default function AlbumListPage() { return
{errorMessage}
} return ( -
+
{albumInfo && ( <>