- {Array(numInputs)
- .fill(null)
- .map((_, i) => {
- return (
-
(inputRefs.current[i] = el)}
- onFocus={(event) => handleFocus(event)(i)}
- onInput={handleInputChange}
- onKeyDown={handleKeyDown}
- onPaste={handlePaste}
- className={
- isInvalidOTP
- ? 'xar-otp-input xar-invalid-otp'
- : 'xar-otp-input'
- }
- />
- )
- })}
+
-
- Incorrect OTP. {attempts} attempts left.
-
+
+
+ {Array(numInputs)
+ .fill(null)
+ .map((_, i) => {
+ return (
+ (inputRefs.current[i] = el)}
+ onFocus={(event) => handleFocus(event)(i)}
+ onInput={handleInputChange}
+ onKeyDown={handleKeyDown}
+ onPaste={handlePaste}
+ className={
+ isInvalidOTP
+ ? 'xar-otp-input xar-invalid-otp'
+ : 'xar-otp-input'
+ }
+ />
+ )
+ })}
- ) : (
- ''
- )}
+ {isInvalidOTP ? (
+
+
+ Incorrect OTP. {attempts} attempts left.
+
+
+ ) : (
+ ''
+ )}
+
-
0}
- text={
- counter > 0 ? `Resend code in ${counter} seconds` : 'Resend code'
- }
- method={resendCode}
- />
+ {counter > 0 ? (
+ Resend code in {counter} seconds
+ ) : (
+
+
Did not receive your code yet?
+
+
+ )}
>
)
@@ -450,16 +524,17 @@ const useCounter = (time = 60) => {
return { counter, resetCounter }
}
-const OTPError = ({ action }: { action: () => void }) => {
+const OTPError = ({ action, mode }: { action: () => void; mode: Theme }) => {
return (
<>
-
+
Login Failed
Please check credentials and try again
>
)
diff --git a/src/ui/icons.ts b/src/ui/icons.ts
index 87d1217..a07df4c 100644
--- a/src/ui/icons.ts
+++ b/src/ui/icons.ts
@@ -1,10 +1,12 @@
const BASE_URL = 'https://auth-icons.s3.ap-south-1.amazonaws.com'
+const LOADING_ICON = `${BASE_URL}/loading.svg`
+
const SOCIAL_LOGO: { [k: string]: string } = {
google: `${BASE_URL}/google.png`,
twitter: `${BASE_URL}/twitter.png`,
- github: `${BASE_URL}/github-light.png`,
- github_light: `${BASE_URL}/github.png`,
+ github: `${BASE_URL}/github.png`,
+ github_light: `${BASE_URL}/github-light.png`,
twitch: `${BASE_URL}/twitch.png`,
discord: `${BASE_URL}/discord.png`,
aws: `${BASE_URL}/aws.png`,
@@ -12,6 +14,33 @@ const SOCIAL_LOGO: { [k: string]: string } = {
steam: `${BASE_URL}/steam.png`,
}
+const MISC_ICONS = {
+ light: {
+ arrow: `${BASE_URL}/arrow-light.svg`,
+ success: `${BASE_URL}/success.svg`,
+ failed: `${BASE_URL}/failed.svg`,
+ email: `${BASE_URL}/email.svg`,
+ 'try-again': `${BASE_URL}/try-again-light.svg`,
+ change: `${BASE_URL}/change.svg`,
+ send: `${BASE_URL}/send.svg`,
+ 'dots-horizontal': `${BASE_URL}/dots-horizontal-light.svg`,
+ shrink: `${BASE_URL}/shrink-light.svg`,
+ 'back-arrow': `${BASE_URL}/back-arrow-light.svg`,
+ },
+ dark: {
+ arrow: `${BASE_URL}/arrow-dark.svg`,
+ success: `${BASE_URL}/success.svg`,
+ failed: `${BASE_URL}/failed.svg`,
+ email: `${BASE_URL}/email.svg`,
+ 'try-again': `${BASE_URL}/try-again-dark.svg`,
+ change: `${BASE_URL}/change.svg`,
+ send: `${BASE_URL}/send.svg`,
+ 'dots-horizontal': `${BASE_URL}/dots-horizontal-dark.svg`,
+ shrink: `${BASE_URL}/shrink-dark.svg`,
+ 'back-arrow': `${BASE_URL}/back-arrow-dark.svg`,
+ },
+}
+
function getSocialLogo(provider: string, theme: 'light' | 'dark') {
if (SOCIAL_LOGO[`${provider}_${theme}`]) {
return SOCIAL_LOGO[`${provider}_${theme}`]
@@ -24,4 +53,4 @@ const ARCANA_LOGO = {
dark: `${BASE_URL}/secured-by-arcana-dark.svg`,
}
-export { getSocialLogo, ARCANA_LOGO }
+export { getSocialLogo, ARCANA_LOGO, MISC_ICONS, LOADING_ICON }
diff --git a/src/ui/loader.tsx b/src/ui/loader.tsx
index 0198a7d..d83cad7 100644
--- a/src/ui/loader.tsx
+++ b/src/ui/loader.tsx
@@ -1,64 +1,5 @@
-const RADIUS = 20
+import { LOADING_ICON } from './icons'
-interface LoaderProps {
- stroke: number
- secondaryColor: string
- strokeColor?: string
- compact?: boolean
- width?: number
-}
-
-export default function Loader(props: LoaderProps) {
- const width = props.width ? props.width : props.compact ? 60 : 80
- const { stroke = 8, secondaryColor } = props
- return (
-
- )
-}
-
-const getViewBoxSize = (strokeWidth: number, radius: number) => {
- const startingPoint = -radius - strokeWidth / 2 + 1
- const endpoint = radius * 2 + strokeWidth
- return [startingPoint, startingPoint, endpoint, endpoint].join(' ')
-}
-
-const getPath = (radius: number) => {
- return ['M' + radius + ' 0c0-9.94-8.06', radius, radius, radius].join('-')
+export default function Loader() {
+ return
}
diff --git a/src/ui/modal.tsx b/src/ui/modal.tsx
index c99d49e..61e4c7a 100644
--- a/src/ui/modal.tsx
+++ b/src/ui/modal.tsx
@@ -10,6 +10,7 @@ import {
OTPError,
} from './components'
import { Overlay } from './overlay'
+import More from './more'
import { useReducer, useState } from 'preact/hooks'
const WAIT_TEXT = {
@@ -58,6 +59,7 @@ const reducer = (
const Modal = (props: ModalParams) => {
const [loaderState, dispatch] = useReducer(reducer, initLoaderState)
const [email, setEmail] = useState('')
+ const [showMore, setShowMore] = useState(false)
const socialLogin = async (kind: string) => {
dispatch('SOCIAL')
@@ -74,17 +76,24 @@ const Modal = (props: ModalParams) => {
return login
}
+ function onShowMore(val: boolean) {
+ setShowMore(val)
+ }
+
if (loaderState.loading) {
return (
{loaderState.type == 'OTP_SENT' ? (
dispatch('RESET')}
loginWithOtpStart={() => props.loginWithOTPStart(email)}
setError={() => dispatch('OTP_ERROR')}
closeFunc={props.closeFunc}
loginWithOtpComplete={props.loginWithOTPComplete}
compact={props.options.compact}
+ email={email}
+ mode={props.mode}
/>
) : (
{
{loaderState.type == 'OTP_ERROR' ? (
- dispatch('RESET')} />
+ dispatch('RESET')} mode={props.mode} />
) : (
<>
@@ -110,17 +119,29 @@ const Modal = (props: ModalParams) => {
email={email}
setEmail={setEmail}
loginWithOTPStart={otpLogin}
+ mode={props.mode}
/>
{props.loginList.length > 0 ? (
<>
-
+
onShowMore(true)}
/>
>
) : null}
+ {showMore ? (
+ onShowMore(false)}
+ mode={props.mode}
+ onLoginClick={socialLogin}
+ />
+ ) : (
+ ''
+ )}
>
)}
diff --git a/src/ui/more.tsx b/src/ui/more.tsx
new file mode 100644
index 0000000..f7797fa
--- /dev/null
+++ b/src/ui/more.tsx
@@ -0,0 +1,55 @@
+import { StateUpdater, Dispatch } from 'preact/hooks'
+import { getSocialLogo, MISC_ICONS } from './icons'
+import { Theme } from '../typings'
+
+interface MoreProps {
+ list: Array
+ setShow: Dispatch>
+ onLoginClick: (kind: string) => void
+ mode: Theme
+}
+
+export default function More(props: MoreProps) {
+ const { list, setShow, mode, onLoginClick } = props
+
+ const onSocialLoginClick = (kind: string) => {
+ onLoginClick(kind)
+ setShow(false)
+ }
+
+ return (
+
+
setShow(false)} style={{ flex: 1 }}>
+
e.preventDefault()}>
+
+
setShow(false)}
+ />
+
+
Continue with a social account
+
+ {list.map((l) => {
+ return (
+
onSocialLoginClick(l)}
+ >
+
+
+
+
{l}
+
+ )
+ })}
+
+
+
+ )
+}
diff --git a/src/ui/style.css b/src/ui/style.css
index 17b91e4..bbf3754 100644
--- a/src/ui/style.css
+++ b/src/ui/style.css
@@ -1,26 +1,51 @@
@import url('https://fonts.googleapis.com/css2?family=Sora:wght@100;400;600;700&display=block');
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&family=Sora:wght@400;600&display=block');
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
+
+@font-face {
+ font-family: 'Nohemi';
+ src: url('https://new-fonts.s3.ap-south-1.amazonaws.com/Nohemi-SemiBold.woff2')
+ format('woff2');
+ font-weight: 400;
+ font-style: normal;
+}
.xar-light-mode {
- --fg: #333333;
- --bg: #eff1f3;
- --background: #fcfcfc;
+ --fg: #e4e9eb;
+ --bg: #e4e9eb;
+ --background: #f7f7f7;
--inputShadow: 0 0 8px 3px rgba(126, 126, 126, 0.25);
- --text-color: #101010;
+ --text-color: #1d2a31;
+ --sub-text-color: #829299;
--otp-bg: #eeeeee;
--otp-shadow: 1px 1px 2px 0px #aeaec033 inset,
-1px -1px 1px 0px #ffffffb2 inset;
+ --action-link-text-color: #bbccd6;
+ --separator-color: #c8d5d9;
+ --separator-text-color: #74919c;
+ --error-text-color: #f61d1d;
+ --more-icon-bg: #47545b;
+ --email-id-color: #1d2a31;
+ --social-login-fw-bg: #1d2a31;
}
.xar-dark-mode {
- --fg: #ffffff;
- --bg: #313131;
- --background: #262626;
+ --fg: #47545b;
+ --bg: #39444a;
+ --background: #2d363b;
--inputShadow: 0 0 8px 3px rgba(0, 0, 0, 0.05);
--text-color: #f7f7f7;
+ --sub-text-color: #829299;
--otp-bg: linear-gradient(141.48deg, #161616 -4.56%, #151515 135.63%);
--otp-shadow: -50px 49px 29px 22px #1c1c1cd6 inset,
5px 5px 10px 0px #0b0b0b80 inset;
+ --action-link-text-color: #bbccd6;
+ --separator-color: #39444a;
+ --separator-text-color: #829299;
+ --error-text-color: #fa3636;
+ --more-icon-bg: #47545b;
+ --email-id-color: #d4d7d8;
+ --social-login-fw-bg: #f7f7f7;
}
.compact {
@@ -32,11 +57,11 @@
}
.full {
- --modal-height: 480px;
- --loader-font-size: 20px;
- --loader-font-weight: 700;
+ --modal-height: 200px;
+ --loader-font-size: 12px;
+ --loader-font-weight: 400;
--success-img-width: 100px;
- --action-link-size: 15px;
+ --action-link-size: 12px;
}
#xar-modal {
@@ -67,13 +92,14 @@
}
.xar-header-logo__empty-container {
- width: 70px;
+ /* width: 70px;
height: 70px;
border-radius: 50%;
margin: 0 auto;
display: flex;
align-items: center;
- justify-content: center;
+ justify-content: center; */
+ display: none;
}
.xar-header-logo {
@@ -81,20 +107,30 @@
max-height: 60px;
margin: 0 auto;
display: inline-block;
+ border-radius: 100%;
}
.xar-header-heading {
- font-family: 'Sora', sans-serif;
+ font-family: 'Nohemi', 'Sora', sans-serif;
text-align: center;
+ font-size: 20px;
+ color: var(--text-color);
}
.xar-header-subtext {
- font-family: 'Sora', sans-serif;
+ font-family: 'Inter', sans-serif;
font-size: 12px;
font-weight: 400;
max-width: 200px;
}
+.xar-sub-text {
+ font-family: 'Inter', sans-serif;
+ font-size: 12px;
+ font-weight: 400;
+ color: var(--sub-text-color);
+}
+
.xar-email-login {
display: flex;
flex-direction: column;
@@ -116,25 +152,61 @@
max-width: var(--success-img-width);
}
+.xar-email-login__input-container {
+ display: flex;
+ min-height: 45px;
+ position: relative;
+}
+
.xar-email-login__input {
+ flex: 1;
height: 45px;
- padding: 0 16px;
font-family: 'Sora', sans-serif;
- font-size: 14px;
- font-weight: 400;
- color: var(--fg);
+ font-size: 16px;
+ font-weight: 500;
+ color: var(--text-color);
background: var(--bg);
border: none;
- border-radius: 5px;
outline: none;
- box-shadow: var(--inputShadow);
+ border-radius: 8px;
+ padding: 10px;
+ box-sizing: border-box;
+}
+
+input[type='text']:focus {
+ border: 1px solid var(--sub-text-color);
}
.xar-social-container {
display: flex;
- justify-content: center;
+ justify-content: space-between;
gap: 1rem;
flex-wrap: wrap;
+ width: 100%;
+}
+
+.xar-social-icon__wrapper-full-width {
+ display: flex;
+ background: var(--social-login-fw-bg);
+ width: 100%;
+ height: 44px;
+ align-items: center;
+ justify-content: center;
+ gap: 4px;
+ border-radius: 100px;
+ cursor: pointer;
+}
+
+.xar-social-icon__wrapper-full-width img {
+ margin: 0;
+ height: 22px;
+ width: 22px;
+}
+
+.xar-social-icon__wrapper-full-width p {
+ font-size: 14px;
+ font-weight: 600;
+ font-family: 'Inter', sans-serif;
}
.xar-social-icon__wrapper {
@@ -159,44 +231,127 @@
}
.xar-container {
- padding: 30px 30px 20px;
- width: 325px;
+ padding: 20px;
+ width: 360px;
min-height: var(--modal-height);
background-color: var(--background);
color: var(--fg);
margin: 0 auto;
- font-family: 'Sora', sans-serif;
+ font-family: 'Inter', sans-serif;
box-shadow: 4px 5px 4px rgba(0, 0, 0, 0.25);
border-radius: 10px;
- box-sizing: content-box;
+ box-sizing: border-box;
transition: all 1s ease;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
}
.xar-inner-container {
- min-height: inherit;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
+ position: relative;
+ margin: auto;
+ width: 100%;
+ gap: 20px;
}
-.xar-inner-container > *:not(:first-child) {
- margin-top: 20px;
+.xar-more-sheet-container {
+ background: rgb(18 18 18 / 90%);
+ position: absolute;
+ height: 108%;
+ width: 112.4%;
+ border-radius: 10px;
+ bottom: 0px;
+ display: flex;
}
-.xar-btn {
- margin: 0 auto;
- padding: 0;
+.xar-more-sheet {
+ padding: 14px;
+ box-sizing: border-box;
+ border-radius: 10px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ background: var(--background);
+ transition: all 0.3s ease-in-out;
+ animation: slide-up 0.3s ease-in-out forwards;
+ position: absolute;
width: 100%;
- height: 2.75rem;
- font-size: 14px;
+ height: 80%;
+ bottom: 0px;
+}
+
+.xar-more-shrink-icon {
+ width: 50px;
+ height: 10px;
+ cursor: pointer;
+}
+
+.xar-more-sheet__title {
+ color: var(--text-color);
+ font-size: 20px;
font-weight: 600;
- text-transform: uppercase;
- color: var(--bg);
- background: var(--fg);
+}
+
+.xar-more-sheet__list-container {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ border-radius: 10px;
+ background: var(--bg);
+ padding: 10px;
+ flex: 1;
+ overflow-y: auto;
+}
+
+.xar-more-sheet__list-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ cursor: pointer;
+}
+
+.xar-more-sheet__list-icon-container {
+ background: var(--more-icon-bg);
+ border-radius: 50%;
+ display: flex;
+}
+
+.xar-more-sheet__list-icon {
+ padding: 6px;
+ width: 16px;
+ height: 16px;
+}
+
+.xar-more-sheet__list-text {
+ font-size: 14px;
+ font-weight: 500;
+ color: var(--text-color);
+ text-transform: capitalize;
+}
+
+.xar-btn__input-arrow {
+ position: absolute;
+ left: 290px;
+ height: 100%;
+ display: inline-flex;
+ justify-content: right;
+}
+
+.xar-btn__input-arrow:disabled img {
+ filter: opacity(25%);
+}
+
+.xar-btn {
+ background: transparent;
border: none;
- border-radius: 5px;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
}
.xar-btn:disabled {
@@ -239,13 +394,21 @@
display: flex;
align-items: center;
text-align: center;
+ color: var(--separator-color);
+}
+
+.xar-separator__text {
+ font-size: 12px;
+ font-weight: 400;
+ font-family: 'Inter', sans-serif;
+ color: var(--separator-text-color);
}
.xar-separator:before,
.xar-separator:after {
content: '';
flex: 1 1 auto;
- border-bottom: 1px solid var(--fg);
+ border-bottom: 1px solid var(--separator-color);
}
.xar-separator:before {
@@ -259,13 +422,9 @@
.xar-action__link {
border: 0;
background: none;
- text-underline-offset: 3px;
- text-transform: uppercase;
- text-decoration: underline;
- color: #3e9aff;
- font-weight: 700;
+ color: var(--action-link-text-color);
+ font-weight: 400;
font-size: var(--action-link-size);
- line-height: 19px;
cursor: pointer;
}
@@ -274,22 +433,35 @@
cursor: not-allowed;
}
+.xar-loading__header {
+ font-size: 20px;
+ font-weight: 600;
+ color: var(--text-color);
+}
+
.xar-loader__text {
font-size: var(--loader-font-size);
font-weight: var(--loader-font-weight);
+ color: var(--text-color);
}
.xar-loader-circle {
stroke: var(--fg);
}
+.xar-otp-box-container {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5em;
+}
+
.xar-otp-box {
display: flex;
gap: 0.5em;
}
.xar-otp-input {
- color: var(--fg);
+ color: var(--text-color);
font-size: 20px;
font-weight: 400;
border: none;
@@ -297,17 +469,19 @@
text-align: center;
width: 30px;
height: 35px;
- border-radius: 10px;
- background: var(--otp-bg);
- box-shadow: var(--otp-shadow);
+ border-radius: 8px;
+ background: var(--bg);
}
.xar-invalid-otp {
- border: 1px solid #b43030;
+ border: 1px solid var(--error-text-color);
}
.xar-invalid-otp-text {
- color: #b43030;
+ color: var(--error-text-color);
+ font-size: 10px;
+ font-weight: 400;
+ text-align: left;
}
.xar-otp-input:disabled {
@@ -315,30 +489,67 @@
}
.xar-otp-heading {
- font-family: 'Montserrat', sans-serif;
- font-size: 24px;
- font-weight: 700;
+ font-family: 'Nohemi', sans-serif;
+ font-size: 20px;
+ font-weight: 600;
text-align: center;
color: var(--text-color);
+ flex: 1;
}
.xar-otp-sub-heading {
- font-family: 'Montserrat', sans-serif;
+ font-family: 'Inter', sans-serif;
font-size: 12px;
font-weight: 400;
text-align: center;
color: var(--text-color);
}
-.xar-otp-error-heading {
- color: var(--fg);
+.xar-otp-email {
+ font-size: 14px;
font-weight: 700;
- font-size: 24px;
- font-family: 'Montserrat', sans-serif;
+ color: var(--email-id-color);
}
-.xar-otp-error-subheading {
+
+.xar-otp-error-heading {
color: var(--text-color);
+ font-weight: 600;
+ font-size: 20px;
+ font-family: 'Nohemi', sans-serif;
+}
+.xar-otp-error-subheading {
+ color: var(--sub-text-color);
font-weight: 400;
font-size: 12px;
- font-family: 'Montserrat', sans-serif;
+ font-family: 'Inter', sans-serif;
+}
+
+.xar-otp-heading-container {
+ display: flex;
+ flex-direction: row;
+ gap: 0.5rem;
+ width: 100%;
+ position: relative;
+ align-items: center;
+}
+
+.xar-loader {
+ animation: spin 1s linear infinite;
+}
+
+@-moz-keyframes spin {
+ 100% {
+ -moz-transform: rotate(360deg);
+ }
+}
+@-webkit-keyframes spin {
+ 100% {
+ -webkit-transform: rotate(360deg);
+ }
+}
+@keyframes spin {
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
}