mirror of
https://github.com/C9Glax/tranga-website.git
synced 2025-09-10 03:48:21 +02:00
Search
This commit is contained in:
@@ -7,6 +7,7 @@ import {V2} from "./apiClient/V2.ts";
|
|||||||
import { ApiContext } from './apiClient/ApiContext.tsx';
|
import { ApiContext } from './apiClient/ApiContext.tsx';
|
||||||
import MangaList from "./Components/Mangas/MangaList.tsx";
|
import MangaList from "./Components/Mangas/MangaList.tsx";
|
||||||
import {FileLibrary, Manga, MangaConnector} from "./apiClient/data-contracts.ts";
|
import {FileLibrary, Manga, MangaConnector} from "./apiClient/data-contracts.ts";
|
||||||
|
import Search from "./Components/Search.tsx";
|
||||||
|
|
||||||
export const MangaConnectorContext = createContext<MangaConnector[]>([]);
|
export const MangaConnectorContext = createContext<MangaConnector[]>([]);
|
||||||
export const MangaContext = createContext<Manga[]>([]);
|
export const MangaContext = createContext<Manga[]>([]);
|
||||||
@@ -63,7 +64,9 @@ export default function App () {
|
|||||||
<Settings setApiUri={setApiUri} />
|
<Settings setApiUri={setApiUri} />
|
||||||
</Header>
|
</Header>
|
||||||
<Sheet className={"app-content"}>
|
<Sheet className={"app-content"}>
|
||||||
<MangaList />
|
<MangaList mangas={manga}>
|
||||||
|
<Search />
|
||||||
|
</MangaList>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
</MangaContext.Provider>
|
</MangaContext.Provider>
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
import {useContext} from "react";
|
import {ReactNode} from "react";
|
||||||
import {MangaCard} from "./MangaCard.tsx";
|
import {MangaCard} from "./MangaCard.tsx";
|
||||||
import {Stack} from "@mui/joy";
|
import {Stack} from "@mui/joy";
|
||||||
import "./MangaList.css";
|
import "./MangaList.css";
|
||||||
import {MangaContext} from "../../App.tsx";
|
import {Manga} from "../../apiClient/data-contracts.ts";
|
||||||
|
|
||||||
export default function MangaList (){
|
export default function MangaList ({mangas, children} : {mangas: Manga[], children?: ReactNode}) {
|
||||||
const mangas = useContext(MangaContext);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack className={"manga-list"} direction={"row"} useFlexGap={true} spacing={2} flexWrap={"wrap"}>
|
<Stack className={"manga-list"} direction={"row"} useFlexGap={true} spacing={2} flexWrap={"wrap"}>
|
||||||
|
{children}
|
||||||
{mangas?.map(manga => <MangaCard key={manga.key} manga={manga} />)}
|
{mangas?.map(manga => <MangaCard key={manga.key} manga={manga} />)}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
115
tranga-website/src/Components/Search.tsx
Normal file
115
tranga-website/src/Components/Search.tsx
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import {Dispatch, KeyboardEventHandler, ReactNode, useContext, useState} from "react";
|
||||||
|
import {
|
||||||
|
Badge, Button,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardCover,
|
||||||
|
Input,
|
||||||
|
Modal,
|
||||||
|
ModalDialog, Option, Select,
|
||||||
|
Step,
|
||||||
|
StepIndicator,
|
||||||
|
Stepper,
|
||||||
|
Typography
|
||||||
|
} from "@mui/joy";
|
||||||
|
import ModalClose from "@mui/joy/ModalClose";
|
||||||
|
import {MangaConnectorContext} from "../App.tsx";
|
||||||
|
import {Manga, MangaConnector} from "../apiClient/data-contracts.ts";
|
||||||
|
import MangaList from "./Mangas/MangaList.tsx";
|
||||||
|
import {ApiContext} from "../apiClient/ApiContext.tsx";
|
||||||
|
|
||||||
|
export default function () : ReactNode {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Badge badgeContent={"+"}>
|
||||||
|
<Card onClick={() => {if (!open) setOpen(true)}} className={"manga-card"}>
|
||||||
|
<CardCover className={"manga-cover"}>
|
||||||
|
<img src={"/blahaj.png"} />
|
||||||
|
</CardCover>
|
||||||
|
<CardCover className={"manga-cover-blur"} />
|
||||||
|
<CardContent>
|
||||||
|
Add
|
||||||
|
</CardContent>
|
||||||
|
<CardContent>
|
||||||
|
<SearchDialog open={open} setOpen={setOpen} />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SearchDialog ({open, setOpen} : {open: boolean, setOpen: Dispatch<boolean>}) : ReactNode {
|
||||||
|
const mangaConnectors = useContext(MangaConnectorContext);
|
||||||
|
const Api = useContext(ApiContext);
|
||||||
|
|
||||||
|
const [selectedMangaConnector, setSelectedMangaConnector] = useState<MangaConnector | undefined>(undefined);
|
||||||
|
const [searchTerm, setSearchTerm] = useState<string>();
|
||||||
|
const [searchResults, setSearchResults] = useState<Manga[]>([]);
|
||||||
|
|
||||||
|
const doTheSearch = () => {
|
||||||
|
if (searchTerm === undefined || searchTerm.length < 1)
|
||||||
|
return;
|
||||||
|
if (!isUrl(searchTerm) && selectedMangaConnector === undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isUrl(searchTerm))
|
||||||
|
Api.searchUrlCreate(searchTerm)
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok)
|
||||||
|
setSearchResults([response.data]);
|
||||||
|
});
|
||||||
|
else
|
||||||
|
Api.searchDetail(selectedMangaConnector!.name, searchTerm)
|
||||||
|
.then(response => {
|
||||||
|
if(response.ok)
|
||||||
|
setSearchResults(response.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isUrl = (url: string) => {
|
||||||
|
try{
|
||||||
|
new URL(url);
|
||||||
|
return true;
|
||||||
|
}catch (Error){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyDownCheck : KeyboardEventHandler<HTMLInputElement> = (e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
doTheSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal sx={{width: "100%", height: "100%"}} open={open} onClose={() => setOpen(false)}>
|
||||||
|
<ModalDialog sx={{width: "80%"}}>
|
||||||
|
<ModalClose />
|
||||||
|
<Stepper orientation={"vertical"}>
|
||||||
|
<Step indicator={<StepIndicator>1</StepIndicator>}>
|
||||||
|
<Typography>Connector</Typography>
|
||||||
|
<Select onChange={(_, v) => setSelectedMangaConnector(v as MangaConnector)}>
|
||||||
|
{mangaConnectors?.map(con => (
|
||||||
|
<Option value={con}>
|
||||||
|
<Typography><img src={con.iconUrl} style={{maxHeight: "var(--Icon-fontSize)"}} />{con.name}</Typography>
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Step>
|
||||||
|
<Step indicator={<StepIndicator>2</StepIndicator>}>
|
||||||
|
<Typography>Search</Typography>
|
||||||
|
<Input onKeyDown={keyDownCheck}
|
||||||
|
onChange={(e) => setSearchTerm(e.currentTarget.value)}
|
||||||
|
endDecorator={<Button onClick={doTheSearch}>Search</Button>}
|
||||||
|
/>
|
||||||
|
</Step>
|
||||||
|
<Step indicator={<StepIndicator>3</StepIndicator>}>
|
||||||
|
<Typography>Result</Typography>
|
||||||
|
<MangaList mangas={searchResults} />
|
||||||
|
</Step>
|
||||||
|
</Stepper>
|
||||||
|
</ModalDialog>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
Reference in New Issue
Block a user