From 222b98fc0e64f90569fd7e4eca0c333aef4a2bfd Mon Sep 17 00:00:00 2001 From: Viktor Riabkov Date: Sun, 3 Nov 2024 22:10:00 +0100 Subject: [PATCH] CSSTransition added --- index.html | 3 +- package.json | 2 + src/app/index.css | 80 +++++++++++++++++-- .../translation/ui/LanguageSwitcher.tsx | 2 +- src/i18n/en/translation.json | 2 + src/i18n/ru/translation.json | 2 + src/shared/ui/Button/index.tsx | 25 ++++++ src/shared/ui/Page/Page.tsx | 2 +- src/shared/ui/Typography/index.tsx | 25 ++++++ src/shared/ui/index.ts | 2 + src/widget/Login/ui/LoginButton.tsx | 43 +++++----- src/widget/Login/ui/LoginHeader.tsx | 5 +- src/widget/Login/ui/index.tsx | 30 ++++--- tailwind.config.js | 4 + yarn.lock | 40 +++++++++- 15 files changed, 226 insertions(+), 41 deletions(-) create mode 100644 src/shared/ui/Button/index.tsx create mode 100644 src/shared/ui/Typography/index.tsx diff --git a/index.html b/index.html index f4161a9..fa023bb 100644 --- a/index.html +++ b/index.html @@ -17,8 +17,7 @@ - + diff --git a/package.json b/package.json index b652898..3ce98ad 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "react-i18next": "^15.1.0", "react-router-dom": "^6.27.0", "react-toastify": "^10.0.6", + "react-transition-group": "^4.4.5", "tailwindcss": "^3.4.14", "zod": "^3.23.8" }, @@ -33,6 +34,7 @@ "@types/node": "^22.8.1", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", + "@types/react-transition-group": "^4", "@typescript-eslint/eslint-plugin": "^8.11.0", "@typescript-eslint/parser": "^8.11.0", "@vitejs/plugin-react": "^4.3.3", diff --git a/src/app/index.css b/src/app/index.css index b3c227c..71944c6 100644 --- a/src/app/index.css +++ b/src/app/index.css @@ -20,14 +20,82 @@ span { cursor: default; } +.text-ru { + font-family: sans-serif; + font-optical-sizing: auto; + font-style: normal; +} + +.text-en { + font-family: "Urbanist", sans-serif; + font-optical-sizing: auto; + font-style: normal; +} + input:-webkit-autofill { - -webkit-box-shadow: 0 0 0px 1000px white inset; - box-shadow: 0 0 0px 1000px white inset; - -webkit-text-fill-color: black; + -webkit-box-shadow: 0 0 0px 1000px #F1EBF5 inset; + box-shadow: 0 0 0px 1000px #F1EBF5 inset; + -webkit-text-fill-color: #3A3341; } input:-webkit-autofill:focus { - -webkit-box-shadow: 0 0 0px 1000px white inset; - box-shadow: 0 0 0px 1000px white inset; - -webkit-text-fill-color: black; + -webkit-box-shadow: 0 0 0px 1000px #F1EBF5 inset; + box-shadow: 0 0 0px 1000px #F1EBF5 inset; + -webkit-text-fill-color: #3A3341; +} + +.node-opacity-enter { + opacity: 0; +} +.node-opacity-enter-active { + opacity: 1; + transition: opacity 500ms; +} +.node-opacity-exit { + opacity: 1; +} +.node-opacity-exit-active { + opacity: 0; + transition: opacity 500ms; +} + +.node-height-and-opacity-enter { + opacity: 0; + height: 0%; +} + +.node-height-and-opacity-enter-active { + opacity: 1; + height: 100%; + transition-property: opacity, height; + transition-duration: 300ms, 600ms; + transition-delay: 0ms, 400ms; +} + +.node-height-and-opacity-exit { + opacity: 1; + height: 100%; +} + +.node-height-and-opacity-exit-active { + opacity: 0; + height: 0%; + transition-property: opacity, height; + transition-duration: 300ms, 600ms; + transition-delay: 0ms, 400ms; +} + +.node-height-enter { + height: 0%; +} +.node-height-enter-active { + height: 100%; + transition: height 750ms; +} +.node-height-exit { + height: 100%; +} +.node-height-exit-active { + height: 0%; + transition: height 750ms; } diff --git a/src/feature/translation/ui/LanguageSwitcher.tsx b/src/feature/translation/ui/LanguageSwitcher.tsx index 90c5dc9..90ee46d 100644 --- a/src/feature/translation/ui/LanguageSwitcher.tsx +++ b/src/feature/translation/ui/LanguageSwitcher.tsx @@ -4,7 +4,7 @@ export const LanguageSwitcher = () => { const { switchLanguage, language } = useCustomTranslation() return ( - ) diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json index cfe8eaa..c3600a1 100644 --- a/src/i18n/en/translation.json +++ b/src/i18n/en/translation.json @@ -16,6 +16,7 @@ "toCompleteChallenge": "to complete your daily challenge!", "youCanRestFor": "you can rest for", "login": "Login", + "loginWithCode": "Login with code", "fastLogin": "Fast login", "logout": "Logout", "enterEmailForCode": "Enter your email. You will receive an email with an authorization code.", @@ -29,6 +30,7 @@ "yes": "Yes", "no": "No", "welcomeToChallengeLogger": ["Welcome to", "Challenge Logger"], + "loginViaCodeHint": ["The email with the code has been sent.","If the email does not arrive, then try again."], "yourAccount": "Your account", "sendingEmail": "Sending email", "sendingCode": "Sending code", diff --git a/src/i18n/ru/translation.json b/src/i18n/ru/translation.json index c793c8c..1351738 100644 --- a/src/i18n/ru/translation.json +++ b/src/i18n/ru/translation.json @@ -16,6 +16,7 @@ "toCompleteChallenge": "для выполнения вашего ежедневного вызова!", "youCanRestFor": "вы можете отдыхать еще", "login": "Логин", + "loginWithCode": "Войти с кодом", "fastLogin": "Быстрый вход", "logout": "Выйти", "enterEmailForCode": "Введите ваш емайл. Вам придет письмо с кодом для авторизации.", @@ -29,6 +30,7 @@ "yes": "Да", "no": "Нет", "welcomeToChallengeLogger": ["Добро пожаловать в", "Challenge Logger"], + "loginViaCodeHint": ["Письмо с кодом было отправлено.","Если письмо не приходит, то попробуйте еще раз."], "yourAccount": "Ваш аккаунт", "sendingEmail": "Отправка письма", "sendingCode": "Отправка кода", diff --git a/src/shared/ui/Button/index.tsx b/src/shared/ui/Button/index.tsx new file mode 100644 index 0000000..341fb68 --- /dev/null +++ b/src/shared/ui/Button/index.tsx @@ -0,0 +1,25 @@ +import { Typography } from '../Typography' + +type Props = { + label: string + onClick: () => void + isLoading?: boolean + isDisabled?: boolean + classNames?: string +} + +export const Button = ({ label, onClick, isDisabled, isLoading, classNames }: Props) => { + return ( + + ) +} diff --git a/src/shared/ui/Page/Page.tsx b/src/shared/ui/Page/Page.tsx index b784583..56232ef 100644 --- a/src/shared/ui/Page/Page.tsx +++ b/src/shared/ui/Page/Page.tsx @@ -4,7 +4,7 @@ type Props = PropsWithChildren export const Page = ({ children }: Props) => { return ( -
+
{children}
) diff --git a/src/shared/ui/Typography/index.tsx b/src/shared/ui/Typography/index.tsx new file mode 100644 index 0000000..b1d1afc --- /dev/null +++ b/src/shared/ui/Typography/index.tsx @@ -0,0 +1,25 @@ +import { PropsWithChildren } from 'react' + +import { useTranslation } from 'react-i18next' + +type Props = PropsWithChildren<{ + text?: string + classNames?: string +}> + +export const Typography = (props: Props) => { + const { i18n } = useTranslation() + + const language = i18n.language as 'en' | 'ru' + + const fontFamilyMap = { + en: 'text-en', + ru: 'text-ru', + } + + return ( +
+ {props.text ?? props.children} +
+ ) +} diff --git a/src/shared/ui/index.ts b/src/shared/ui/index.ts index dccaa25..f2034d4 100644 --- a/src/shared/ui/index.ts +++ b/src/shared/ui/index.ts @@ -2,3 +2,5 @@ export * from './Page' export * from './RightArrow' export * from './PlusIcon' export * from './Modal' +export * from './Typography' +export * from './Button' diff --git a/src/widget/Login/ui/LoginButton.tsx b/src/widget/Login/ui/LoginButton.tsx index 67c93b2..69d5d73 100644 --- a/src/widget/Login/ui/LoginButton.tsx +++ b/src/widget/Login/ui/LoginButton.tsx @@ -1,28 +1,35 @@ +import { ForwardedRef, forwardRef } from 'react' + import { useCustomTranslation } from '~/feature/translation' +import { Button } from '~/shared/ui' type Props = { labelKey: string onClick: () => void isLoading?: boolean isDisabled?: boolean + classNames?: string } -export const LoginButton = ({ onClick, isLoading, labelKey, isDisabled }: Props) => { - const { t } = useCustomTranslation() +export const LoginButton = forwardRef( + ( + { onClick, isLoading, labelKey, isDisabled, classNames }: Props, + ref: ForwardedRef, + ) => { + const { t } = useCustomTranslation() - return ( -
- -
- ) -} + return ( +
+
+ ) + }, +) + +LoginButton.displayName = 'LoginButton' diff --git a/src/widget/Login/ui/LoginHeader.tsx b/src/widget/Login/ui/LoginHeader.tsx index 5aaa92f..0f54437 100644 --- a/src/widget/Login/ui/LoginHeader.tsx +++ b/src/widget/Login/ui/LoginHeader.tsx @@ -1,4 +1,5 @@ import { useCustomTranslation } from '~/feature/translation' +import { Typography } from '~/shared/ui' export const LoginHeader = () => { const { t } = useCustomTranslation() @@ -9,9 +10,9 @@ export const LoginHeader = () => {
-

+ {t('welcomeToChallengeLogger')} -

+
) diff --git a/src/widget/Login/ui/index.tsx b/src/widget/Login/ui/index.tsx index 61f83aa..9dfc2ac 100644 --- a/src/widget/Login/ui/index.tsx +++ b/src/widget/Login/ui/index.tsx @@ -1,19 +1,21 @@ -import { useCallback, useState } from 'react' +import { useCallback, useRef, useState } from 'react' import { browserSupportsWebAuthn, startAuthentication } from '@simplewebauthn/browser' import { useMutation } from '@tanstack/react-query' import { useNavigate } from 'react-router-dom' +import { CSSTransition } from 'react-transition-group' import z from 'zod' import { LoginButton } from './LoginButton' import { LoginHeader } from './LoginHeader' -import { useToast } from '../../../shared/hooks' import { useAuthenticateViaPasskeys } from '~/feature/AuthorizePasskeys/' import { useOTPLogin } from '~/feature/LoginOTP' import { useCustomTranslation } from '~/feature/translation' import { authService } from '~/shared/api/auth.service' import { Routes } from '~/shared/constants' +import { useToast } from '~/shared/hooks' +import { Typography } from '~/shared/ui' const emailSchema = z.string().email() @@ -24,6 +26,8 @@ export const LoginWidget = () => { const navigate = useNavigate() + const hintRef = useRef(null) + const { showPromiseToast, dismissAllToasts, showErrorToast } = useToast() const codeInputVisibility = new Map([ @@ -163,27 +167,35 @@ export const LoginWidget = () => { /> - {browserSupportsWebAuthn() && ( + {!isEmailSent && browserSupportsWebAuthn() && ( )} -
-

- {isEmailSent ? t('enterCodeFromEmail') : t('enterEmailForCode')} -

-
+ +
+ {t('loginViaCodeHint')} +
+
) } diff --git a/tailwind.config.js b/tailwind.config.js index b6223e1..9549ec2 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -8,6 +8,10 @@ export default { red: '#FF2B6B', green: '#C1FF72', blue: '#37F0F7', + background: '#F1EBF5', + black: '#3A3341', + violet: '#B29BC7', + violet20: 'rgba(178, 155, 199, 0.2)', }, fontFamily: { monospace: ['Source Code Pro', 'monospace'], diff --git a/yarn.lock b/yarn.lock index 2c53efa..c8b95d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1241,7 +1241,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.25.0": +"@babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": version: 7.26.0 resolution: "@babel/runtime@npm:7.26.0" dependencies: @@ -2212,6 +2212,15 @@ __metadata: languageName: node linkType: hard +"@types/react-transition-group@npm:^4": + version: 4.4.11 + resolution: "@types/react-transition-group@npm:4.4.11" + dependencies: + "@types/react": "npm:*" + checksum: 10c0/8fbf0dcc1b81985cdcebe3c59d769fe2ea3f4525f12c3a10a7429a59f93e303c82b2abb744d21cb762879f4514969d70a7ab11b9bf486f92213e8fe70e04098d + languageName: node + linkType: hard + "@types/react@npm:*": version: 18.3.5 resolution: "@types/react@npm:18.3.5" @@ -2961,6 +2970,7 @@ __metadata: "@types/node": "npm:^22.8.1" "@types/react": "npm:^18.3.12" "@types/react-dom": "npm:^18.3.1" + "@types/react-transition-group": "npm:^4" "@typescript-eslint/eslint-plugin": "npm:^8.11.0" "@typescript-eslint/parser": "npm:^8.11.0" "@vitejs/plugin-react": "npm:^4.3.3" @@ -2985,6 +2995,7 @@ __metadata: react-i18next: "npm:^15.1.0" react-router-dom: "npm:^6.27.0" react-toastify: "npm:^10.0.6" + react-transition-group: "npm:^4.4.5" tailwindcss: "npm:^3.4.14" typescript: "npm:^5.6.3" vite: "npm:^5.4.10" @@ -3306,6 +3317,16 @@ __metadata: languageName: node linkType: hard +"dom-helpers@npm:^5.0.1": + version: 5.2.1 + resolution: "dom-helpers@npm:5.2.1" + dependencies: + "@babel/runtime": "npm:^7.8.7" + csstype: "npm:^3.0.2" + checksum: 10c0/f735074d66dd759b36b158fa26e9d00c9388ee0e8c9b16af941c38f014a37fc80782de83afefd621681b19ac0501034b4f1c4a3bff5caa1b8667f0212b5e124c + languageName: node + linkType: hard + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -5761,7 +5782,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:^15.8.1": +"prop-types@npm:^15.6.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -5882,6 +5903,21 @@ __metadata: languageName: node linkType: hard +"react-transition-group@npm:^4.4.5": + version: 4.4.5 + resolution: "react-transition-group@npm:4.4.5" + dependencies: + "@babel/runtime": "npm:^7.5.5" + dom-helpers: "npm:^5.0.1" + loose-envify: "npm:^1.4.0" + prop-types: "npm:^15.6.2" + peerDependencies: + react: ">=16.6.0" + react-dom: ">=16.6.0" + checksum: 10c0/2ba754ba748faefa15f87c96dfa700d5525054a0141de8c75763aae6734af0740e77e11261a1e8f4ffc08fd9ab78510122e05c21c2d79066c38bb6861a886c82 + languageName: node + linkType: hard + "react@npm:^18.3.1": version: 18.3.1 resolution: "react@npm:18.3.1"