diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index cb2014e1..227a31c7 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -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 = { ios_files: ``, wand: ``, copy: ``, + user: ``, }; function ChromeCastButton() { diff --git a/src/components/PassphraseDisplay.tsx b/src/components/PassphraseDisplay.tsx new file mode 100644 index 00000000..4a1235d9 --- /dev/null +++ b/src/components/PassphraseDisplay.tsx @@ -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>(); + + function copyMnemonic() { + copy(props.mnemonic); + setHasCopied(true); + if (timeout.current) clearTimeout(timeout.current); + timeout.current = setTimeout(() => setHasCopied(false), 500); + } + + return ( +
+
+

Passphase

+ +
+
+ {individualWords.map((word) => ( +
+ {word} +
+ ))} +
+
+ ); +} diff --git a/src/components/layout/LargeCard.tsx b/src/components/layout/LargeCard.tsx new file mode 100644 index 00000000..1367a85f --- /dev/null +++ b/src/components/layout/LargeCard.tsx @@ -0,0 +1,37 @@ +export function LargeCard(props: { children: React.ReactNode }) { + return ( +
+ {props.children} +
+ ); +} + +export function LargeCardText(props: { + title: string; + children?: React.ReactNode; + icon?: React.ReactNode; +}) { + return ( +
+
+ {props.icon ? ( +
{props.icon}
+ ) : null} +

{props.title}

+ {props.children ? ( +
{props.children}
+ ) : null} +
+
+ ); +} + +export function LargeCardButtons(props: { children: React.ReactNode }) { + return ( +
+
+ {props.children} +
+
+ ); +} diff --git a/src/pages/layouts/SubPageLayout.tsx b/src/pages/layouts/SubPageLayout.tsx index 9e3c66f4..a18cfa7b 100644 --- a/src/pages/layouts/SubPageLayout.tsx +++ b/src/pages/layouts/SubPageLayout.tsx @@ -36,7 +36,7 @@ export function SubPageLayout(props: { children: React.ReactNode }) { {/* Main page */} -
{props.children}
+
{props.children}
); diff --git a/src/pages/parts/auth/PassphraseGeneratePart.tsx b/src/pages/parts/auth/PassphraseGeneratePart.tsx index dcc2c683..40e35cfd 100644 --- a/src/pages/parts/auth/PassphraseGeneratePart.tsx +++ b/src/pages/parts/auth/PassphraseGeneratePart.tsx @@ -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 ( -
-

Remeber the following passphrase:

-

{mnemonic}

- -
+ + }> + If you lose this, you're a silly goose and will be posted on the + wall of shame™️ + + + + + + + ); } diff --git a/src/pages/parts/auth/TrustBackendPart.tsx b/src/pages/parts/auth/TrustBackendPart.tsx index 1726905d..62c7888b 100644 --- a/src/pages/parts/auth/TrustBackendPart.tsx +++ b/src/pages/parts/auth/TrustBackendPart.tsx @@ -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

Failed to talk to backend, did you configure it correctly?

; return ( -
-

- do you trust{" "} - {result.value.domain} -

-
-

{result.value.data.name}

+ + } + > + Do you trust {result.value.domain}? + + +
+

+ {result.value.data.name} +

{result.value.data.description ? (

{result.value.data.description}

) : null}
- -
+ + + + + ); } diff --git a/tailwind.config.js b/tailwind.config.js index ef997936..883d49a3 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -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", + }, + }, + }, + }, + }, + }, + }), + ], };