mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-15 16:20:03 +00:00
Extend Plugin API to return a list of covers and header images
Implement dedicated header image in GameView Implement GameHeaderPicker
This commit is contained in:
@@ -4,6 +4,10 @@ import React, {useEffect, useState} from "react";
|
||||
import GameSearchResultDto from "Frontend/generated/org/gameyfin/app/games/dto/GameSearchResultDto";
|
||||
import {GameEndpoint} from "Frontend/generated/endpoints";
|
||||
import {ArrowRight, MagnifyingGlass} from "@phosphor-icons/react";
|
||||
import PluginIcon from "Frontend/components/general/plugin/PluginIcon";
|
||||
import {useSnapshot} from "valtio/react";
|
||||
import {pluginState} from "Frontend/state/PluginState";
|
||||
import PluginDto from "Frontend/generated/org/gameyfin/app/core/plugins/dto/PluginDto";
|
||||
|
||||
interface GameCoverPickerModalProps {
|
||||
game: GameDto;
|
||||
@@ -17,7 +21,9 @@ export function GameCoverPickerModal({game, isOpen, onOpenChange, setCoverUrl}:
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState(game.title);
|
||||
const [searchResults, setSearchResults] = useState<GameSearchResultDto[]>([]);
|
||||
const [isSearching, setIsSearching] = useState(false)
|
||||
const [isSearching, setIsSearching] = useState(false);
|
||||
|
||||
const state = useSnapshot(pluginState).state;
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && searchTerm.length > 0 && searchResults.length === 0) {
|
||||
@@ -27,8 +33,8 @@ export function GameCoverPickerModal({game, isOpen, onOpenChange, setCoverUrl}:
|
||||
|
||||
async function search() {
|
||||
setIsSearching(true);
|
||||
const results = await GameEndpoint.getPotentialMatches(searchTerm, false);
|
||||
let validResults = results.filter(result => result.coverUrl && result.coverUrl.length > 0 && result.coverUrl !== "null");
|
||||
const results = await GameEndpoint.getPotentialMatches(searchTerm);
|
||||
let validResults = results.filter(result => result.coverUrls && result.coverUrls.length > 0);
|
||||
setSearchResults(validResults);
|
||||
setIsSearching(false);
|
||||
}
|
||||
@@ -78,25 +84,36 @@ export function GameCoverPickerModal({game, isOpen, onOpenChange, setCoverUrl}:
|
||||
<p className="text-center text-foreground/70">Searching...</p>
|
||||
}
|
||||
<ScrollShadow
|
||||
className="grid grid-cols-auto-fill gap-4 h-96 overflow-scroll justify-evenly">
|
||||
{searchResults.map((result) => (
|
||||
<div className="relative group w-fit h-fit cursor-pointer"
|
||||
className="grid grid-cols-auto-fill gap-4 h-96 overflow-y-scroll justify-evenly">
|
||||
{searchResults.flatMap(result => {
|
||||
if (!result.coverUrls) return [];
|
||||
return result.coverUrls.map((url, idx) => ({
|
||||
id: `${result.id}-${idx}`,
|
||||
title: result.title,
|
||||
url: url.url,
|
||||
source: url.pluginId
|
||||
}))
|
||||
}).map(cover => (
|
||||
<div key={cover.id}
|
||||
className="relative group w-fit h-fit cursor-pointer"
|
||||
onClick={() => {
|
||||
setCoverUrl(result.coverUrl!);
|
||||
onClose();
|
||||
}}>
|
||||
setCoverUrl(cover.url);
|
||||
onOpenChange();
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
key={result.id}
|
||||
alt={result.title}
|
||||
className="z-0 object-cover aspect-[12/17] group-hover:brightness-50"
|
||||
src={result.coverUrl!}
|
||||
alt={cover.title}
|
||||
className="z-0 object-cover aspect-[12/17] group-hover:brightness-[25%]"
|
||||
src={cover.url}
|
||||
radius="none"
|
||||
height={216}
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100"
|
||||
>
|
||||
<ArrowRight size={46}/>
|
||||
className="absolute inset-0 flex flex-col gap-4 items-center justify-center opacity-0 group-hover:opacity-100">
|
||||
<PluginIcon plugin={state[cover.source] as PluginDto} size={32}
|
||||
blurred={false} showTooltip={false}/>
|
||||
<p className="text-s text-center">{cover.title}</p>
|
||||
<ArrowRight/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user