From 061c944034e8346ef38081af0ced1aa6d6efd282 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sat, 18 Nov 2023 15:12:31 +0100 Subject: [PATCH] finish register and login flow + suspense fallback fix Co-authored-by: Jip Frijlink --- src/components/Avatar.tsx | 10 +- src/components/Button.tsx | 35 ++++--- src/components/UserIcon.tsx | 35 +++++++ src/components/form/ColorPicker.tsx | 39 ++++++++ src/components/form/IconPicker.tsx | 47 +++++++++ src/components/layout/LargeCard.tsx | 2 +- .../player/atoms/NextEpisodeButton.tsx | 4 +- src/hooks/auth/useAuthRestore.ts | 10 +- src/index.tsx | 17 +++- src/pages/Register.tsx | 7 +- src/pages/parts/auth/AccountCreatePart.tsx | 31 ++++-- src/pages/parts/auth/LoginFormPart.tsx | 8 +- src/pages/parts/auth/VerifyPassphrasePart.tsx | 10 +- tailwind.config.js | 96 +++++++++---------- 14 files changed, 251 insertions(+), 100 deletions(-) create mode 100644 src/components/UserIcon.tsx create mode 100644 src/components/form/ColorPicker.tsx create mode 100644 src/components/form/IconPicker.tsx diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index e05ebb6a..61ad5cf7 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -1,4 +1,4 @@ -import { Icon, Icons } from "@/components/Icon"; +import { UserIcon } from "@/components/UserIcon"; import { AccountProfile } from "@/pages/parts/auth/AccountCreatePart"; import { useAuthStore } from "@/stores/auth"; @@ -6,13 +6,7 @@ export interface AvatarProps { profile: AccountProfile["profile"]; } -const possibleIcons = ["bookmark"] as const; -const avatarIconMap: Record<(typeof possibleIcons)[number], Icons> = { - bookmark: Icons.BOOKMARK, -}; - export function Avatar(props: AvatarProps) { - const icon = (avatarIconMap as any)[props.profile.icon] ?? Icons.X; return (
- +
); } diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 5237806b..07417aff 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,8 +1,9 @@ import classNames from "classnames"; -import { ReactNode } from "react"; +import { ReactNode, useCallback } from "react"; import { useHistory } from "react-router-dom"; import { Icon, Icons } from "@/components/Icon"; +import { Spinner } from "@/components/layout/Spinner"; interface Props { icon?: Icons; @@ -14,18 +15,24 @@ interface Props { href?: string; disabled?: boolean; download?: string; + loading?: boolean; } export function Button(props: Props) { const history = useHistory(); + const { onClick, href, loading } = props; + const cb = useCallback(() => { + if (loading) return; + if (href) history.push(href); + else onClick?.(); + }, [onClick, href, history, loading]); let colorClasses = "bg-white hover:bg-gray-200 text-black"; if (props.theme === "purple") - colorClasses = - "bg-video-buttons-purple hover:bg-video-buttons-purpleHover text-white"; + colorClasses = "bg-buttons-purple hover:bg-buttons-purpleHover text-white"; if (props.theme === "secondary") colorClasses = - "bg-video-buttons-cancel hover:bg-video-buttons-cancelHover transition-colors duration-100 text-white"; + "bg-buttons-cancel hover:bg-buttons-cancelHover transition-colors duration-100 text-white"; if (props.theme === "danger") colorClasses = "bg-buttons-danger hover:bg-buttons-dangerHover text-white"; @@ -48,19 +55,20 @@ export function Button(props: Props) { const content = ( <> - {props.icon ? ( + {props.icon && !props.loading ? ( ) : null} + {props.loading ? ( + + + + ) : null} {props.children} ); - function goTo(href: string) { - history.push(href); - } - if ( props.href && (props.href.startsWith("https://") || props.href?.startsWith("data:")) @@ -79,13 +87,13 @@ export function Button(props: Props) { if (props.href) return ( - goTo(props.href || "")}> + {content} ); return ( - ); @@ -101,11 +109,10 @@ interface ButtonPlainProps { export function ButtonPlain(props: ButtonPlainProps) { let colorClasses = "bg-white hover:bg-gray-200 text-black"; if (props.theme === "purple") - colorClasses = - "bg-video-buttons-purple hover:bg-video-buttons-purpleHover text-white"; + colorClasses = "bg-buttons-purple hover:bg-buttons-purpleHover text-white"; if (props.theme === "secondary") colorClasses = - "bg-video-buttons-cancel hover:bg-video-buttons-cancelHover transition-colors duration-100 text-white"; + "bg-buttons-cancel hover:bg-buttons-cancelHover transition-colors duration-100 text-white"; const classes = classNames( "cursor-pointer inline-flex items-center justify-center rounded-lg font-medium transition-[transform,background-color] duration-100 active:scale-105 md:px-8", diff --git a/src/components/UserIcon.tsx b/src/components/UserIcon.tsx new file mode 100644 index 00000000..ba90a451 --- /dev/null +++ b/src/components/UserIcon.tsx @@ -0,0 +1,35 @@ +import { memo } from "react"; + +import { Icon, Icons } from "@/components/Icon"; + +export enum UserIcons { + SEARCH = "search", + BOOKMARK = "bookmark", + CLOCK = "clock", + EYE_SLASH = "eyeSlash", + USER = "user", +} + +export interface UserIconProps { + icon: UserIcons; + className?: string; +} + +const iconList: Record = { + search: ``, + bookmark: ``, + clock: ``, + eyeSlash: ``, + user: ``, +}; + +export const UserIcon = memo((props: UserIconProps) => { + const icon = iconList[props.icon]; + if (!icon) return ; + return ( + + ); +}); diff --git a/src/components/form/ColorPicker.tsx b/src/components/form/ColorPicker.tsx new file mode 100644 index 00000000..4e922b22 --- /dev/null +++ b/src/components/form/ColorPicker.tsx @@ -0,0 +1,39 @@ +import classNames from "classnames"; + +import { Icon, Icons } from "../Icon"; + +export function ColorPicker(props: { + label: string; + value: string; + onInput: (v: string) => void; +}) { + // Migrate this to another file later + const colors = ["#2E65CF", "#7652DD", "#CF2E68", "#C2CF2E", "#2ECFA8"]; + return ( +
+ {props.label ? ( +

{props.label}

+ ) : null} + +
+ {colors.map((color) => { + return ( + + ); + })} +
+
+ ); +} diff --git a/src/components/form/IconPicker.tsx b/src/components/form/IconPicker.tsx new file mode 100644 index 00000000..17d9f7f5 --- /dev/null +++ b/src/components/form/IconPicker.tsx @@ -0,0 +1,47 @@ +import classNames from "classnames"; + +import { UserIcon, UserIcons } from "../UserIcon"; + +export function IconPicker(props: { + label: string; + value: UserIcons; + onInput: (v: UserIcons) => void; +}) { + // Migrate this to another file later + const icons = [ + UserIcons.USER, + UserIcons.BOOKMARK, + UserIcons.CLOCK, + UserIcons.EYE_SLASH, + UserIcons.SEARCH, + ]; + + return ( +
+ {props.label ? ( +

{props.label}

+ ) : null} + +
+ {icons.map((icon) => { + return ( + + ); + })} +
+
+ ); +} diff --git a/src/components/layout/LargeCard.tsx b/src/components/layout/LargeCard.tsx index ba756ab0..2266be3a 100644 --- a/src/components/layout/LargeCard.tsx +++ b/src/components/layout/LargeCard.tsx @@ -38,7 +38,7 @@ export function LargeCardText(props: { export function LargeCardButtons(props: { children: React.ReactNode }) { return ( -
+
{props.children}
diff --git a/src/components/player/atoms/NextEpisodeButton.tsx b/src/components/player/atoms/NextEpisodeButton.tsx index 8e669c30..e0a5c0d5 100644 --- a/src/components/player/atoms/NextEpisodeButton.tsx +++ b/src/components/player/atoms/NextEpisodeButton.tsx @@ -93,14 +93,14 @@ export function NextEpisodeButton(props: { ])} >
- diff --git a/src/pages/parts/auth/VerifyPassphrasePart.tsx b/src/pages/parts/auth/VerifyPassphrasePart.tsx index 34c3a52b..2506807a 100644 --- a/src/pages/parts/auth/VerifyPassphrasePart.tsx +++ b/src/pages/parts/auth/VerifyPassphrasePart.tsx @@ -1,5 +1,5 @@ -import { useCallback, useEffect, useState } from "react"; -import { GoogleReCaptcha, useGoogleReCaptcha } from "react-google-recaptcha-v3"; +import { useState } from "react"; +import { useGoogleReCaptcha } from "react-google-recaptcha-v3"; import { useAsyncFn } from "react-use"; import { Button } from "@/components/Button"; @@ -77,7 +77,11 @@ export function VerifyPassphrase(props: VerifyPassphraseProps) {

) : null} - diff --git a/tailwind.config.js b/tailwind.config.js index 8e79202b..84240765 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 @@ -72,13 +72,24 @@ module.exports = { toggleDisabled: "#202836", danger: "#792131", dangerHover: "#8a293b", + + secondary: "#161F25", + secondaryText: "#8EA3B0", + secondaryHover: "#1B262E", + primary: "#fff", + primaryText: "#000", + primaryHover: "#dedede", + purple: "#6b298a", + purpleHover: "#7f35a1", + cancel: "#252533", + cancelHover: "#3C3C4A" }, // only used for body colors/textures background: { main: "#0A0A10", accentA: "#6E3B80", - accentB: "#1F1F50", + accentB: "#1F1F50" }, // typography @@ -87,7 +98,7 @@ module.exports = { text: "#73739D", dimmed: "#926CAD", divider: "#262632", - secondary: "#64647B", + secondary: "#64647B" }, // search bar @@ -96,7 +107,7 @@ module.exports = { focused: "#24243C", placeholder: "#4A4A71", icon: "#545476", - text: "#FFFFFF", + text: "#FFFFFF" }, // media cards @@ -108,13 +119,13 @@ module.exports = { barColor: "#4B4B63", barFillColor: "#BA7FD6", badge: "#151522", - badgeText: "#5F5F7A", + badgeText: "#5F5F7A" }, // Large card largeCard: { background: "#171728", - icon: "#6741A5", + icon: "#6741A5" }, // Passphrase @@ -124,7 +135,7 @@ module.exports = { wordBackground: "#171728", copyText: "#58587A", copyTextHover: "#8888AA", - errorText: "#DB3D62", + errorText: "#DB3D62" }, // Settings page @@ -137,19 +148,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 @@ -158,20 +169,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 @@ -183,24 +194,11 @@ module.exports = { error: "#E44F4F", success: "#40B44B", loading: "#B759D8", - noresult: "#64647B", + noresult: "#64647B" }, audio: { - set: "#A75FC9", - }, - - buttons: { - secondary: "#161F25", - secondaryText: "#8EA3B0", - secondaryHover: "#1B262E", - primary: "#fff", - primaryText: "#000", - primaryHover: "#dedede", - purple: "#6b298a", - purpleHover: "#7f35a1", - cancel: "#252533", - cancelHover: "#3C3C4A", + set: "#A75FC9" }, context: { @@ -220,19 +218,19 @@ module.exports = { buttons: { list: "#161C26", - active: "#0D1317", + active: "#0D1317" }, type: { main: "#617A8A", secondary: "#374A56", - accent: "#A570FA", - }, - }, - }, - }, - }, - }, - }), - ], + accent: "#A570FA" + } + } + } + } + } + } + }) + ] };