mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-24 19:11:49 +01:00
Basic component structure
This commit is contained in:
parent
b3c4ad5e15
commit
81373da404
26
src/App.tsx
26
src/App.tsx
@ -1,24 +1,16 @@
|
|||||||
import { GetProviderFromId, SearchProviders, MWMedia, MWMediaType } from '@/scrapers';
|
import { Route, Switch } from 'react-router-dom';
|
||||||
import { useState } from 'react';
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
import { MovieView } from './views/MovieView';
|
||||||
|
import { SearchView } from './views/SearchView';
|
||||||
|
import { SeriesView } from './views/SeriesView';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [results, setResults] = useState<MWMedia[]>([]);
|
|
||||||
|
|
||||||
async function runSearch() {
|
|
||||||
const results = await SearchProviders({ type: MWMediaType.MOVIE, searchQuery: "abc" });
|
|
||||||
setResults(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Switch>
|
||||||
<h1>Search</h1>
|
<Route exact path="/" component={SearchView} />
|
||||||
<button onClick={() => runSearch()}>Search</button>
|
<Route exact path="/media/movie" component={MovieView} />
|
||||||
<h1>Search results</h1>
|
<Route exact path="/media/series" component={SeriesView} />
|
||||||
{results.map(v=>(
|
</Switch>
|
||||||
<p>{v.title} ({GetProviderFromId(v.providerId)?.displayName})</p>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
src/components/Buttons/ButtonControl.tsx
Normal file
8
src/components/Buttons/ButtonControl.tsx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface ButtonControlProps {
|
||||||
|
onClick?: () => void;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ButtonControl({ onClick, children }: ButtonControlProps) {
|
||||||
|
return <button onClick={onClick}>{children}</button>
|
||||||
|
}
|
15
src/components/Icon.tsx
Normal file
15
src/components/Icon.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export enum Icons {
|
||||||
|
SEARCH = "search",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IconProps {
|
||||||
|
icon: Icons;
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconList = {
|
||||||
|
search: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>`,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Icon(props: IconProps) {
|
||||||
|
return <span dangerouslySetInnerHTML={{ __html: iconList[props.icon] }} />;
|
||||||
|
}
|
20
src/components/SearchBar.tsx
Normal file
20
src/components/SearchBar.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { ButtonControl } from './Buttons/ButtonControl';
|
||||||
|
import { Icon, Icons } from './Icon';
|
||||||
|
import { TextInputControl, TextInputControlPropsNoLabel } from './TextInputs/TextInputControl';
|
||||||
|
|
||||||
|
export interface SearchBarProps extends TextInputControlPropsNoLabel {
|
||||||
|
buttonText?: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SearchBarInput(props: SearchBarProps) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TextInputControl onChange={props.onChange} value={props.value} />
|
||||||
|
<ButtonControl onClick={props.onClick}>
|
||||||
|
<Icon icon={Icons.SEARCH} />
|
||||||
|
{ props.buttonText || "Search" }
|
||||||
|
</ButtonControl>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
23
src/components/TextInputs/TextInputControl.tsx
Normal file
23
src/components/TextInputs/TextInputControl.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
export interface TextInputControlPropsNoLabel {
|
||||||
|
onChange?: (data: string) => void;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TextInputControlProps extends TextInputControlPropsNoLabel {
|
||||||
|
label?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TextInputControl({ onChange, value, label }: TextInputControlProps) {
|
||||||
|
const input = <input type="text" onChange={(e) => onChange && onChange(e.target.value)} value={value} />
|
||||||
|
|
||||||
|
if (label) {
|
||||||
|
return (
|
||||||
|
<label>
|
||||||
|
<span>{label}</span>
|
||||||
|
{input}
|
||||||
|
</label>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
30
src/components/media/MediaCard.tsx
Normal file
30
src/components/media/MediaCard.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { GetProviderFromId, MWMedia, MWMediaType } from "@/scrapers";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
export interface MediaCardProps {
|
||||||
|
media: MWMedia;
|
||||||
|
watchedPercentage: Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MediaCardContent({ media, watchedPercentage }: MediaCardProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>{media.title} ({GetProviderFromId(media.providerId)?.displayName})</p>
|
||||||
|
<p>{watchedPercentage}% watched</p>
|
||||||
|
<hr/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MediaCard(props: MediaCardProps) {
|
||||||
|
const provider = GetProviderFromId(props.media.providerId);
|
||||||
|
let link = "movie"
|
||||||
|
if (provider?.type === MWMediaType.SERIES)
|
||||||
|
link = "series";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link to={`/media/${link}`}>
|
||||||
|
<MediaCardContent {...props} />
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
10
src/components/media/WatchedMediaCard.tsx
Normal file
10
src/components/media/WatchedMediaCard.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { MWMedia } from "@/scrapers";
|
||||||
|
import { MediaCard } from "./MediaCard";
|
||||||
|
|
||||||
|
export interface WatchedMediaCardProps {
|
||||||
|
media: MWMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WatchedMediaCard(props: WatchedMediaCardProps) {
|
||||||
|
return <MediaCard watchedPercentage={42} media={props.media} />
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
import { theFlixScraper } from "./list/theflix";
|
import { theFlixMovieScraper } from "./list/theflixmovie";
|
||||||
|
import { theFlixSeriesScraper } from "./list/theflixseries";
|
||||||
import { MWMediaProvider, MWQuery } from "./types";
|
import { MWMediaProvider, MWQuery } from "./types";
|
||||||
export * from "./types";
|
export * from "./types";
|
||||||
|
|
||||||
const mediaProvidersUnchecked: MWMediaProvider[] = [
|
const mediaProvidersUnchecked: MWMediaProvider[] = [
|
||||||
theFlixScraper
|
theFlixMovieScraper,
|
||||||
|
theFlixSeriesScraper,
|
||||||
]
|
]
|
||||||
export const mediaProviders: MWMediaProvider[] = mediaProvidersUnchecked.filter(v=>v.enabled);
|
export const mediaProviders: MWMediaProvider[] = mediaProvidersUnchecked.filter(v=>v.enabled);
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { MWMedia, MWMediaProvider, MWMediaType, MWPortableMedia, MWQuery } from "@/scrapers/types";
|
import { MWMedia, MWMediaProvider, MWMediaType, MWPortableMedia, MWQuery } from "@/scrapers/types";
|
||||||
|
|
||||||
export const theFlixScraper: MWMediaProvider = {
|
export const theFlixMovieScraper: MWMediaProvider = {
|
||||||
id: "theflix",
|
id: "theflixmovie",
|
||||||
enabled: true,
|
enabled: true,
|
||||||
type: MWMediaType.MOVIE,
|
type: MWMediaType.MOVIE,
|
||||||
displayName: "TheFlix",
|
displayName: "TheFlix",
|
||||||
@ -17,7 +17,7 @@ export const theFlixScraper: MWMediaProvider = {
|
|||||||
return [{
|
return [{
|
||||||
mediaId: "a",
|
mediaId: "a",
|
||||||
providerId: this.id,
|
providerId: this.id,
|
||||||
title: "testing",
|
title: `movie test`,
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
}
|
}
|
23
src/scrapers/list/theflixseries/index.ts
Normal file
23
src/scrapers/list/theflixseries/index.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { MWMedia, MWMediaProvider, MWMediaType, MWPortableMedia, MWQuery } from "@/scrapers/types";
|
||||||
|
|
||||||
|
export const theFlixSeriesScraper: MWMediaProvider = {
|
||||||
|
id: "theflixseries",
|
||||||
|
enabled: true,
|
||||||
|
type: MWMediaType.SERIES,
|
||||||
|
displayName: "TheFlix",
|
||||||
|
|
||||||
|
async getMediaFromPortable(media: MWPortableMedia): Promise<MWMedia> {
|
||||||
|
return {
|
||||||
|
...media,
|
||||||
|
title: "title here"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async searchForMedia(query: MWQuery): Promise<MWMedia[]> {
|
||||||
|
return [{
|
||||||
|
mediaId: "b",
|
||||||
|
providerId: this.id,
|
||||||
|
title: `series test`,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
}
|
7
src/views/MovieView.tsx
Normal file
7
src/views/MovieView.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export function MovieView() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Movie view here</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
23
src/views/SearchView.tsx
Normal file
23
src/views/SearchView.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { WatchedMediaCard } from "@/components/media/WatchedMediaCard";
|
||||||
|
import { SearchBarInput } from "@/components/SearchBar";
|
||||||
|
import { GetProviderFromId, MWMedia, MWMediaType, SearchProviders } from "@/scrapers";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export function SearchView() {
|
||||||
|
const [results, setResults] = useState<MWMedia[]>([]);
|
||||||
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
|
async function runSearch() {
|
||||||
|
const results = await SearchProviders({ type: MWMediaType.MOVIE, searchQuery: search });
|
||||||
|
setResults(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Search</h1>
|
||||||
|
<SearchBarInput onChange={setSearch} value={search} onClick={runSearch}/>
|
||||||
|
<h1>Search results</h1>
|
||||||
|
{results.map((v)=>(<WatchedMediaCard media={v} />))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
7
src/views/SeriesView.tsx
Normal file
7
src/views/SeriesView.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export function SeriesView() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Series view here</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user