feat: update onboarding ui
This commit is contained in:
@@ -1,20 +1,47 @@
|
||||
import { useState } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { Helmet } from "react-helmet";
|
||||
import WelcomeStep from "./steps/1-welcome";
|
||||
import ServerNameStep from "./steps/2-serverName";
|
||||
import AdminCredentialsStep from "./steps/3-adminCredentials";
|
||||
import WhoCanInviteStep from "./steps/4-whoCanInvite";
|
||||
import InviteLinkStep from "./steps/5-inviteLink";
|
||||
import CompletedStep from "./steps/6-completed";
|
||||
import WelcomePage from "./steps/welcomePage";
|
||||
import ServerName from "./steps/serverName";
|
||||
import AdminAccount from "./steps/adminAccount";
|
||||
import WhoCanSignUp from "./steps/whoCanSignUp";
|
||||
import InviteLink from "./steps/inviteLink";
|
||||
import DonePage from "./steps/donePage";
|
||||
import useServerSetup, { steps } from "./useServerSetup";
|
||||
import StyledOnboardingPage from "./styled";
|
||||
|
||||
function Navigator({ step, setStep }) {
|
||||
const index = steps.map((value) => value.name).indexOf(step);
|
||||
const canJumpTo = steps.find((value) => value.name === step).canJumpTo || [];
|
||||
|
||||
return (
|
||||
<div className="navigator">
|
||||
{steps.map((stepToRender, indexToRender) => {
|
||||
const clickable = canJumpTo.includes(stepToRender.name);
|
||||
const nodeCls = `node ${indexToRender === index ? "emphasized" : ""} ${
|
||||
indexToRender > index ? "disabled" : ""
|
||||
} ${clickable ? "clickable" : ""}`;
|
||||
const arrowCls = `arrow ${indexToRender >= index ? "disabled" : ""}`;
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
className={nodeCls}
|
||||
onClick={() => {
|
||||
if (clickable) {
|
||||
setStep(stepToRender.name);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{stepToRender.label}
|
||||
</span>
|
||||
{indexToRender !== steps.length - 1 && <span className={arrowCls}>→</span>}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function OnboardingPage() {
|
||||
const [step, setStep] = useState(0);
|
||||
const [data, setData] = useState({
|
||||
serverName: ""
|
||||
});
|
||||
const props = { setStep, data, setData };
|
||||
const serverSetup = useServerSetup();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -22,13 +49,13 @@ export default function OnboardingPage() {
|
||||
<title>Rustchat Setup</title>
|
||||
</Helmet>
|
||||
<StyledOnboardingPage>
|
||||
{step === 0 && <WelcomeStep {...props} />}
|
||||
{step === 1 && <ServerNameStep {...props} />}
|
||||
{step === 2 && <AdminCredentialsStep {...props} />}
|
||||
{step === 3 && <WhoCanInviteStep {...props} />}
|
||||
{step === 4 && <InviteLinkStep {...props} />}
|
||||
{step === 5 && <CompletedStep {...props} />}
|
||||
{step === 6 && <Navigate replace to="/" />}
|
||||
<Navigator {...serverSetup} />
|
||||
{serverSetup.step === "welcomePage" && <WelcomePage {...serverSetup} />}
|
||||
{serverSetup.step === "serverName" && <ServerName {...serverSetup} />}
|
||||
{serverSetup.step === "adminAccount" && <AdminAccount {...serverSetup} />}
|
||||
{serverSetup.step === "whoCanSignUp" && <WhoCanSignUp {...serverSetup} />}
|
||||
{serverSetup.step === "inviteLink" && <InviteLink {...serverSetup} />}
|
||||
{serverSetup.step === "donePage" && <DonePage {...serverSetup} />}
|
||||
</StyledOnboardingPage>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
import StyledButton from "../../../common/component/styled/Button";
|
||||
import PlayIcon from "../../../assets/icons/play.svg?url";
|
||||
|
||||
const StyledFirstStep = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export default function WelcomeStep({ setStep }) {
|
||||
return (
|
||||
<StyledFirstStep>
|
||||
<span className="primaryText">Welcome to your Rustchat!</span>
|
||||
<span className="secondaryText">
|
||||
Everything in this space is owned by you. Let’s set up your space!
|
||||
</span>
|
||||
<StyledButton className="startButton" onClick={() => setStep((prev) => prev + 1)}>
|
||||
<img src={PlayIcon} alt="play icon" />
|
||||
<span>Start</span>
|
||||
</StyledButton>
|
||||
</StyledFirstStep>
|
||||
);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
import StyledButton from "../../../common/component/styled/Button";
|
||||
import PlayIcon from "../../../assets/icons/play.svg?url";
|
||||
|
||||
const StyledLastStep = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> .secondaryText {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
> .tip {
|
||||
width: 560px;
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
margin-bottom: 96px;
|
||||
|
||||
> .strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function CompletedStep({ data, setStep }) {
|
||||
return (
|
||||
<StyledLastStep>
|
||||
<span className="primaryText">Welcome to {data.serverName}</span>
|
||||
<span className="secondaryText">Proudly presented by Rustchat</span>
|
||||
<span className="tip">
|
||||
More settings, including domain resolution, privileges, securities, and invites are
|
||||
available in <span className="strong">Settings</span>
|
||||
</span>
|
||||
<StyledButton className="startButton" onClick={() => setStep((prev) => prev + 1)}>
|
||||
<img src={PlayIcon} alt="play icon" />
|
||||
<span>Enter</span>
|
||||
</StyledButton>
|
||||
</StyledLastStep>
|
||||
);
|
||||
}
|
||||
+35
-8
@@ -12,23 +12,50 @@ import {
|
||||
import { useLoginMutation } from "../../../app/services/auth";
|
||||
import { updateInitialized } from "../../../app/slices/auth.data";
|
||||
|
||||
const StyledAdminCredentialsStep = styled.div`
|
||||
const StyledWrapper = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> .input:not(:nth-last-child(2)) {
|
||||
margin-bottom: 20px;
|
||||
> .primaryText {
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> .secondaryText {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
> .input {
|
||||
width: 360px;
|
||||
height: 44px;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
border: 1px solid #d0d5dd;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
|
||||
|
||||
&:not(:nth-last-child(2)) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
> .button {
|
||||
width: 360px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function AdminCredentialsStep({ data, setStep }) {
|
||||
export default function AdminAccount({ serverName, nextStep }) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [createAdmin, { isLoading: isSigningUp, error: signUpError }] = useCreateAdminMutation();
|
||||
@@ -60,7 +87,7 @@ export default function AdminCredentialsStep({ data, setStep }) {
|
||||
// Set server name
|
||||
updateServer({
|
||||
...serverData,
|
||||
name: data.serverName
|
||||
name: serverName
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
@@ -69,12 +96,12 @@ export default function AdminCredentialsStep({ data, setStep }) {
|
||||
// After updated server
|
||||
useEffect(() => {
|
||||
if (isUpdatedServer) {
|
||||
setStep((prev) => prev + 1);
|
||||
nextStep();
|
||||
}
|
||||
}, [isUpdatedServer]);
|
||||
|
||||
return (
|
||||
<StyledAdminCredentialsStep>
|
||||
<StyledWrapper>
|
||||
<span className="primaryText">Now let’s set up your admin account</span>
|
||||
<span className="secondaryText">You are the 1st user and admin of your space!</span>
|
||||
<StyledInput
|
||||
@@ -126,6 +153,6 @@ export default function AdminCredentialsStep({ data, setStep }) {
|
||||
>
|
||||
{!(isSigningUp || isLoggingIn || isUpdatingServer) ? "Sign Up" : "..."}
|
||||
</StyledButton>
|
||||
</StyledAdminCredentialsStep>
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import styled from "styled-components";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import StyledButton from "../../../common/component/styled/Button";
|
||||
import PlayIcon from "../../../assets/icons/play.svg?url";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> .primaryText {
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> .secondaryText {
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
> .tip {
|
||||
width: 588px;
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
margin-bottom: 48px;
|
||||
|
||||
> .strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
> .startButton {
|
||||
width: 128px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 15px 0 12px;
|
||||
|
||||
> img {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
> span {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function DonePage({ serverName }) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<span className="primaryText">Welcome to {serverName}</span>
|
||||
<span className="secondaryText">Proudly presented by Rustchat</span>
|
||||
<span className="tip">
|
||||
More settings, including domain resolution, privileges, securities, and invites are
|
||||
available in <span className="strong">Settings</span>
|
||||
</span>
|
||||
<StyledButton className="startButton" onClick={() => navigate("/")}>
|
||||
<img src={PlayIcon} alt="play icon" />
|
||||
<span>Enter</span>
|
||||
</StyledButton>
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
+28
-9
@@ -3,14 +3,25 @@ import StyledInput from "../../../common/component/styled/Input";
|
||||
import StyledButton from "../../../common/component/styled/Button";
|
||||
import useInviteLink from "../../../common/hook/useInviteLink";
|
||||
|
||||
const StyledInviteLinkStep = styled.div`
|
||||
const StyledWrapper = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> .primaryText {
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> .secondaryText {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
@@ -47,15 +58,26 @@ const StyledInviteLinkStep = styled.div`
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #22ccee;
|
||||
transition: color 150ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
color: #088ab2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .button {
|
||||
width: 124px;
|
||||
height: 44px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function InviteLinkStep({ setStep }) {
|
||||
export default function InviteLink({ nextStep }) {
|
||||
const { link, linkCopied, copyLink } = useInviteLink();
|
||||
|
||||
return (
|
||||
<StyledInviteLinkStep>
|
||||
<StyledWrapper>
|
||||
<span className="primaryText">Last step: invite others!</span>
|
||||
<span className="secondaryText">Now let’s invite others!</span>
|
||||
<span className="tip">Send invitation link to your future community members:</span>
|
||||
@@ -65,12 +87,9 @@ export default function InviteLinkStep({ setStep }) {
|
||||
{linkCopied ? "Copied" : `Copy`}
|
||||
</StyledButton>
|
||||
</div>
|
||||
<StyledButton
|
||||
className="button border_less ghost"
|
||||
onClick={() => setStep((prev) => prev + 1)}
|
||||
>
|
||||
Skip
|
||||
<StyledButton className="button" onClick={nextStep}>
|
||||
Done
|
||||
</StyledButton>
|
||||
</StyledInviteLinkStep>
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
+34
-13
@@ -3,25 +3,51 @@ import toast from "react-hot-toast";
|
||||
import StyledInput from "../../../common/component/styled/Input";
|
||||
import StyledButton from "../../../common/component/styled/Button";
|
||||
|
||||
const StyledSpaceNameStep = styled.div`
|
||||
const StyledWrapper = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> .primaryText {
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> .secondaryText {
|
||||
width: 360px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 24px;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
> .input {
|
||||
width: 360px;
|
||||
height: 44px;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid #d0d5dd;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
|
||||
}
|
||||
|
||||
> .button {
|
||||
width: 360px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function ServerNameStep({ setStep, data, setData }) {
|
||||
export default function ServerName({ serverName, setServerName, nextStep }) {
|
||||
return (
|
||||
<StyledSpaceNameStep>
|
||||
<StyledWrapper>
|
||||
<span className="primaryText">Create a new server</span>
|
||||
<span className="secondaryText">
|
||||
Servers are shared environments where teams can work on projects and chat.
|
||||
@@ -29,27 +55,22 @@ export default function ServerNameStep({ setStep, data, setData }) {
|
||||
<StyledInput
|
||||
className="input"
|
||||
placeholder="Enter server name"
|
||||
value={data.serverName}
|
||||
onChange={(e) =>
|
||||
setData({
|
||||
...data,
|
||||
serverName: e.target.value
|
||||
})
|
||||
}
|
||||
value={serverName}
|
||||
onChange={(e) => setServerName(e.target.value)}
|
||||
/>
|
||||
<StyledButton
|
||||
className="button"
|
||||
onClick={() => {
|
||||
// Verification for space name
|
||||
if (data.serverName === "") {
|
||||
if (serverName === "") {
|
||||
toast.error("Please enter server name!");
|
||||
return;
|
||||
}
|
||||
setStep((prev) => prev + 1);
|
||||
nextStep();
|
||||
}}
|
||||
>
|
||||
Create Server
|
||||
</StyledButton>
|
||||
</StyledSpaceNameStep>
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import styled from "styled-components";
|
||||
import StyledButton from "../../../common/component/styled/Button";
|
||||
import PlayIcon from "../../../assets/icons/play.svg?url";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> .primaryText {
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> .secondaryText {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
> .startButton {
|
||||
width: 128px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 15px 0 12px;
|
||||
|
||||
> img {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
> span {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function WelcomePage({ nextStep }) {
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<span className="primaryText">Welcome to your Rustchat!</span>
|
||||
<span className="secondaryText">
|
||||
Everything in this space is owned by you. Let’s set up your space!
|
||||
</span>
|
||||
<StyledButton className="startButton" onClick={nextStep}>
|
||||
<img src={PlayIcon} alt="play icon" />
|
||||
<span>Start</span>
|
||||
</StyledButton>
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
+43
-15
@@ -1,27 +1,55 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import styled from "styled-components";
|
||||
import StyledRadio from "../../../common/component/styled/Radio";
|
||||
import StyledButton from "../../../common/component/styled/Button";
|
||||
import { useGetLoginConfigQuery, useUpdateLoginConfigMutation } from "../../../app/services/server";
|
||||
|
||||
const StyledWhoCanSignUpStep = styled.div`
|
||||
const StyledWrapper = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> .primaryText {
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> .secondaryText {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
> form {
|
||||
width: 512px;
|
||||
}
|
||||
|
||||
> .button {
|
||||
width: 124px;
|
||||
height: 44px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function WhoCanInviteStep({ setStep }) {
|
||||
export default function WhoCanSignUp({ nextStep }) {
|
||||
const { data: loginConfig } = useGetLoginConfigQuery();
|
||||
const [updateLoginConfig, { isSuccess, error }] = useUpdateLoginConfigMutation();
|
||||
|
||||
const [value, setValue] = useState("EveryOne");
|
||||
const [value, setValue] = useState(undefined);
|
||||
|
||||
// Sync to `value` when `loginConfig` is fetched
|
||||
useEffect(() => {
|
||||
if (loginConfig) {
|
||||
setValue(loginConfig.who_can_sign_up);
|
||||
}
|
||||
}, [loginConfig]);
|
||||
|
||||
// Display error
|
||||
useEffect(() => {
|
||||
@@ -31,33 +59,33 @@ export default function WhoCanInviteStep({ setStep }) {
|
||||
|
||||
// Increment `step` when updating has completed
|
||||
useEffect(() => {
|
||||
if (isSuccess) setStep((prev) => prev + 1);
|
||||
if (isSuccess) nextStep();
|
||||
}, [isSuccess]);
|
||||
|
||||
return (
|
||||
<StyledWhoCanSignUpStep>
|
||||
<StyledWrapper>
|
||||
<span className="primaryText">Last step: invite others!</span>
|
||||
<span className="secondaryText">Firstly, who can sign up to this server?</span>
|
||||
<StyledRadio
|
||||
options={["Everyone", "Invitation link only"]}
|
||||
values={["EveryOne", "InvitationOnly"]}
|
||||
value={value}
|
||||
onChange={(v) => {
|
||||
setValue(v);
|
||||
onChange={setValue}
|
||||
/>
|
||||
<StyledButton
|
||||
className="button"
|
||||
disabled={!value}
|
||||
onClick={() => {
|
||||
if (loginConfig !== undefined) {
|
||||
updateLoginConfig({
|
||||
...loginConfig,
|
||||
who_can_sign_up: v
|
||||
who_can_sign_up: value
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<StyledButton
|
||||
className="button border_less ghost"
|
||||
onClick={() => setStep((prev) => prev + 1)}
|
||||
>
|
||||
Skip
|
||||
Confirm
|
||||
</StyledButton>
|
||||
</StyledWhoCanSignUpStep>
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
@@ -4,70 +4,37 @@ const StyledOnboardingPage = styled.div`
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
|
||||
// shared with child components
|
||||
.primaryText,
|
||||
.secondaryText {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.primaryText {
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.secondaryText {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.startButton {
|
||||
width: 128px;
|
||||
> .navigator {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 15px 0 12px;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
|
||||
> img {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
> span {
|
||||
font-weight: 500;
|
||||
> .node,
|
||||
> .arrow {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
line-height: 28px;
|
||||
color: #101828;
|
||||
cursor: default;
|
||||
|
||||
.input {
|
||||
width: 360px;
|
||||
height: 44px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
&.disabled {
|
||||
color: #d0d5dd;
|
||||
}
|
||||
|
||||
input.input {
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid #d0d5dd;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
|
||||
}
|
||||
&.emphasized {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 360px;
|
||||
&.clickable {
|
||||
cursor: pointer;
|
||||
|
||||
&.ghost.border_less {
|
||||
width: fit-content;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
color: #98a2b3;
|
||||
margin-top: 14px;
|
||||
&:hover {
|
||||
color: #717180;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
// `name` for in-code usage, `label` for display
|
||||
const steps = [
|
||||
{
|
||||
name: "welcomePage",
|
||||
label: "Welcome Page"
|
||||
},
|
||||
{
|
||||
name: "serverName",
|
||||
label: "Set Name"
|
||||
},
|
||||
{
|
||||
name: "adminAccount",
|
||||
label: "Admin Account"
|
||||
},
|
||||
{
|
||||
name: "whoCanSignUp",
|
||||
label: "Who Can Sign Up"
|
||||
},
|
||||
{
|
||||
name: "inviteLink",
|
||||
label: "Invites",
|
||||
canJumpTo: ["whoCanSignUp"]
|
||||
},
|
||||
{
|
||||
name: "donePage",
|
||||
label: "Done",
|
||||
canJumpTo: ["whoCanSignUp", "inviteLink"]
|
||||
}
|
||||
];
|
||||
|
||||
export default function useServerSetup() {
|
||||
const [index, setIndex] = useState(0);
|
||||
const step = steps[index].name;
|
||||
const setStep = useCallback((name) => {
|
||||
setIndex(steps.map((step) => step.name).indexOf(name));
|
||||
}, []);
|
||||
const nextStep = useCallback(() => {
|
||||
setIndex((prev) => prev + 1);
|
||||
}, []);
|
||||
|
||||
const [serverName, setServerName] = useState("");
|
||||
|
||||
return {
|
||||
step,
|
||||
setStep,
|
||||
nextStep,
|
||||
serverName,
|
||||
setServerName
|
||||
};
|
||||
}
|
||||
|
||||
export { steps };
|
||||
Reference in New Issue
Block a user