mirror of
https://github.com/codex-storage/codex-marketplace-ui.git
synced 2025-02-24 05:38:18 +00:00
Improve onboarding screen
This commit is contained in:
parent
ed932e1baf
commit
d4667c5ec7
@ -1,14 +1,10 @@
|
|||||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { CodexSdk } from "../../sdk/codex";
|
|
||||||
import {
|
import {
|
||||||
NetworkIndicator,
|
NetworkIndicator,
|
||||||
Toast,
|
Toast,
|
||||||
} from "@codex-storage/marketplace-ui-components";
|
} from "@codex-storage/marketplace-ui-components";
|
||||||
import { Promises } from "../../utils/promises";
|
import { useCodexConnection } from "../../hooks/useCodexConnection";
|
||||||
|
|
||||||
const report = false;
|
|
||||||
export let isCodexOnline: boolean | null = null;
|
|
||||||
|
|
||||||
export function NodeIndicator() {
|
export function NodeIndicator() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@ -16,44 +12,19 @@ export function NodeIndicator() {
|
|||||||
time: 0,
|
time: 0,
|
||||||
message: "",
|
message: "",
|
||||||
});
|
});
|
||||||
|
const codex = useCodexConnection();
|
||||||
const { data, isError } = useQuery({
|
|
||||||
queryKey: ["spr"],
|
|
||||||
queryFn: async () => {
|
|
||||||
return CodexSdk.node()
|
|
||||||
.spr()
|
|
||||||
.then((data) => Promises.rejectOnError(data, report));
|
|
||||||
},
|
|
||||||
refetchInterval: 5000,
|
|
||||||
|
|
||||||
// No need to retry because we defined a refetch interval
|
|
||||||
retry: false,
|
|
||||||
|
|
||||||
// The client node should be local, so display the cache value while
|
|
||||||
// making a background request looks good.
|
|
||||||
staleTime: 0,
|
|
||||||
|
|
||||||
// Refreshing when focus returns can be useful if a user comes back
|
|
||||||
// to the UI after performing an operation in the terminal.
|
|
||||||
refetchOnWindowFocus: true,
|
|
||||||
|
|
||||||
// Cache is not useful for the spr endpoint
|
|
||||||
gcTime: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
isCodexOnline = !isError && !!data;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
type: "active",
|
type: "active",
|
||||||
refetchType: "all",
|
refetchType: "all",
|
||||||
});
|
});
|
||||||
}, [queryClient, isCodexOnline]);
|
}, [queryClient, codex.enabled]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Toast message={toast.message} time={toast.time} variant="success" />
|
<Toast message={toast.message} time={toast.time} variant="success" />
|
||||||
<NetworkIndicator online={isCodexOnline} text="Codex node" />
|
<NetworkIndicator online={codex.enabled} text="Codex node" />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
100
src/components/OnBoarding/OnBoardingStepOne.tsx
Normal file
100
src/components/OnBoarding/OnBoardingStepOne.tsx
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import { AlphaIcon } from "./AlphaIcon";
|
||||||
|
import { AlphaText } from "../AlphaText/AlphaText";
|
||||||
|
import { Modal, SimpleText } from "@codex-storage/marketplace-ui-components";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ArrowRight } from "lucide-react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
onNextStep: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function OnBoardingStepOne({ onNextStep }: Props) {
|
||||||
|
const [modal, setModal] = useState(false);
|
||||||
|
|
||||||
|
const onLegalDisclaimerOpen = () => setModal(true);
|
||||||
|
|
||||||
|
const onLegalDisclaimerClose = () => setModal(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="index-column-section">
|
||||||
|
<div>
|
||||||
|
<AlphaIcon />
|
||||||
|
</div>
|
||||||
|
<div className="index-alphaText">
|
||||||
|
<p>
|
||||||
|
<AlphaText></AlphaText>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<SimpleText className="index-version" variant="normal">
|
||||||
|
{import.meta.env.PACKAGE_VERSION}
|
||||||
|
</SimpleText>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<SimpleText
|
||||||
|
className="index-disclaimer"
|
||||||
|
variant="error"
|
||||||
|
onClick={onLegalDisclaimerOpen}>
|
||||||
|
<a className="index-link">Legal Disclaimer</a>
|
||||||
|
</SimpleText>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="index-column-section">
|
||||||
|
<h3 className="index-mainTitle">
|
||||||
|
Hello,
|
||||||
|
<br /> Welcome to <span className="index-codex">Codex</span>{" "}
|
||||||
|
<span className="index-vault">Vault</span>
|
||||||
|
</h3>
|
||||||
|
<p className="index-description">
|
||||||
|
<SimpleText variant="light">
|
||||||
|
Codex is a durable, decentralised data storage protocol, created so
|
||||||
|
the world community can preserve its most important knowledge
|
||||||
|
without risk of censorship.
|
||||||
|
</SimpleText>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="index-column-section ">
|
||||||
|
<SimpleText variant="primary">
|
||||||
|
<a onClick={onNextStep} className="index-link index-getStarted">
|
||||||
|
Let’s get started <ArrowRight></ArrowRight>
|
||||||
|
</a>
|
||||||
|
</SimpleText>
|
||||||
|
|
||||||
|
<Modal onClose={onLegalDisclaimerClose} open={modal}>
|
||||||
|
<h1 className="disclaimer-title" style={{ marginTop: 0 }}>
|
||||||
|
Disclaimer
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="disclaimer-text">
|
||||||
|
The website and the content herein is not intended for public use
|
||||||
|
and is for informational and demonstration purposes only.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<p className="disclaimer-text">
|
||||||
|
The website and any associated functionalities are provided on an
|
||||||
|
“as is” basis without any guarantees, warranties, or representations
|
||||||
|
of any kind, either express or implied. The website and any
|
||||||
|
associated functionalities may not reflect the final version of the
|
||||||
|
project and is subject to changes, updates, or removal at any time
|
||||||
|
and without notice.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<p className="disclaimer-text">
|
||||||
|
By accessing and using this website, you agree that we, Logos
|
||||||
|
Collective Association and its affiliates, will not be liable for
|
||||||
|
any direct, indirect, incidental, or consequential damages arising
|
||||||
|
from the use of, or inability to use, this website. Any data,
|
||||||
|
content, or interactions on this site are non-binding and should not
|
||||||
|
be considered final or actionable. Your use of this website is at
|
||||||
|
your sole risk.
|
||||||
|
</p>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
37
src/components/OnBoarding/OnBoardingStepThree.css
Normal file
37
src/components/OnBoarding/OnBoardingStepThree.css
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
.onboarding-check {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-check-icon--valid {
|
||||||
|
color: var(--codex-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-check-icon--invalid {
|
||||||
|
color: rgb(var(--codex-color-error));
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-check-line {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-check-refresh {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-check-refresh--fetching {
|
||||||
|
animation: rotateAnimation 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg); /* Start at 0 degrees */
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg); /* End at 360 degrees */
|
||||||
|
}
|
||||||
|
}
|
114
src/components/OnBoarding/OnBoardingStepThree.tsx
Normal file
114
src/components/OnBoarding/OnBoardingStepThree.tsx
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import { CheckIcon, RefreshCcw, X } from "lucide-react";
|
||||||
|
import { classnames } from "../../utils/classnames";
|
||||||
|
import "./OnBoardingStepThree.css";
|
||||||
|
import { usePortForwarding } from "../../hooks/usePortForwarding";
|
||||||
|
import { useCodexConnection } from "../../hooks/useCodexConnection";
|
||||||
|
import { SimpleText } from "@codex-storage/marketplace-ui-components";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
online: boolean;
|
||||||
|
onStepValid: (valid: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function OnBoardingStepThree({ online, onStepValid }: Props) {
|
||||||
|
const portForwarding = usePortForwarding(online);
|
||||||
|
const codex = useCodexConnection();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onStepValid(online && portForwarding.enabled && codex.enabled);
|
||||||
|
}, [portForwarding.enabled, codex.enabled, onStepValid, online]);
|
||||||
|
|
||||||
|
const InternetIcon = online ? CheckIcon : X;
|
||||||
|
const PortForWarningIcon = portForwarding.enabled ? CheckIcon : X;
|
||||||
|
const CodexIcon = codex.enabled ? CheckIcon : X;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="index-column-section">
|
||||||
|
<div
|
||||||
|
className={classnames(
|
||||||
|
["onboarding-check"],
|
||||||
|
["onboarding-check--valid", online]
|
||||||
|
)}>
|
||||||
|
<InternetIcon
|
||||||
|
className={classnames(
|
||||||
|
["onboarding-check-icon--valid", online],
|
||||||
|
["onboarding-check-icon--invalid", !online]
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<p>Internet connection</p>
|
||||||
|
<SimpleText variant="light">
|
||||||
|
Status indicator for the Internet.
|
||||||
|
</SimpleText>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classnames(
|
||||||
|
["onboarding-check"],
|
||||||
|
["onboarding-check--valid", portForwarding.enabled]
|
||||||
|
)}>
|
||||||
|
<PortForWarningIcon
|
||||||
|
className={classnames(
|
||||||
|
["onboarding-check-icon--valid", portForwarding.enabled],
|
||||||
|
["onboarding-check-icon--invalid", !portForwarding.enabled]
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="onboarding-check-line">
|
||||||
|
<div>
|
||||||
|
<p>Port forwarding</p>
|
||||||
|
<SimpleText variant="light">
|
||||||
|
Status indicator for port forwarding activation.
|
||||||
|
</SimpleText>
|
||||||
|
</div>
|
||||||
|
{!portForwarding.enabled && (
|
||||||
|
<a
|
||||||
|
className="onboarding-check-refresh"
|
||||||
|
onClick={() => portForwarding.refetch()}>
|
||||||
|
<RefreshCcw
|
||||||
|
size={"1.25rem"}
|
||||||
|
className={classnames([
|
||||||
|
"onboarding-check-refresh--fetching",
|
||||||
|
portForwarding.isFetching,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classnames(
|
||||||
|
["onboarding-check"],
|
||||||
|
["onboarding-check--valid", codex.enabled]
|
||||||
|
)}>
|
||||||
|
<CodexIcon
|
||||||
|
className={classnames(
|
||||||
|
["onboarding-check-icon--valid", codex.enabled],
|
||||||
|
["onboarding-check-icon--invalid", !codex.enabled]
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="onboarding-check-line">
|
||||||
|
<div>
|
||||||
|
<p>Codex connection</p>
|
||||||
|
<SimpleText variant="light">
|
||||||
|
Status indicator for the Codex network.
|
||||||
|
</SimpleText>
|
||||||
|
</div>
|
||||||
|
{!codex.enabled && (
|
||||||
|
<a
|
||||||
|
className="onboarding-check-refresh"
|
||||||
|
onClick={() => codex.refetch()}>
|
||||||
|
<RefreshCcw
|
||||||
|
size={"1.25rem"}
|
||||||
|
className={classnames([
|
||||||
|
"onboarding-check-refresh--fetching",
|
||||||
|
codex.isFetching,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
27
src/components/OnBoarding/OnBoardingStepTwo.tsx
Normal file
27
src/components/OnBoarding/OnBoardingStepTwo.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { Input } from "@codex-storage/marketplace-ui-components";
|
||||||
|
import { ChangeEvent, useState } from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
onStepValid: (valid: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function OnBoardingStepTwo({ onStepValid }: Props) {
|
||||||
|
const [displayName, setDisplayName] = useState("");
|
||||||
|
|
||||||
|
const onDisplayNameChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setDisplayName(e.currentTarget.value);
|
||||||
|
onStepValid(!!e.currentTarget.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="index-column-section">
|
||||||
|
<Input
|
||||||
|
onChange={onDisplayNameChange}
|
||||||
|
label="Display name"
|
||||||
|
id="displayName"
|
||||||
|
value={displayName}></Input>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
33
src/hooks/useCodexConnection.tsx
Normal file
33
src/hooks/useCodexConnection.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { CodexSdk } from "../sdk/codex";
|
||||||
|
import { Promises } from "../utils/promises";
|
||||||
|
|
||||||
|
const report = false;
|
||||||
|
|
||||||
|
export function useCodexConnection() {
|
||||||
|
const { data, isError, isFetching, refetch } = useQuery({
|
||||||
|
queryKey: ["spr"],
|
||||||
|
queryFn: async () => {
|
||||||
|
return CodexSdk.node()
|
||||||
|
.spr()
|
||||||
|
.then((data) => Promises.rejectOnError(data, report));
|
||||||
|
},
|
||||||
|
refetchInterval: 5000,
|
||||||
|
|
||||||
|
// No need to retry because we defined a refetch interval
|
||||||
|
retry: false,
|
||||||
|
|
||||||
|
// The client node should be local, so display the cache value while
|
||||||
|
// making a background request looks good.
|
||||||
|
staleTime: 0,
|
||||||
|
|
||||||
|
// Refreshing when focus returns can be useful if a user comes back
|
||||||
|
// to the UI after performing an operation in the terminal.
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
|
||||||
|
// Cache is not useful for the spr endpoint
|
||||||
|
gcTime: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { enabled: !isError && !!data, isFetching, refetch };
|
||||||
|
}
|
31
src/hooks/usePortForwarding.tsx
Normal file
31
src/hooks/usePortForwarding.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { Errors } from "../utils/errors";
|
||||||
|
|
||||||
|
type PortForwardingResponse = { reachable: boolean };
|
||||||
|
|
||||||
|
export function usePortForwarding(online: boolean) {
|
||||||
|
const { data, isFetching, refetch } = useQuery({
|
||||||
|
queryFn: (): Promise<PortForwardingResponse> =>
|
||||||
|
fetch(import.meta.env.VITE_ECHO_URL + "/port/8070")
|
||||||
|
.then((res) => res.json())
|
||||||
|
.catch((e) => Errors.report(e)),
|
||||||
|
queryKey: ["port-forwarding"],
|
||||||
|
|
||||||
|
initialData: { reachable: false },
|
||||||
|
|
||||||
|
// Enable only when the use has an internet connection
|
||||||
|
enabled: !!online,
|
||||||
|
|
||||||
|
// No need to retry because we provide a retry button
|
||||||
|
retry: false,
|
||||||
|
|
||||||
|
// The data should not be cached
|
||||||
|
staleTime: 0,
|
||||||
|
|
||||||
|
// The user may try to change the port forwarding and go back
|
||||||
|
// to the tab
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { enabled: data.reachable, isFetching, refetch };
|
||||||
|
}
|
@ -52,7 +52,22 @@
|
|||||||
font-size: var(--codex-font-size);
|
font-size: var(--codex-font-size);
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
color: var(--codex-color);
|
color: var(--codex-color);
|
||||||
background: linear-gradient(246.02deg, #000000 30.36%, #222222 91.05%);
|
background: #000000; /* Fallback color */
|
||||||
|
background: -webkit-linear-gradient(
|
||||||
|
246.02deg,
|
||||||
|
#000000 30.36%,
|
||||||
|
#222222 91.05%
|
||||||
|
); /* For Safari and older Chrome */
|
||||||
|
background: -moz-linear-gradient(
|
||||||
|
246.02deg,
|
||||||
|
#000000 30.36%,
|
||||||
|
#222222 91.05%
|
||||||
|
); /* For older Firefox */
|
||||||
|
background: linear-gradient(
|
||||||
|
246.02deg,
|
||||||
|
#000000 30.36%,
|
||||||
|
#222222 91.05%
|
||||||
|
); /* Standard syntax */
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
@ -140,6 +155,12 @@ pre {
|
|||||||
a {
|
a {
|
||||||
text-decoration: inherit;
|
text-decoration: inherit;
|
||||||
color: var(--codex-color);
|
color: var(--codex-color);
|
||||||
|
transition: opacity 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[aria-disabled] {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
filter: brightness(1);
|
filter: brightness(1);
|
||||||
-webkit-filter: brightness(1);
|
-webkit-filter: brightness(1);
|
||||||
}
|
}
|
||||||
50% {
|
30% {
|
||||||
filter: brightness(0.7);
|
filter: brightness(0.7);
|
||||||
-webkit-filter: brightness(0.7);
|
-webkit-filter: brightness(0.7);
|
||||||
}
|
}
|
||||||
@ -167,7 +167,6 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transition: opacity 0.35s;
|
transition: opacity 0.35s;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.index-dot:not(.index-dot--active) {
|
.index-dot:not(.index-dot--active) {
|
||||||
@ -175,10 +174,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.index-dot:hover {
|
.index-dot:hover {
|
||||||
opacity: 0.8;
|
animation-name: pulse;
|
||||||
|
animation-duration: 2.5s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.index-dot--active {
|
.index-dot--active {
|
||||||
box-shadow: 0px 0px 13px 2px #fff;
|
box-shadow: 0px 0px 12px 0px #fff;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import { AlphaIcon } from "../components/AlphaIcon/AlphaIcon";
|
|
||||||
import { AlphaText } from "../components/AlphaText/AlphaText";
|
|
||||||
import { SimpleText } from "@codex-storage/marketplace-ui-components";
|
|
||||||
import { ArrowRight } from "lucide-react";
|
|
||||||
import { CodexLogo } from "../components/CodexLogo/CodexLogo";
|
|
||||||
import { ArrowRightCircle } from "../components/ArrowRightCircle/ArrowRightCircle";
|
import { ArrowRightCircle } from "../components/ArrowRightCircle/ArrowRightCircle";
|
||||||
import { useNetwork } from "../network/useNetwork";
|
import { useNetwork } from "../network/useNetwork";
|
||||||
import { NetworkIcon } from "../components/NetworkIcon/NetworkIcon";
|
import { NetworkIcon } from "../components/NetworkIcon/NetworkIcon";
|
||||||
import { Logotype } from "../components/Logotype/Logotype";
|
import { Logotype } from "../components/Logotype/Logotype";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { OnBoardingStepOne } from "../components/OnBoarding/OnBoardingStepOne";
|
||||||
|
import { OnBoardingStepTwo } from "../components/OnBoarding/OnBoardingStepTwo";
|
||||||
|
import { classnames } from "../utils/classnames";
|
||||||
|
import { OnBoardingStepThree } from "../components/OnBoarding/OnBoardingStepThree";
|
||||||
|
import { attributes } from "../utils/attributes";
|
||||||
|
import { CodexLogo } from "../components/CodexLogo/CodexLogo";
|
||||||
|
|
||||||
export const Route = createFileRoute("/")({
|
export const Route = createFileRoute("/")({
|
||||||
component: Index,
|
component: Index,
|
||||||
@ -20,7 +22,31 @@ export const Route = createFileRoute("/")({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function Index() {
|
function Index() {
|
||||||
|
const [isStepValid, setIsStepValid] = useState(true);
|
||||||
|
const [step, setStep] = useState(0);
|
||||||
const online = useNetwork();
|
const online = useNetwork();
|
||||||
|
const navigate = useNavigate({ from: "/" });
|
||||||
|
const onStepValid = (valid: boolean) => setIsStepValid(valid);
|
||||||
|
|
||||||
|
const onNextStep = () => {
|
||||||
|
if (!isStepValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step === 2) {
|
||||||
|
navigate({ to: "/dashboard" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setStep(step + 1);
|
||||||
|
setIsStepValid(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const components = [
|
||||||
|
<OnBoardingStepOne onNextStep={onNextStep} />,
|
||||||
|
<OnBoardingStepTwo onStepValid={onStepValid} />,
|
||||||
|
<OnBoardingStepThree online={online} onStepValid={onStepValid} />,
|
||||||
|
];
|
||||||
|
|
||||||
const text = online ? "Network connected" : "Network disconnected";
|
const text = online ? "Network connected" : "Network disconnected";
|
||||||
|
|
||||||
@ -32,51 +58,25 @@ function Index() {
|
|||||||
<Logotype />
|
<Logotype />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="index-column-section">
|
{components[step]}
|
||||||
<div>
|
|
||||||
<AlphaIcon />
|
|
||||||
</div>
|
|
||||||
<div className="index-alphaText">
|
|
||||||
<p>
|
|
||||||
<AlphaText></AlphaText>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<SimpleText className="index-version" variant="normal">
|
|
||||||
{import.meta.env.PACKAGE_VERSION}
|
|
||||||
</SimpleText>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<SimpleText className="index-disclaimer" variant="error">
|
|
||||||
<a className="index-link">Legal Disclaimer</a>
|
|
||||||
</SimpleText>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="index-column-section">
|
|
||||||
<h3 className="index-mainTitle">
|
|
||||||
Hello,
|
|
||||||
<br /> Welcome to <span className="index-codex">Codex</span>{" "}
|
|
||||||
<span className="index-vault">Vault</span>
|
|
||||||
</h3>
|
|
||||||
<p className="index-description">
|
|
||||||
<SimpleText variant="light">
|
|
||||||
Codex is a durable, decentralised data storage protocol, created
|
|
||||||
so the world community can preserve its most important knowledge
|
|
||||||
without risk of censorship.
|
|
||||||
</SimpleText>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="index-column-section ">
|
|
||||||
<SimpleText variant="primary">
|
|
||||||
<a href="/dashboard" className="index-link index-getStarted">
|
|
||||||
Let’s get started <ArrowRight></ArrowRight>
|
|
||||||
</a>
|
|
||||||
</SimpleText>
|
|
||||||
|
|
||||||
|
<div className=" ">
|
||||||
<div className="index-dots">
|
<div className="index-dots">
|
||||||
<span className="index-dot index-dot--active"></span>
|
<span
|
||||||
<span className="index-dot"></span>
|
className={classnames(
|
||||||
<span className="index-dot"></span>
|
["index-dot"],
|
||||||
|
["index-dot--active", step === 0]
|
||||||
|
)}></span>
|
||||||
|
<span
|
||||||
|
className={classnames(
|
||||||
|
["index-dot"],
|
||||||
|
["index-dot--active", step === 1]
|
||||||
|
)}></span>
|
||||||
|
<span
|
||||||
|
className={classnames(
|
||||||
|
["index-dot"],
|
||||||
|
["index-dot--active", step === 2]
|
||||||
|
)}></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -88,7 +88,10 @@ function Index() {
|
|||||||
</div>
|
</div>
|
||||||
<CodexLogo></CodexLogo>
|
<CodexLogo></CodexLogo>
|
||||||
</div>
|
</div>
|
||||||
<a href="/dashboard" className="index-link2">
|
<a
|
||||||
|
className="index-link2"
|
||||||
|
{...attributes({ "aria-disabled": !isStepValid })}
|
||||||
|
onClick={onNextStep}>
|
||||||
<ArrowRightCircle></ArrowRightCircle>
|
<ArrowRightCircle></ArrowRightCircle>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,23 +1,6 @@
|
|||||||
import * as Sentry from "@sentry/browser";
|
import * as Sentry from "@sentry/browser";
|
||||||
import { isCodexOnline } from "../components/NodeIndicator/NodeIndicator";
|
|
||||||
import { CodexError } from "@codex-storage/sdk-js";
|
import { CodexError } from "@codex-storage/sdk-js";
|
||||||
|
|
||||||
// It would be preferable to completely ignore the error
|
|
||||||
// when the node is not connected. However, during the
|
|
||||||
// initial load, we lack this information until the
|
|
||||||
// SPR response is completed. In the meantime, other
|
|
||||||
// requests may be initiated, so if the node is not
|
|
||||||
// connected, we should set the level to 'log'.
|
|
||||||
const getLogLevel = () => {
|
|
||||||
switch (isCodexOnline) {
|
|
||||||
case true:
|
|
||||||
return "error";
|
|
||||||
case null:
|
|
||||||
return "info";
|
|
||||||
case false:
|
|
||||||
return "log";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Errors = {
|
export const Errors = {
|
||||||
report(safe: { error: true, data: CodexError }) {
|
report(safe: { error: true, data: CodexError }) {
|
||||||
@ -26,7 +9,6 @@ export const Errors = {
|
|||||||
code: safe.data.code,
|
code: safe.data.code,
|
||||||
errors: safe.data.errors,
|
errors: safe.data.errors,
|
||||||
sourceStack: safe.data.sourceStack,
|
sourceStack: safe.data.sourceStack,
|
||||||
level: getLogLevel(),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
1
src/vite-env.d.ts
vendored
1
src/vite-env.d.ts
vendored
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
VITE_CODEX_API_URL: string;
|
VITE_CODEX_API_URL: string;
|
||||||
|
VITE_ECHO_URL: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user