mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-26 16:31:50 +01:00
cleanup settings modal + add sources list
This commit is contained in:
parent
65d46190e6
commit
abec91a322
17
src/components/FlagIcon.tsx
Normal file
17
src/components/FlagIcon.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import classNames from "classnames";
|
||||
import "flag-icons/css/flag-icons.min.css";
|
||||
|
||||
export interface FlagIconProps {
|
||||
countryCode?: string;
|
||||
}
|
||||
|
||||
export function FlagIcon(props: FlagIconProps) {
|
||||
return (
|
||||
<span
|
||||
className={classNames(
|
||||
"!w-8 h-6 rounded overflow-hidden bg-video-context-flagBg bg-cover bg-center block fi",
|
||||
props.countryCode ? `fi-${props.countryCode}` : undefined
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,256 +1,27 @@
|
||||
import "flag-icons/css/flag-icons.min.css";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import classNames from "classnames";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { Toggle } from "@/components/buttons/Toggle";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Icons } from "@/components/Icon";
|
||||
import { OverlayAnchor } from "@/components/overlays/OverlayAnchor";
|
||||
import { Overlay } from "@/components/overlays/OverlayDisplay";
|
||||
import { OverlayPage } from "@/components/overlays/OverlayPage";
|
||||
import { OverlayRouter } from "@/components/overlays/OverlayRouter";
|
||||
import { SettingsMenu } from "@/components/player/atoms/settings/SettingsMenu";
|
||||
import { SourceSelectionView } from "@/components/player/atoms/settings/SourceSelectingView";
|
||||
import { VideoPlayerButton } from "@/components/player/internals/Button";
|
||||
import { Context } from "@/components/player/internals/ContextUtils";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import {
|
||||
SourceQuality,
|
||||
allQualities,
|
||||
qualityToString,
|
||||
} from "@/stores/player/utils/qualities";
|
||||
|
||||
function QualityOption(props: {
|
||||
children: React.ReactNode;
|
||||
selected?: boolean;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
}) {
|
||||
let textClasses;
|
||||
if (props.selected) textClasses = "text-white";
|
||||
if (props.disabled)
|
||||
textClasses = "text-video-context-type-main text-opacity-40";
|
||||
|
||||
return (
|
||||
<Context.Link onClick={props.disabled ? undefined : props.onClick}>
|
||||
<Context.LinkTitle textClass={textClasses}>
|
||||
{props.children}
|
||||
</Context.LinkTitle>
|
||||
{props.selected ? (
|
||||
<Icon
|
||||
icon={Icons.CIRCLE_CHECK}
|
||||
className="text-xl text-video-context-type-accent"
|
||||
/>
|
||||
) : null}
|
||||
</Context.Link>
|
||||
);
|
||||
}
|
||||
|
||||
function QualityView({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
const availableQualities = usePlayerStore((s) => s.qualities);
|
||||
const currentQuality = usePlayerStore((s) => s.currentQuality);
|
||||
const switchQuality = usePlayerStore((s) => s.switchQuality);
|
||||
|
||||
const change = useCallback(
|
||||
(q: SourceQuality) => {
|
||||
switchQuality(q);
|
||||
router.close();
|
||||
},
|
||||
[router, switchQuality]
|
||||
);
|
||||
|
||||
const allVisibleQualities = allQualities.filter((t) => t !== "unknown");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Context.BackLink onClick={() => router.navigate("/")}>
|
||||
Quality
|
||||
</Context.BackLink>
|
||||
<Context.Section>
|
||||
{allVisibleQualities.map((v) => (
|
||||
<QualityOption
|
||||
key={v}
|
||||
selected={v === currentQuality}
|
||||
onClick={
|
||||
availableQualities.includes(v) ? () => change(v) : undefined
|
||||
}
|
||||
disabled={!availableQualities.includes(v)}
|
||||
>
|
||||
{qualityToString(v)}
|
||||
</QualityOption>
|
||||
))}
|
||||
<Context.Divider />
|
||||
<Context.Link>
|
||||
<Context.LinkTitle>Automatic quality</Context.LinkTitle>
|
||||
<span>Toggle</span>
|
||||
</Context.Link>
|
||||
<Context.SmallText>
|
||||
You can try{" "}
|
||||
<Context.Anchor onClick={() => router.navigate("/source")}>
|
||||
switching source
|
||||
</Context.Anchor>{" "}
|
||||
to get different quality options.
|
||||
</Context.SmallText>
|
||||
</Context.Section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function ColorOption(props: {
|
||||
color: string;
|
||||
active?: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"p-1.5 bg-video-context-buttonFocus rounded transition-colors duration-100",
|
||||
props.active ? "bg-opacity-100" : "bg-opacity-0 cursor-pointer"
|
||||
)}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<div
|
||||
className="w-6 h-6 rounded-full flex justify-center items-center"
|
||||
style={{ backgroundColor: props.color }}
|
||||
>
|
||||
{props.active ? (
|
||||
<Icon className="text-sm text-black" icon={Icons.CHECKMARK} />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CaptionSettingsView({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Context.BackLink onClick={() => router.navigate("/captions")}>
|
||||
Custom captions
|
||||
</Context.BackLink>
|
||||
<Context.Section>
|
||||
<div className="flex justify-between items-center">
|
||||
<Context.FieldTitle>Color</Context.FieldTitle>
|
||||
<div className="flex justify-center items-center">
|
||||
<ColorOption onClick={() => {}} color="#FFFFFF" active />
|
||||
<ColorOption onClick={() => {}} color="#80B1FA" />
|
||||
<ColorOption onClick={() => {}} color="#E2E535" />
|
||||
</div>
|
||||
</div>
|
||||
</Context.Section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function CaptionOption(props: {
|
||||
countryCode?: string;
|
||||
children: React.ReactNode;
|
||||
selected?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="grid grid-cols-[auto,1fr,auto] items-center gap-3 rounded -ml-3 -mr-3 px-3 py-2 cursor-pointer hover:bg-video-context-border hover:bg-opacity-10">
|
||||
<div>
|
||||
<span
|
||||
className={classNames(
|
||||
"!w-8 h-6 rounded overflow-hidden bg-video-context-flagBg bg-cover bg-center block fi",
|
||||
props.countryCode ? `fi-${props.countryCode}` : undefined
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className={classNames(props.selected && "text-white", "font-medium")}
|
||||
>
|
||||
{props.children}
|
||||
</span>
|
||||
{props.selected ? (
|
||||
<Icon
|
||||
icon={Icons.CIRCLE_CHECK}
|
||||
className="text-xl text-video-context-type-accent"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CaptionsView({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Context.BackLink
|
||||
onClick={() => router.navigate("/")}
|
||||
rightSide={
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.navigate("/captions/settings")}
|
||||
>
|
||||
Customize
|
||||
</button>
|
||||
}
|
||||
>
|
||||
Captions
|
||||
</Context.BackLink>
|
||||
<Context.Section>
|
||||
<CaptionOption>Off</CaptionOption>
|
||||
<CaptionOption countryCode="nl" selected>
|
||||
Nederlands
|
||||
</CaptionOption>
|
||||
<CaptionOption countryCode="gr">Idk Gibraltar of zo?</CaptionOption>
|
||||
</Context.Section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
import { CaptionSettingsView } from "./settings/CaptionSettingsView";
|
||||
import { CaptionsView } from "./settings/CaptionsView";
|
||||
import { QualityView } from "./settings/QualityView";
|
||||
|
||||
function SettingsOverlay({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
const currentQuality = usePlayerStore((s) => s.currentQuality);
|
||||
|
||||
const [tmpBool, setTmpBool] = useState(false);
|
||||
|
||||
function toggleBool() {
|
||||
setTmpBool(!tmpBool);
|
||||
}
|
||||
|
||||
return (
|
||||
<Overlay id={id}>
|
||||
<OverlayRouter id={id}>
|
||||
<OverlayPage id={id} path="/" width={343} height={431}>
|
||||
<Context.Card>
|
||||
<Context.SectionTitle>Video settings</Context.SectionTitle>
|
||||
<Context.Section>
|
||||
<Context.Link onClick={() => router.navigate("/quality")}>
|
||||
<Context.LinkTitle>Quality</Context.LinkTitle>
|
||||
<Context.LinkChevron>
|
||||
{currentQuality ? qualityToString(currentQuality) : ""}
|
||||
</Context.LinkChevron>
|
||||
</Context.Link>
|
||||
<Context.Link onClick={() => router.navigate("/source")}>
|
||||
<Context.LinkTitle>Video source</Context.LinkTitle>
|
||||
<Context.LinkChevron>SuperStream</Context.LinkChevron>
|
||||
</Context.Link>
|
||||
<Context.Link>
|
||||
<Context.LinkTitle>Download</Context.LinkTitle>
|
||||
<Context.IconButton icon={Icons.DOWNLOAD} />
|
||||
</Context.Link>
|
||||
</Context.Section>
|
||||
|
||||
<Context.SectionTitle>Viewing Experience</Context.SectionTitle>
|
||||
<Context.Section>
|
||||
<Context.Link>
|
||||
<Context.LinkTitle>Enable Captions</Context.LinkTitle>
|
||||
<Toggle enabled={tmpBool} onClick={() => toggleBool()} />
|
||||
</Context.Link>
|
||||
<Context.Link onClick={() => router.navigate("/captions")}>
|
||||
<Context.LinkTitle>Caption settings</Context.LinkTitle>
|
||||
<Context.LinkChevron>English</Context.LinkChevron>
|
||||
</Context.Link>
|
||||
<Context.Link>
|
||||
<Context.LinkTitle>Playback settings</Context.LinkTitle>
|
||||
<Context.LinkChevron />
|
||||
</Context.Link>
|
||||
</Context.Section>
|
||||
</Context.Card>
|
||||
<SettingsMenu id={id} />
|
||||
</OverlayPage>
|
||||
<OverlayPage id={id} path="/quality" width={343} height={431}>
|
||||
<Context.Card>
|
||||
@ -269,10 +40,7 @@ function SettingsOverlay({ id }: { id: string }) {
|
||||
</OverlayPage>
|
||||
<OverlayPage id={id} path="/source" width={343} height={431}>
|
||||
<Context.Card>
|
||||
<Context.BackLink onClick={() => router.navigate("/")}>
|
||||
It's a minion!
|
||||
</Context.BackLink>
|
||||
<img src="https://media2.giphy.com/media/oa4Au5xDZ6HJYF6KGH/giphy.gif" />
|
||||
<SourceSelectionView id={id} />
|
||||
</Context.Card>
|
||||
</OverlayPage>
|
||||
</OverlayRouter>
|
||||
|
52
src/components/player/atoms/settings/CaptionSettingsView.tsx
Normal file
52
src/components/player/atoms/settings/CaptionSettingsView.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import classNames from "classnames";
|
||||
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Context } from "@/components/player/internals/ContextUtils";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
|
||||
export function ColorOption(props: {
|
||||
color: string;
|
||||
active?: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"p-1.5 bg-video-context-buttonFocus rounded transition-colors duration-100",
|
||||
props.active ? "bg-opacity-100" : "bg-opacity-0 cursor-pointer"
|
||||
)}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<div
|
||||
className="w-6 h-6 rounded-full flex justify-center items-center"
|
||||
style={{ backgroundColor: props.color }}
|
||||
>
|
||||
{props.active ? (
|
||||
<Icon className="text-sm text-black" icon={Icons.CHECKMARK} />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function CaptionSettingsView({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Context.BackLink onClick={() => router.navigate("/captions")}>
|
||||
Custom captions
|
||||
</Context.BackLink>
|
||||
<Context.Section>
|
||||
<div className="flex justify-between items-center">
|
||||
<Context.FieldTitle>Color</Context.FieldTitle>
|
||||
<div className="flex justify-center items-center">
|
||||
<ColorOption onClick={() => {}} color="#FFFFFF" active />
|
||||
<ColorOption onClick={() => {}} color="#80B1FA" />
|
||||
<ColorOption onClick={() => {}} color="#E2E535" />
|
||||
</div>
|
||||
</div>
|
||||
</Context.Section>
|
||||
</>
|
||||
);
|
||||
}
|
60
src/components/player/atoms/settings/CaptionsView.tsx
Normal file
60
src/components/player/atoms/settings/CaptionsView.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import classNames from "classnames";
|
||||
|
||||
import { FlagIcon } from "@/components/FlagIcon";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Context } from "@/components/player/internals/ContextUtils";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
|
||||
export function CaptionOption(props: {
|
||||
countryCode?: string;
|
||||
children: React.ReactNode;
|
||||
selected?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="grid grid-cols-[auto,1fr,auto] items-center gap-3 rounded -ml-3 -mr-3 px-3 py-2 cursor-pointer hover:bg-video-context-border hover:bg-opacity-10">
|
||||
<div>
|
||||
<FlagIcon countryCode={props.countryCode} />
|
||||
</div>
|
||||
<span
|
||||
className={classNames(props.selected && "text-white", "font-medium")}
|
||||
>
|
||||
{props.children}
|
||||
</span>
|
||||
{props.selected ? (
|
||||
<Icon
|
||||
icon={Icons.CIRCLE_CHECK}
|
||||
className="text-xl text-video-context-type-accent"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function CaptionsView({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Context.BackLink
|
||||
onClick={() => router.navigate("/")}
|
||||
rightSide={
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.navigate("/captions/settings")}
|
||||
>
|
||||
Customize
|
||||
</button>
|
||||
}
|
||||
>
|
||||
Captions
|
||||
</Context.BackLink>
|
||||
<Context.Section>
|
||||
<CaptionOption>Off</CaptionOption>
|
||||
<CaptionOption countryCode="nl" selected>
|
||||
Nederlands
|
||||
</CaptionOption>
|
||||
<CaptionOption countryCode="gr">Idk Gibraltar of zo?</CaptionOption>
|
||||
</Context.Section>
|
||||
</>
|
||||
);
|
||||
}
|
88
src/components/player/atoms/settings/QualityView.tsx
Normal file
88
src/components/player/atoms/settings/QualityView.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Context } from "@/components/player/internals/ContextUtils";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import {
|
||||
SourceQuality,
|
||||
allQualities,
|
||||
qualityToString,
|
||||
} from "@/stores/player/utils/qualities";
|
||||
|
||||
export function QualityOption(props: {
|
||||
children: React.ReactNode;
|
||||
selected?: boolean;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
}) {
|
||||
let textClasses;
|
||||
if (props.selected) textClasses = "text-white";
|
||||
if (props.disabled)
|
||||
textClasses = "text-video-context-type-main text-opacity-40";
|
||||
|
||||
return (
|
||||
<Context.Link onClick={props.disabled ? undefined : props.onClick}>
|
||||
<Context.LinkTitle textClass={textClasses}>
|
||||
{props.children}
|
||||
</Context.LinkTitle>
|
||||
{props.selected ? (
|
||||
<Icon
|
||||
icon={Icons.CIRCLE_CHECK}
|
||||
className="text-xl text-video-context-type-accent"
|
||||
/>
|
||||
) : null}
|
||||
</Context.Link>
|
||||
);
|
||||
}
|
||||
|
||||
export function QualityView({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
const availableQualities = usePlayerStore((s) => s.qualities);
|
||||
const currentQuality = usePlayerStore((s) => s.currentQuality);
|
||||
const switchQuality = usePlayerStore((s) => s.switchQuality);
|
||||
|
||||
const change = useCallback(
|
||||
(q: SourceQuality) => {
|
||||
switchQuality(q);
|
||||
router.close();
|
||||
},
|
||||
[router, switchQuality]
|
||||
);
|
||||
|
||||
const allVisibleQualities = allQualities.filter((t) => t !== "unknown");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Context.BackLink onClick={() => router.navigate("/")}>
|
||||
Quality
|
||||
</Context.BackLink>
|
||||
<Context.Section>
|
||||
{allVisibleQualities.map((v) => (
|
||||
<QualityOption
|
||||
key={v}
|
||||
selected={v === currentQuality}
|
||||
onClick={
|
||||
availableQualities.includes(v) ? () => change(v) : undefined
|
||||
}
|
||||
disabled={!availableQualities.includes(v)}
|
||||
>
|
||||
{qualityToString(v)}
|
||||
</QualityOption>
|
||||
))}
|
||||
<Context.Divider />
|
||||
<Context.Link>
|
||||
<Context.LinkTitle>Automatic quality</Context.LinkTitle>
|
||||
<span>Toggle</span>
|
||||
</Context.Link>
|
||||
<Context.SmallText>
|
||||
You can try{" "}
|
||||
<Context.Anchor onClick={() => router.navigate("/source")}>
|
||||
switching source
|
||||
</Context.Anchor>{" "}
|
||||
to get different quality options.
|
||||
</Context.SmallText>
|
||||
</Context.Section>
|
||||
</>
|
||||
);
|
||||
}
|
57
src/components/player/atoms/settings/SettingsMenu.tsx
Normal file
57
src/components/player/atoms/settings/SettingsMenu.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { Toggle } from "@/components/buttons/Toggle";
|
||||
import { Icons } from "@/components/Icon";
|
||||
import { Context } from "@/components/player/internals/ContextUtils";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { qualityToString } from "@/stores/player/utils/qualities";
|
||||
|
||||
export function SettingsMenu({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
const currentQuality = usePlayerStore((s) => s.currentQuality);
|
||||
|
||||
const [tmpBool, setTmpBool] = useState(false);
|
||||
|
||||
function toggleBool() {
|
||||
setTmpBool(!tmpBool);
|
||||
}
|
||||
|
||||
return (
|
||||
<Context.Card>
|
||||
<Context.SectionTitle>Video settings</Context.SectionTitle>
|
||||
<Context.Section>
|
||||
<Context.Link onClick={() => router.navigate("/quality")}>
|
||||
<Context.LinkTitle>Quality</Context.LinkTitle>
|
||||
<Context.LinkChevron>
|
||||
{currentQuality ? qualityToString(currentQuality) : ""}
|
||||
</Context.LinkChevron>
|
||||
</Context.Link>
|
||||
<Context.Link onClick={() => router.navigate("/source")}>
|
||||
<Context.LinkTitle>Video source</Context.LinkTitle>
|
||||
<Context.LinkChevron>SuperStream</Context.LinkChevron>
|
||||
</Context.Link>
|
||||
<Context.Link>
|
||||
<Context.LinkTitle>Download</Context.LinkTitle>
|
||||
<Context.IconButton icon={Icons.DOWNLOAD} />
|
||||
</Context.Link>
|
||||
</Context.Section>
|
||||
|
||||
<Context.SectionTitle>Viewing Experience</Context.SectionTitle>
|
||||
<Context.Section>
|
||||
<Context.Link>
|
||||
<Context.LinkTitle>Enable Captions</Context.LinkTitle>
|
||||
<Toggle enabled={tmpBool} onClick={() => toggleBool()} />
|
||||
</Context.Link>
|
||||
<Context.Link onClick={() => router.navigate("/captions")}>
|
||||
<Context.LinkTitle>Caption settings</Context.LinkTitle>
|
||||
<Context.LinkChevron>English</Context.LinkChevron>
|
||||
</Context.Link>
|
||||
<Context.Link>
|
||||
<Context.LinkTitle>Playback settings</Context.LinkTitle>
|
||||
<Context.LinkChevron />
|
||||
</Context.Link>
|
||||
</Context.Section>
|
||||
</Context.Card>
|
||||
);
|
||||
}
|
57
src/components/player/atoms/settings/SourceSelectingView.tsx
Normal file
57
src/components/player/atoms/settings/SourceSelectingView.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import classNames from "classnames";
|
||||
import { useMemo } from "react";
|
||||
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Context } from "@/components/player/internals/ContextUtils";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { providers } from "@/utils/providers";
|
||||
|
||||
export function SourceOption(props: {
|
||||
children: React.ReactNode;
|
||||
selected?: boolean;
|
||||
onClick?: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
onClick={props.onClick}
|
||||
className="grid grid-cols-[auto,1fr,auto] items-center gap-3 rounded -ml-3 -mr-3 px-3 py-2 cursor-pointer hover:bg-video-context-border hover:bg-opacity-10"
|
||||
>
|
||||
<span
|
||||
className={classNames(props.selected && "text-white", "font-medium")}
|
||||
>
|
||||
{props.children}
|
||||
</span>
|
||||
{props.selected ? (
|
||||
<Icon
|
||||
icon={Icons.CIRCLE_CHECK}
|
||||
className="text-xl text-video-context-type-accent"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SourceSelectionView({ id }: { id: string }) {
|
||||
const router = useOverlayRouter(id);
|
||||
const metaType = usePlayerStore((s) => s.meta?.type);
|
||||
const sources = useMemo(() => {
|
||||
if (!metaType) return [];
|
||||
return providers
|
||||
.listSources()
|
||||
.filter((v) => v.mediaTypes?.includes(metaType));
|
||||
}, [metaType]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Context.BackLink onClick={() => router.navigate("/")}>
|
||||
Sources
|
||||
</Context.BackLink>
|
||||
<Context.Section>
|
||||
{sources.map((v) => (
|
||||
<SourceOption key={v.id}>{v.name}</SourceOption>
|
||||
))}
|
||||
</Context.Section>
|
||||
</>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user