mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-28 01:41:50 +01:00
Style onboarding pages
Co-authored-by: William Oldham <github@binaryoverload.co.uk>
This commit is contained in:
parent
bb147a1367
commit
9ec273e78c
@ -5,7 +5,7 @@ export interface StepperProps {
|
||||
}
|
||||
|
||||
export function Stepper(props: StepperProps) {
|
||||
const percentage = (props.current / (props.steps + 1)) * 100;
|
||||
const percentage = (props.current / props.steps) * 100;
|
||||
|
||||
return (
|
||||
<div className={props.className}>
|
||||
|
@ -1,3 +1,5 @@
|
||||
import classNames from "classnames";
|
||||
|
||||
import { TextInputControl } from "./TextInputControl";
|
||||
|
||||
export function AuthInputBox(props: {
|
||||
@ -8,9 +10,10 @@ export function AuthInputBox(props: {
|
||||
placeholder?: string;
|
||||
onChange?: (data: string) => void;
|
||||
passwordToggleable?: boolean;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className={classNames("space-y-3", props.className)}>
|
||||
{props.label ? (
|
||||
<p className="font-bold text-white">{props.label}</p>
|
||||
) : null}
|
||||
|
18
src/components/utils/ErrorLine.tsx
Normal file
18
src/components/utils/ErrorLine.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import classNames from "classnames";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
|
||||
export function ErrorLine(props: { children?: ReactNode; className?: string }) {
|
||||
return (
|
||||
<p
|
||||
className={classNames(
|
||||
"inline-flex items-center text-type-danger",
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
<Icon icon={Icons.WARNING} className="text-xl mr-4" />
|
||||
{props.children}
|
||||
</p>
|
||||
);
|
||||
}
|
@ -89,14 +89,6 @@ export function OnboardingPage() {
|
||||
use the default setup
|
||||
</a>
|
||||
</p>
|
||||
|
||||
{/* <Button onClick={() => navigate("/onboarding/proxy")}>
|
||||
Custom proxy
|
||||
</Button>
|
||||
<Button onClick={() => navigate("/onboarding/extension")}>
|
||||
Extension
|
||||
</Button>
|
||||
<Button onClick={skipModal.show}>Default</Button> */}
|
||||
</CenterContainer>
|
||||
</MinimalPageLayout>
|
||||
);
|
||||
|
@ -5,11 +5,13 @@ import { useAsyncFn, useInterval } from "react-use";
|
||||
import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
|
||||
import { extensionInfo } from "@/backend/extension/messaging";
|
||||
import { Button } from "@/components/buttons/Button";
|
||||
import { Loading } from "@/components/layout/Loading";
|
||||
import { Stepper } from "@/components/layout/Stepper";
|
||||
import { CenterContainer } from "@/components/layout/ThinContainer";
|
||||
import { Heading2, Paragraph } from "@/components/utils/Text";
|
||||
import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
|
||||
import { useRedirectBack } from "@/pages/onboarding/onboardingHooks";
|
||||
import { Card, Link } from "@/pages/onboarding/utils";
|
||||
import { PageTitle } from "@/pages/parts/util/PageTitle";
|
||||
|
||||
type ExtensionStatus =
|
||||
@ -36,14 +38,25 @@ export function ExtensionStatus(props: {
|
||||
}) {
|
||||
let content: ReactNode = null;
|
||||
if (props.loading || props.status === "unknown")
|
||||
content = <p>waiting on extension...</p>;
|
||||
content = (
|
||||
<>
|
||||
<Loading />
|
||||
<p>waiting on extension</p>
|
||||
</>
|
||||
);
|
||||
if (props.status === "disallowed")
|
||||
content = <p>Extension disabled for this page</p>;
|
||||
else if (props.status === "failed") content = <p>Failed to request status</p>;
|
||||
else if (props.status === "outdated") content = <p>Extension too old</p>;
|
||||
else if (props.status === "noperms") content = <p>No permissions to act</p>;
|
||||
else if (props.status === "success") content = <p>Extension is working!</p>;
|
||||
return <div>{content}</div>;
|
||||
return (
|
||||
<Card>
|
||||
<div className="flex py-6 flex-col space-y-2 items-center justify-center">
|
||||
{content}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export function OnboardingExtensionPage() {
|
||||
@ -65,13 +78,26 @@ export function OnboardingExtensionPage() {
|
||||
<PageTitle subpage k="global.pages.about" />
|
||||
<CenterContainer>
|
||||
<Stepper steps={2} current={2} className="mb-12" />
|
||||
<Heading2 className="!mt-0">Lorem ipsum</Heading2>
|
||||
<Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph>
|
||||
<Heading2 className="!mt-0 !text-3xl max-w-[435px]">
|
||||
Let's start with an extension
|
||||
</Heading2>
|
||||
<Paragraph className="max-w-[320px] mb-4">
|
||||
Using the browser extension, you can get the best streams we have to
|
||||
offer. With just a simple install.
|
||||
</Paragraph>
|
||||
<Link href="https://google.com" target="_blank" className="mb-12">
|
||||
Install extension
|
||||
</Link>
|
||||
|
||||
<ExtensionStatus status={value ?? "unknown"} loading={loading} />
|
||||
<Button onClick={() => navigate("/onboarding")}>Back</Button>
|
||||
<Button onClick={() => exec(true)}>
|
||||
{value === "success" ? "Continue" : "Check extension"}{" "}
|
||||
</Button>
|
||||
<div className="flex justify-between items-center mt-8">
|
||||
<Button onClick={() => navigate("/onboarding")} theme="secondary">
|
||||
Back
|
||||
</Button>
|
||||
<Button onClick={() => exec(true)} theme="purple">
|
||||
{value === "success" ? "Continue" : "Check extension"}{" "}
|
||||
</Button>
|
||||
</div>
|
||||
</CenterContainer>
|
||||
</MinimalPageLayout>
|
||||
);
|
||||
|
@ -7,9 +7,12 @@ import { Button } from "@/components/buttons/Button";
|
||||
import { Stepper } from "@/components/layout/Stepper";
|
||||
import { CenterContainer } from "@/components/layout/ThinContainer";
|
||||
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
||||
import { Divider } from "@/components/utils/Divider";
|
||||
import { ErrorLine } from "@/components/utils/ErrorLine";
|
||||
import { Heading2, Paragraph } from "@/components/utils/Text";
|
||||
import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
|
||||
import { useRedirectBack } from "@/pages/onboarding/onboardingHooks";
|
||||
import { Link } from "@/pages/onboarding/utils";
|
||||
import { PageTitle } from "@/pages/parts/util/PageTitle";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
@ -23,10 +26,14 @@ export function OnboardingProxyPage() {
|
||||
|
||||
const [{ loading, error }, test] = useAsyncFn(async () => {
|
||||
if (!url.startsWith("http")) throw new Error("Not a valid URL");
|
||||
const res = await singularProxiedFetch(url, testUrl, {});
|
||||
if (res.url !== testUrl) throw new Error("Not a proxy");
|
||||
setProxySet([url]);
|
||||
completeAndRedirect();
|
||||
try {
|
||||
const res = await singularProxiedFetch(url, testUrl, {});
|
||||
if (res.url !== testUrl) throw new Error("Not a proxy");
|
||||
setProxySet([url]);
|
||||
completeAndRedirect();
|
||||
} catch (e) {
|
||||
throw new Error("Could not connect to proxy");
|
||||
}
|
||||
}, [url, completeAndRedirect, setProxySet]);
|
||||
|
||||
return (
|
||||
@ -34,14 +41,32 @@ export function OnboardingProxyPage() {
|
||||
<PageTitle subpage k="global.pages.about" />
|
||||
<CenterContainer>
|
||||
<Stepper steps={2} current={2} className="mb-12" />
|
||||
<Heading2 className="!mt-0">Lorem ipsum</Heading2>
|
||||
<Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph>
|
||||
<AuthInputBox value={url} onChange={setUrl} placeholder="lorem ipsum" />
|
||||
{error ? <p>url invalid</p> : null}
|
||||
<Button onClick={() => navigate("/onboarding")} loading={loading}>
|
||||
Backagd
|
||||
</Button>
|
||||
<Button onClick={test}>Submit proxy</Button>
|
||||
<Heading2 className="!mt-0 !text-3xl max-w-[435px]">
|
||||
Let's setup a custom proxy
|
||||
</Heading2>
|
||||
<Paragraph className="max-w-[320px] !mb-5">
|
||||
Using a custom proxy, you can get great quality streams!
|
||||
</Paragraph>
|
||||
<Link>Learn how to make a custom proxy</Link>
|
||||
<div className="w-[400px] max-w-full mt-14 mb-28">
|
||||
<AuthInputBox
|
||||
label="Proxy URL"
|
||||
value={url}
|
||||
onChange={setUrl}
|
||||
placeholder="lorem ipsum"
|
||||
className="mb-4"
|
||||
/>
|
||||
{error ? <ErrorLine>{error.message}</ErrorLine> : null}
|
||||
</div>
|
||||
<Divider />
|
||||
<div className="flex justify-between">
|
||||
<Button theme="secondary" onClick={() => navigate("/onboarding")}>
|
||||
Back
|
||||
</Button>
|
||||
<Button theme="purple" loading={loading} onClick={test}>
|
||||
Submit proxy
|
||||
</Button>
|
||||
</div>
|
||||
</CenterContainer>
|
||||
</MinimalPageLayout>
|
||||
);
|
||||
|
@ -1,16 +1,22 @@
|
||||
import classNames from "classnames";
|
||||
import { ReactNode } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Heading2, Heading3, Paragraph } from "@/components/utils/Text";
|
||||
|
||||
export function Card(props: {
|
||||
children: React.ReactNode;
|
||||
onClick: () => void;
|
||||
children?: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="bg-onboarding-card hover:bg-onboarding-cardHover transition-colors duration-300 border border-onboarding-border rounded-lg p-7 cursor-pointer "
|
||||
className={classNames({
|
||||
"bg-onboarding-card duration-300 border border-onboarding-border rounded-lg p-7":
|
||||
true,
|
||||
"hover:bg-onboarding-cardHover transition-colors cursor-pointer":
|
||||
!!props.onClick,
|
||||
})}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
{props.children}
|
||||
@ -50,9 +56,27 @@ export function CardContent(props: {
|
||||
);
|
||||
}
|
||||
|
||||
export function Link(props: { children: React.ReactNode }) {
|
||||
export function Link(props: {
|
||||
children?: React.ReactNode;
|
||||
to?: string;
|
||||
href?: string;
|
||||
className?: string;
|
||||
target?: "_blank";
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<a className="text-onboarding-link cursor-pointer flex gap-2 items-center group hover:opacity-75 transition-opacity">
|
||||
<a
|
||||
onClick={() => {
|
||||
if (props.to) navigate(props.to);
|
||||
}}
|
||||
href={props.href}
|
||||
target={props.target}
|
||||
className={classNames(
|
||||
"text-onboarding-link cursor-pointer inline-flex gap-2 items-center group hover:opacity-75 transition-opacity",
|
||||
props.className,
|
||||
)}
|
||||
rel="noreferrer"
|
||||
>
|
||||
{props.children}
|
||||
<Icon
|
||||
icon={Icons.ARROW_RIGHT}
|
||||
|
Loading…
Reference in New Issue
Block a user