mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-29 16:07:40 +01:00
First two pages of register flow
Co-authored-by: William Oldham <github@binaryoverload.co.uk>
This commit is contained in:
parent
7f474af657
commit
a25b3dee54
7 changed files with 195 additions and 51 deletions
|
@ -50,6 +50,7 @@ export enum Icons {
|
|||
IOS_FILES = "ios_files",
|
||||
WAND = "wand",
|
||||
COPY = "copy",
|
||||
USER = "user",
|
||||
}
|
||||
|
||||
export interface IconProps {
|
||||
|
@ -107,6 +108,7 @@ const iconList: Record<Icons, string> = {
|
|||
ios_files: `<svg width="1em" height="1em" viewBox="0 0 24 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.22405 20H21.024C22.9178 20 24 18.8772 24 16.7018V5.33333C24 3.1462 22.9065 2.03509 20.776 2.03509H10.5063C9.72851 2.03509 9.30014 1.85965 8.74777 1.36842L8.12776 0.818713C7.41757 0.187135 6.91029 0 5.85063 0H2.81822C1.01456 0 0 1.04094 0 3.1462V16.7018C0 18.8889 1.0822 20 3.22405 20ZM1.47675 3.22807C1.47675 2.08187 2.04039 1.50877 3.11132 1.50877H5.47863C6.23391 1.50877 6.65101 1.68421 7.21466 2.19883L7.84594 2.74854C8.52231 3.35673 9.06341 3.55556 10.1343 3.55556H20.7534C21.8807 3.55556 22.5233 4.18713 22.5233 5.4152V6.17544H1.47675V3.22807ZM3.24659 18.4795C2.09676 18.4795 1.47675 17.848 1.47675 16.6199V7.61403H22.5233V16.6316C22.5233 17.848 21.8807 18.4795 20.7534 18.4795H3.24659Z" fill="white"/></svg>`,
|
||||
wand: `<svg width="1em" height="1em" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.33437 4.33438L8.15625 4.775C8.0625 4.80937 8 4.9 8 5C8 5.1 8.0625 5.19062 8.15625 5.225L9.33437 5.66563L9.775 6.84375C9.80938 6.9375 9.9 7 10 7C10.1 7 10.1906 6.9375 10.225 6.84375L10.6656 5.66563L11.8438 5.225C11.9375 5.19062 12 5.1 12 5C12 4.9 11.9375 4.80937 11.8438 4.775L10.6656 4.33438L10.225 3.15625C10.1906 3.0625 10.1 3 10 3C9.9 3 9.80938 3.0625 9.775 3.15625L9.33437 4.33438ZM3.44062 15.3562C2.85625 15.9406 2.85625 16.8906 3.44062 17.4781L4.52187 18.5594C5.10625 19.1437 6.05625 19.1437 6.64375 18.5594L18.5594 6.64062C19.1438 6.05625 19.1438 5.10625 18.5594 4.51875L17.4781 3.44063C16.8937 2.85625 15.9437 2.85625 15.3562 3.44063L3.44062 15.3562ZM17.1438 5.58125L13.8625 8.8625L13.1344 8.13438L16.4156 4.85312L17.1438 5.58125ZM2.23438 6.6625C2.09375 6.71562 2 6.85 2 7C2 7.15 2.09375 7.28438 2.23438 7.3375L4 8L4.6625 9.76562C4.71562 9.90625 4.85 10 5 10C5.15 10 5.28438 9.90625 5.3375 9.76562L6 8L7.76562 7.3375C7.90625 7.28438 8 7.15 8 7C8 6.85 7.90625 6.71562 7.76562 6.6625L6 6L5.3375 4.23438C5.28438 4.09375 5.15 4 5 4C4.85 4 4.71562 4.09375 4.6625 4.23438L4 6L2.23438 6.6625ZM13.2344 14.6625C13.0938 14.7156 13 14.85 13 15C13 15.15 13.0938 15.2844 13.2344 15.3375L15 16L15.6625 17.7656C15.7156 17.9062 15.85 18 16 18C16.15 18 16.2844 17.9062 16.3375 17.7656L17 16L18.7656 15.3375C18.9062 15.2844 19 15.15 19 15C19 14.85 18.9062 14.7156 18.7656 14.6625L17 14L16.3375 12.2344C16.2844 12.0938 16.15 12 16 12C15.85 12 15.7156 12.0938 15.6625 12.2344L15 14L13.2344 14.6625Z" fill="currentColor"/></svg>`,
|
||||
copy: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-copy"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`,
|
||||
user: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>`,
|
||||
};
|
||||
|
||||
function ChromeCastButton() {
|
||||
|
|
50
src/components/PassphraseDisplay.tsx
Normal file
50
src/components/PassphraseDisplay.tsx
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { useRef, useState } from "react";
|
||||
import { useCopyToClipboard } from "react-use";
|
||||
|
||||
import { Icon, Icons } from "./Icon";
|
||||
|
||||
export function PassphaseDisplay(props: { mnemonic: string }) {
|
||||
const individualWords = props.mnemonic.split(" ");
|
||||
|
||||
const [_, copy] = useCopyToClipboard();
|
||||
|
||||
const [hasCopied, setHasCopied] = useState(false);
|
||||
|
||||
const timeout = useRef<ReturnType<typeof setTimeout>>();
|
||||
|
||||
function copyMnemonic() {
|
||||
copy(props.mnemonic);
|
||||
setHasCopied(true);
|
||||
if (timeout.current) clearTimeout(timeout.current);
|
||||
timeout.current = setTimeout(() => setHasCopied(false), 500);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-authentication-border/50 ">
|
||||
<div className="px-4 py-2 flex justify-between border-b border-authentication-border/50">
|
||||
<p className="font-bold text-sm text-white">Passphase</p>
|
||||
<button
|
||||
type="button"
|
||||
className="text-authentication-copyText hover:text-authentication-copyTextHover transition-colors flex gap-2 items-center cursor-pointer"
|
||||
onClick={() => copyMnemonic()}
|
||||
>
|
||||
<Icon
|
||||
icon={hasCopied ? Icons.CHECKMARK : Icons.COPY}
|
||||
className={hasCopied ? "text-xs" : ""}
|
||||
/>
|
||||
<span className="text-sm">Copy</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="px-4 py-4 flex flex-wrap gap-x-2 gap-y-4">
|
||||
{individualWords.map((word) => (
|
||||
<div
|
||||
className="px-4 rounded-md py-2 bg-authentication-wordBackground text-white font-medium"
|
||||
key={word}
|
||||
>
|
||||
{word}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
37
src/components/layout/LargeCard.tsx
Normal file
37
src/components/layout/LargeCard.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
export function LargeCard(props: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="rounded-xl bg-largeCard-background bg-opacity-50 max-w-[600px] mx-auto p-[3rem]">
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function LargeCardText(props: {
|
||||
title: string;
|
||||
children?: React.ReactNode;
|
||||
icon?: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex flex-col items-center text-center mb-8">
|
||||
<div className="flex flex-col items-center text-center max-w-[318px]">
|
||||
{props.icon ? (
|
||||
<div className="text-2xl mb-4 text-largeCard-icon">{props.icon}</div>
|
||||
) : null}
|
||||
<h2 className="text-xl text-white font-bold">{props.title}</h2>
|
||||
{props.children ? (
|
||||
<div className="text-type-text mt-4">{props.children}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function LargeCardButtons(props: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="flex justify-center mt-8">
|
||||
<div className="mx-auto inline-grid grid-cols-1 gap-3 justify-center items-center">
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -36,7 +36,7 @@ export function SubPageLayout(props: { children: React.ReactNode }) {
|
|||
{/* Main page */}
|
||||
<FooterView>
|
||||
<Navigation doBackground noLightbar />
|
||||
<div className="mt-40">{props.children}</div>
|
||||
<div className="mt-40 relative">{props.children}</div>
|
||||
</FooterView>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,6 +2,13 @@ import { useMemo } from "react";
|
|||
|
||||
import { genMnemonic } from "@/backend/accounts/crypto";
|
||||
import { Button } from "@/components/Button";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import {
|
||||
LargeCard,
|
||||
LargeCardButtons,
|
||||
LargeCardText,
|
||||
} from "@/components/layout/LargeCard";
|
||||
import { PassphaseDisplay } from "@/components/PassphraseDisplay";
|
||||
|
||||
interface PassphraseGeneratePartProps {
|
||||
onNext?: (mnemonic: string) => void;
|
||||
|
@ -11,10 +18,18 @@ export function PassphraseGeneratePart(props: PassphraseGeneratePartProps) {
|
|||
const mnemonic = useMemo(() => genMnemonic(), []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Remeber the following passphrase:</p>
|
||||
<p className="border rounded-xl p-2">{mnemonic}</p>
|
||||
<Button onClick={() => props.onNext?.(mnemonic)}>Next</Button>
|
||||
</div>
|
||||
<LargeCard>
|
||||
<LargeCardText title="Your passphrase" icon={<Icon icon={Icons.USER} />}>
|
||||
If you lose this, you're a silly goose and will be posted on the
|
||||
wall of shame™️
|
||||
</LargeCardText>
|
||||
<PassphaseDisplay mnemonic={mnemonic} />
|
||||
|
||||
<LargeCardButtons>
|
||||
<Button theme="purple" onClick={() => props.onNext?.(mnemonic)}>
|
||||
NEXT!
|
||||
</Button>
|
||||
</LargeCardButtons>
|
||||
</LargeCard>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,12 @@ import { useAsync } from "react-use";
|
|||
|
||||
import { MetaResponse, getBackendMeta } from "@/backend/accounts/meta";
|
||||
import { Button } from "@/components/Button";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import {
|
||||
LargeCard,
|
||||
LargeCardButtons,
|
||||
LargeCardText,
|
||||
} from "@/components/layout/LargeCard";
|
||||
import { conf } from "@/setup/config";
|
||||
|
||||
interface TrustBackendPartProps {
|
||||
|
@ -23,18 +29,37 @@ export function TrustBackendPart(props: TrustBackendPartProps) {
|
|||
return <p>Failed to talk to backend, did you configure it correctly?</p>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
do you trust{" "}
|
||||
<span className="text-white font-bold">{result.value.domain}</span>
|
||||
</p>
|
||||
<div className="border rounded-xl p-4">
|
||||
<p className="text-white font-bold">{result.value.data.name}</p>
|
||||
<LargeCard>
|
||||
<LargeCardText
|
||||
title="Do you trust this host?"
|
||||
icon={<Icon icon={Icons.CIRCLE_EXCLAMATION} />}
|
||||
>
|
||||
Do you trust <span className="text-white">{result.value.domain}</span>?
|
||||
</LargeCardText>
|
||||
|
||||
<div className="border border-authentication-border rounded-xl px-4 py-8 flex flex-col items-center space-y-2 my-8">
|
||||
<h3 className="text-white font-bold text-lg">
|
||||
{result.value.data.name}
|
||||
</h3>
|
||||
{result.value.data.description ? (
|
||||
<p>{result.value.data.description}</p>
|
||||
) : null}
|
||||
</div>
|
||||
<Button onClick={() => props.onNext?.(result.value.data)}>Next</Button>
|
||||
</div>
|
||||
<LargeCardButtons>
|
||||
<Button
|
||||
theme="purple"
|
||||
onClick={() => props.onNext?.(result.value.data)}
|
||||
>
|
||||
I pledge my life to the United States
|
||||
</Button>
|
||||
<Button
|
||||
theme="secondary"
|
||||
// eslint-disable-next-line no-return-assign, no-restricted-globals
|
||||
onClick={() => (location.href = "https://youtu.be/of0O-lS-OqQ")}
|
||||
>
|
||||
I WILL NEVER SUCCUMB!
|
||||
</Button>
|
||||
</LargeCardButtons>
|
||||
</LargeCard>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,23 +26,23 @@ module.exports = {
|
|||
"ash-400": "#3D394D",
|
||||
"ash-300": "#2C293A",
|
||||
"ash-200": "#2B2836",
|
||||
"ash-100": "#1E1C26"
|
||||
"ash-100": "#1E1C26",
|
||||
},
|
||||
|
||||
/* fonts */
|
||||
fontFamily: {
|
||||
"open-sans": "'Open Sans'"
|
||||
"open-sans": "'Open Sans'",
|
||||
},
|
||||
|
||||
/* animations */
|
||||
keyframes: {
|
||||
"loading-pin": {
|
||||
"0%, 40%, 100%": { height: "0.5em", "background-color": "#282336" },
|
||||
"20%": { height: "1em", "background-color": "white" }
|
||||
}
|
||||
"20%": { height: "1em", "background-color": "white" },
|
||||
},
|
||||
},
|
||||
animation: { "loading-pin": "loading-pin 1.8s ease-in-out infinite" }
|
||||
}
|
||||
animation: { "loading-pin": "loading-pin 1.8s ease-in-out infinite" },
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require("tailwind-scrollbar"),
|
||||
|
@ -52,18 +52,18 @@ module.exports = {
|
|||
colors: {
|
||||
// Branding
|
||||
pill: {
|
||||
background: "#1C1C36"
|
||||
background: "#1C1C36",
|
||||
},
|
||||
|
||||
// meta data for the theme itself
|
||||
global: {
|
||||
accentA: "#505DBD",
|
||||
accentB: "#3440A1"
|
||||
accentB: "#3440A1",
|
||||
},
|
||||
|
||||
// light bar
|
||||
lightBar: {
|
||||
light: "#2A2A71"
|
||||
light: "#2A2A71",
|
||||
},
|
||||
|
||||
// Buttons
|
||||
|
@ -71,14 +71,14 @@ module.exports = {
|
|||
toggle: "#8D44D6",
|
||||
toggleDisabled: "#202836",
|
||||
danger: "#792131",
|
||||
dangerHover: "#8a293b"
|
||||
dangerHover: "#8a293b",
|
||||
},
|
||||
|
||||
// only used for body colors/textures
|
||||
background: {
|
||||
main: "#0A0A10",
|
||||
accentA: "#6E3B80",
|
||||
accentB: "#1F1F50"
|
||||
accentB: "#1F1F50",
|
||||
},
|
||||
|
||||
// typography
|
||||
|
@ -87,7 +87,7 @@ module.exports = {
|
|||
text: "#73739D",
|
||||
dimmed: "#926CAD",
|
||||
divider: "#262632",
|
||||
secondary: "#64647B"
|
||||
secondary: "#64647B",
|
||||
},
|
||||
|
||||
// search bar
|
||||
|
@ -96,7 +96,7 @@ module.exports = {
|
|||
focused: "#24243C",
|
||||
placeholder: "#4A4A71",
|
||||
icon: "#545476",
|
||||
text: "#FFFFFF"
|
||||
text: "#FFFFFF",
|
||||
},
|
||||
|
||||
// media cards
|
||||
|
@ -108,9 +108,24 @@ module.exports = {
|
|||
barColor: "#4B4B63",
|
||||
barFillColor: "#BA7FD6",
|
||||
badge: "#151522",
|
||||
badgeText: "#5F5F7A"
|
||||
badgeText: "#5F5F7A",
|
||||
},
|
||||
|
||||
// Large card
|
||||
largeCard: {
|
||||
background: "#171728",
|
||||
icon: "#6741A5",
|
||||
},
|
||||
|
||||
// Passphrase
|
||||
authentication: {
|
||||
border: "#393954",
|
||||
wordBackground: "#171728",
|
||||
copyText: "#58587A",
|
||||
copyTextHover: "#8888AA",
|
||||
},
|
||||
|
||||
// Settings page
|
||||
settings: {
|
||||
sidebar: {
|
||||
activeLink: "#171728",
|
||||
|
@ -120,19 +135,19 @@ module.exports = {
|
|||
inactive: "#8D68A9",
|
||||
icon: "#926CAD",
|
||||
iconActivated: "#6942A8",
|
||||
activated: "#CBA1E8"
|
||||
}
|
||||
activated: "#CBA1E8",
|
||||
},
|
||||
},
|
||||
|
||||
card: {
|
||||
border: "#2A243E",
|
||||
background: "#29243D",
|
||||
altBackground: "#29243D"
|
||||
}
|
||||
altBackground: "#29243D",
|
||||
},
|
||||
},
|
||||
|
||||
utils: {
|
||||
divider: "#353549"
|
||||
divider: "#353549",
|
||||
},
|
||||
|
||||
// Error page
|
||||
|
@ -141,20 +156,20 @@ module.exports = {
|
|||
border: "#252534",
|
||||
|
||||
type: {
|
||||
secondary: "#62627D"
|
||||
}
|
||||
secondary: "#62627D",
|
||||
},
|
||||
},
|
||||
|
||||
// About page
|
||||
about: {
|
||||
circle: "#262632",
|
||||
circleText: "#9A9AC3"
|
||||
circleText: "#9A9AC3",
|
||||
},
|
||||
|
||||
progress: {
|
||||
background: "#8787A8",
|
||||
preloaded: "#8787A8",
|
||||
filled: "#A75FC9"
|
||||
filled: "#A75FC9",
|
||||
},
|
||||
|
||||
// video player
|
||||
|
@ -166,11 +181,11 @@ module.exports = {
|
|||
error: "#E44F4F",
|
||||
success: "#40B44B",
|
||||
loading: "#B759D8",
|
||||
noresult: "#64647B"
|
||||
noresult: "#64647B",
|
||||
},
|
||||
|
||||
audio: {
|
||||
set: "#A75FC9"
|
||||
set: "#A75FC9",
|
||||
},
|
||||
|
||||
buttons: {
|
||||
|
@ -183,7 +198,7 @@ module.exports = {
|
|||
purple: "#6b298a",
|
||||
purpleHover: "#7f35a1",
|
||||
cancel: "#252533",
|
||||
cancelHover: "#3C3C4A"
|
||||
cancelHover: "#3C3C4A",
|
||||
},
|
||||
|
||||
context: {
|
||||
|
@ -203,19 +218,19 @@ module.exports = {
|
|||
|
||||
buttons: {
|
||||
list: "#161C26",
|
||||
active: "#0D1317"
|
||||
active: "#0D1317",
|
||||
},
|
||||
|
||||
type: {
|
||||
main: "#617A8A",
|
||||
secondary: "#374A56",
|
||||
accent: "#A570FA"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
accent: "#A570FA",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue