Add full layout and styling for the first step in onboarding

Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
mrjvs 2024-01-18 19:22:55 +01:00
parent 3b2be31691
commit dc95bd7455
5 changed files with 137 additions and 9 deletions

View File

@ -12,9 +12,9 @@ export function Stepper(props: StepperProps) {
<p className="mb-2"> <p className="mb-2">
{props.current}/{props.steps} {props.current}/{props.steps}
</p> </p>
<div className="max-w-full h-1 w-32 bg-white rounded-full overflow-hidden"> <div className="max-w-full h-1 w-32 bg-onboarding-bar rounded-full overflow-hidden">
<div <div
className="h-full bg-blue-500 transition-[width] rounded-full" className="h-full bg-onboarding-barFilled transition-[width] rounded-full"
style={{ style={{
width: `${percentage.toFixed(0)}%`, width: `${percentage.toFixed(0)}%`,
}} }}

View File

@ -26,7 +26,7 @@ export function CenterContainer(props: ThinContainerProps) {
props.classNames, props.classNames,
)} )}
> >
<div className="w-[600px] max-w-full">{props.children}</div> <div className="w-[700px] max-w-full">{props.children}</div>
</div> </div>
); );
} }

View File

@ -1,14 +1,24 @@
import classNames from "classnames";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { Button } from "@/components/buttons/Button"; import { Button } from "@/components/buttons/Button";
import { Stepper } from "@/components/layout/Stepper"; import { Stepper } from "@/components/layout/Stepper";
import { CenterContainer } from "@/components/layout/ThinContainer"; import { CenterContainer } from "@/components/layout/ThinContainer";
import { Modal, ModalCard, useModal } from "@/components/overlays/Modal"; import { Modal, ModalCard, useModal } from "@/components/overlays/Modal";
import { Heading2, Paragraph } from "@/components/utils/Text"; import { Heading1, Heading2, Paragraph } from "@/components/utils/Text";
import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout"; import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
import { useRedirectBack } from "@/pages/onboarding/onboardingHooks"; import { useRedirectBack } from "@/pages/onboarding/onboardingHooks";
import { Card, CardContent, Link } from "@/pages/onboarding/utils";
import { PageTitle } from "@/pages/parts/util/PageTitle"; import { PageTitle } from "@/pages/parts/util/PageTitle";
function VerticalLine(props: { className?: string }) {
return (
<div className={classNames("w-full grid justify-center", props.className)}>
<div className="w-px h-10 bg-onboarding-divider" />
</div>
);
}
export function OnboardingPage() { export function OnboardingPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const skipModal = useModal("skip"); const skipModal = useModal("skip");
@ -20,7 +30,7 @@ export function OnboardingPage() {
<Modal id={skipModal.id}> <Modal id={skipModal.id}>
<ModalCard> <ModalCard>
<ModalCard> <ModalCard>
<Heading2 className="!mt-0">Lorem ipsum</Heading2> <Heading1 className="!mt-0">Lorem ipsum</Heading1>
<Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph> <Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph>
<Button theme="secondary" onClick={skipModal.hide}> <Button theme="secondary" onClick={skipModal.hide}>
Lorem ipsum Lorem ipsum
@ -33,15 +43,60 @@ export function OnboardingPage() {
</Modal> </Modal>
<CenterContainer> <CenterContainer>
<Stepper steps={2} current={1} className="mb-12" /> <Stepper steps={2} current={1} className="mb-12" />
<Heading2 className="!mt-0">Lorem ipsum</Heading2> <Heading2 className="!mt-0 !text-3xl max-w-[435px]">
<Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph> Let&apos;s get you set up with movie-web
<Button onClick={() => navigate("/onboarding/proxy")}> </Heading2>
<Paragraph className="max-w-[320px]">
To get the best streams possible, you will need to choose which
streaming method you want to use.
</Paragraph>
<div className="w-full grid grid-cols-[1fr,auto,1fr] gap-3">
<Card onClick={() => navigate("/onboarding/proxy")}>
<CardContent
colorClass="!text-onboarding-good"
title="Custom proxy"
subtitle="Good quality"
description="Set up a proxy in only 5 minutes and gain access to great sources."
>
<Link>Set up proxy</Link>
</CardContent>
</Card>
<div className="grid grid-rows-[1fr,auto,1fr] justify-center gap-4">
<VerticalLine className="items-end" />
<span className="text-xs uppercase font-bold">or</span>
<VerticalLine />
</div>
<Card onClick={() => navigate("/onboarding/extension")}>
<CardContent
colorClass="!text-onboarding-best"
title="Browser extension — best quality"
subtitle="Best quality"
description="Install browser extension and gain access to the best sources."
>
<Link>Install extension</Link>
</CardContent>
</Card>
</div>
<p className="text-center mt-12">
I don&apos;t want good quality, <br />
<a
onClick={skipModal.show}
type="button"
className="text-onboarding-link cursor-pointer"
>
use the default setup
</a>
</p>
{/* <Button onClick={() => navigate("/onboarding/proxy")}>
Custom proxy Custom proxy
</Button> </Button>
<Button onClick={() => navigate("/onboarding/extension")}> <Button onClick={() => navigate("/onboarding/extension")}>
Extension Extension
</Button> </Button>
<Button onClick={skipModal.show}>Default</Button> <Button onClick={skipModal.show}>Default</Button> */}
</CenterContainer> </CenterContainer>
</MinimalPageLayout> </MinimalPageLayout>
); );

View File

@ -0,0 +1,59 @@
import classNames from "classnames";
import { Icon, Icons } from "@/components/Icon";
import { Heading2, Heading3, Paragraph } from "@/components/utils/Text";
export function Card(props: {
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 "
onClick={props.onClick}
>
{props.children}
</div>
);
}
export function CardContent(props: {
title: string;
description: string;
subtitle: string;
colorClass: string;
children?: React.ReactNode;
}) {
return (
<div className="grid grid-rows-[1fr,auto] h-full">
<div>
<Icon
icon={Icons.RISING_STAR}
className={classNames("text-4xl mb-8 block", props.colorClass)}
/>
<Heading3
className={classNames(
"!mt-0 !mb-0 !text-xs uppercase",
props.colorClass,
)}
>
{props.subtitle}
</Heading3>
<Heading2 className="!mb-0 !mt-1 !text-base">{props.title}</Heading2>
<Paragraph className="max-w-[320px] !my-4">
{props.description}
</Paragraph>
</div>
<div>{props.children}</div>
</div>
);
}
export function Link(props: { children: React.ReactNode }) {
return (
<a className="text-onboarding-link cursor-pointer flex gap-2 items-center">
{props.children}
<Icon icon={Icons.ARROW_RIGHT} />
</a>
);
}

View File

@ -228,10 +228,24 @@ export const defaultTheme = {
} }
}, },
// Utilities
utils: { utils: {
divider: tokens.ash.c300, divider: tokens.ash.c300,
}, },
// Onboarding
onboarding: {
bar: tokens.shade.c400,
barFilled: tokens.purple.c300,
divider: tokens.shade.c200,
card: tokens.shade.c800,
cardHover: tokens.shade.c700,
border: tokens.shade.c600,
good: tokens.purple.c100,
best: tokens.semantic.yellow.c100,
link: tokens.purple.c100,
},
// Error page // Error page
errors: { errors: {
card: tokens.shade.c800, card: tokens.shade.c800,