diff --git a/src/components/layout/Stepper.tsx b/src/components/layout/Stepper.tsx index 867a438c..75dc150b 100644 --- a/src/components/layout/Stepper.tsx +++ b/src/components/layout/Stepper.tsx @@ -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 (
diff --git a/src/components/text-inputs/AuthInputBox.tsx b/src/components/text-inputs/AuthInputBox.tsx index c79c079d..2e34594a 100644 --- a/src/components/text-inputs/AuthInputBox.tsx +++ b/src/components/text-inputs/AuthInputBox.tsx @@ -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 ( -
+
{props.label ? (

{props.label}

) : null} diff --git a/src/components/utils/ErrorLine.tsx b/src/components/utils/ErrorLine.tsx new file mode 100644 index 00000000..b0761fee --- /dev/null +++ b/src/components/utils/ErrorLine.tsx @@ -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 ( +

+ + {props.children} +

+ ); +} diff --git a/src/pages/onboarding/Onboarding.tsx b/src/pages/onboarding/Onboarding.tsx index 3387f044..01e4631b 100644 --- a/src/pages/onboarding/Onboarding.tsx +++ b/src/pages/onboarding/Onboarding.tsx @@ -89,14 +89,6 @@ export function OnboardingPage() { use the default setup

- - {/* - - */} ); diff --git a/src/pages/onboarding/OnboardingExtension.tsx b/src/pages/onboarding/OnboardingExtension.tsx index c3fa5380..b2e98c83 100644 --- a/src/pages/onboarding/OnboardingExtension.tsx +++ b/src/pages/onboarding/OnboardingExtension.tsx @@ -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 =

waiting on extension...

; + content = ( + <> + +

waiting on extension

+ + ); if (props.status === "disallowed") content =

Extension disabled for this page

; else if (props.status === "failed") content =

Failed to request status

; else if (props.status === "outdated") content =

Extension too old

; else if (props.status === "noperms") content =

No permissions to act

; else if (props.status === "success") content =

Extension is working!

; - return
{content}
; + return ( + +
+ {content} +
+
+ ); } export function OnboardingExtensionPage() { @@ -65,13 +78,26 @@ export function OnboardingExtensionPage() { - Lorem ipsum - Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum + + Let's start with an extension + + + Using the browser extension, you can get the best streams we have to + offer. With just a simple install. + + + Install extension + + - - +
+ + +
); diff --git a/src/pages/onboarding/OnboardingProxy.tsx b/src/pages/onboarding/OnboardingProxy.tsx index 0cb2b38b..be001de6 100644 --- a/src/pages/onboarding/OnboardingProxy.tsx +++ b/src/pages/onboarding/OnboardingProxy.tsx @@ -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() { - Lorem ipsum - Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum - - {error ?

url invalid

: null} - - + + Let's setup a custom proxy + + + Using a custom proxy, you can get great quality streams! + + Learn how to make a custom proxy +
+ + {error ? {error.message} : null} +
+ +
+ + +
); diff --git a/src/pages/onboarding/utils.tsx b/src/pages/onboarding/utils.tsx index 410875b7..e8129230 100644 --- a/src/pages/onboarding/utils.tsx +++ b/src/pages/onboarding/utils.tsx @@ -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 (
{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 ( - + { + 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}