Style onboarding pages

Co-authored-by: William Oldham <github@binaryoverload.co.uk>
This commit is contained in:
mrjvs 2024-01-20 11:18:16 +01:00
parent bb147a1367
commit 9ec273e78c
7 changed files with 123 additions and 35 deletions

View File

@ -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}>

View File

@ -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}

View 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>
);
}

View File

@ -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>
);

View File

@ -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&apos;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>
);

View File

@ -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&apos;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>
);

View File

@ -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}