From dc95bd7455adc85a3ef9fe7ee986c18b9486150f Mon Sep 17 00:00:00 2001 From: mrjvs <jellevs@gmail.com> Date: Thu, 18 Jan 2024 19:22:55 +0100 Subject: [PATCH] Add full layout and styling for the first step in onboarding Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com> --- src/components/layout/Stepper.tsx | 4 +- src/components/layout/ThinContainer.tsx | 2 +- src/pages/onboarding/Onboarding.tsx | 67 ++++++++++++++++++++++--- src/pages/onboarding/utils.tsx | 59 ++++++++++++++++++++++ themes/default.ts | 14 ++++++ 5 files changed, 137 insertions(+), 9 deletions(-) create mode 100644 src/pages/onboarding/utils.tsx diff --git a/src/components/layout/Stepper.tsx b/src/components/layout/Stepper.tsx index d0c9c499..867a438c 100644 --- a/src/components/layout/Stepper.tsx +++ b/src/components/layout/Stepper.tsx @@ -12,9 +12,9 @@ export function Stepper(props: StepperProps) { <p className="mb-2"> {props.current}/{props.steps} </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 - className="h-full bg-blue-500 transition-[width] rounded-full" + className="h-full bg-onboarding-barFilled transition-[width] rounded-full" style={{ width: `${percentage.toFixed(0)}%`, }} diff --git a/src/components/layout/ThinContainer.tsx b/src/components/layout/ThinContainer.tsx index 345afa5c..8b128040 100644 --- a/src/components/layout/ThinContainer.tsx +++ b/src/components/layout/ThinContainer.tsx @@ -26,7 +26,7 @@ export function CenterContainer(props: ThinContainerProps) { props.classNames, )} > - <div className="w-[600px] max-w-full">{props.children}</div> + <div className="w-[700px] max-w-full">{props.children}</div> </div> ); } diff --git a/src/pages/onboarding/Onboarding.tsx b/src/pages/onboarding/Onboarding.tsx index 3247a7ee..05879507 100644 --- a/src/pages/onboarding/Onboarding.tsx +++ b/src/pages/onboarding/Onboarding.tsx @@ -1,14 +1,24 @@ +import classNames from "classnames"; import { useNavigate } from "react-router-dom"; import { Button } from "@/components/buttons/Button"; import { Stepper } from "@/components/layout/Stepper"; import { CenterContainer } from "@/components/layout/ThinContainer"; 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 { useRedirectBack } from "@/pages/onboarding/onboardingHooks"; +import { Card, CardContent, Link } from "@/pages/onboarding/utils"; 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() { const navigate = useNavigate(); const skipModal = useModal("skip"); @@ -20,7 +30,7 @@ export function OnboardingPage() { <Modal id={skipModal.id}> <ModalCard> <ModalCard> - <Heading2 className="!mt-0">Lorem ipsum</Heading2> + <Heading1 className="!mt-0">Lorem ipsum</Heading1> <Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph> <Button theme="secondary" onClick={skipModal.hide}> Lorem ipsum @@ -33,15 +43,60 @@ export function OnboardingPage() { </Modal> <CenterContainer> <Stepper steps={2} current={1} className="mb-12" /> - <Heading2 className="!mt-0">Lorem ipsum</Heading2> - <Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph> - <Button onClick={() => navigate("/onboarding/proxy")}> + <Heading2 className="!mt-0 !text-3xl max-w-[435px]"> + Let's get you set up with movie-web + </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'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 </Button> <Button onClick={() => navigate("/onboarding/extension")}> Extension </Button> - <Button onClick={skipModal.show}>Default</Button> + <Button onClick={skipModal.show}>Default</Button> */} </CenterContainer> </MinimalPageLayout> ); diff --git a/src/pages/onboarding/utils.tsx b/src/pages/onboarding/utils.tsx new file mode 100644 index 00000000..eaf722b2 --- /dev/null +++ b/src/pages/onboarding/utils.tsx @@ -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> + ); +} diff --git a/themes/default.ts b/themes/default.ts index 7a010338..bf2510ff 100644 --- a/themes/default.ts +++ b/themes/default.ts @@ -228,10 +228,24 @@ export const defaultTheme = { } }, + // Utilities utils: { 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 errors: { card: tokens.shade.c800,