mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
move to ui package drectory
This commit is contained in:
1 parent
b0233d3e3d
commit
55329d540e
1124 files changed
+888
-2201
No files matched your search
@@ -774,6 +774,60 @@
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/launch-week-5-community-day</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/launch-week-5-one-more-thing</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/pg-jsonschema-a-postgres-extension-for-json-validation</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/postgrest-v10</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/supabase-vault</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/building-a-realtime-trello-board-with-supabase-and-angular</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/launch-week-5-hackathon-winners</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/supabase-beta-update-august-2022</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/blog/choosing-a-postgres-primary-key</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/alternatives/supabase-vs-firebase</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.sbui-auth {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sbui-auth-label {
|
||||
@apply block text-sm text-gray-700 dark:text-gray-200 font-medium;
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Auth } from './'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
// @ts-ignore
|
||||
import { Typography, Button, Space } from '../../index'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://rsnibhkhsbfnncjmwnkj.supabase.co',
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYxNTIxNDE1MywiZXhwIjoxOTMwNzkwMTUzfQ.OQEbAaTfgDdLCCht251P2JRD3QDnui6nsU8N-tZA_Mc'
|
||||
)
|
||||
|
||||
export default {
|
||||
title: 'Auth/Auth',
|
||||
component: Auth,
|
||||
}
|
||||
|
||||
const Container = (props: any) => {
|
||||
const { user } = Auth.useUser()
|
||||
if (user)
|
||||
return (
|
||||
<>
|
||||
<Typography.Text>Signed in: {user.email}</Typography.Text>
|
||||
<Button block onClick={() => props.supabaseClient.auth.signOut()}>
|
||||
Sign out
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
return props.children
|
||||
}
|
||||
|
||||
export const Default = (args: any) => (
|
||||
<Auth.UserContextProvider {...args}>
|
||||
<Container {...args}>
|
||||
<Auth {...args} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
)
|
||||
export const withSocialAuth = (args: any) => (
|
||||
<Auth.UserContextProvider {...args}>
|
||||
<Container {...args}>
|
||||
<Auth {...args} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
)
|
||||
export const withAllSocialAuth = (args: any) => (
|
||||
<Auth.UserContextProvider {...args}>
|
||||
<Container {...args}>
|
||||
<Auth {...args} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
)
|
||||
export const withSocialLargeButtons = (args: any) => (
|
||||
<Auth.UserContextProvider {...args}>
|
||||
<Container {...args}>
|
||||
<Auth {...args} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
)
|
||||
export const withColouredSocialAuth = (args: any) => (
|
||||
<Auth.UserContextProvider {...args}>
|
||||
<Container {...args}>
|
||||
<Auth {...args} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
)
|
||||
export const withSocialAuthHorizontal = (args: any) => (
|
||||
<Auth.UserContextProvider {...args}>
|
||||
<Container {...args}>
|
||||
<Auth {...args} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
)
|
||||
export const updatePassword = (args: any) => <Auth.UpdatePassword {...args} />
|
||||
|
||||
export const ChangeViewState = (args: any) => {
|
||||
const [view, setView] = useState<
|
||||
'sign_in' | 'sign_up' | 'forgotten_password' | 'magic_link'
|
||||
>('sign_in')
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Space>
|
||||
<Button
|
||||
type={view === 'sign_up' ? 'primary' : 'default'}
|
||||
onClick={() => setView('sign_up')}
|
||||
>
|
||||
Sign up
|
||||
</Button>
|
||||
<Button
|
||||
type={view === 'sign_in' ? 'primary' : 'default'}
|
||||
onClick={() => setView('sign_in')}
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
<Button
|
||||
type={view === 'forgotten_password' ? 'primary' : 'default'}
|
||||
onClick={() => setView('forgotten_password')}
|
||||
>
|
||||
Forgotten password
|
||||
</Button>
|
||||
<Button
|
||||
type={view === 'magic_link' ? 'primary' : 'default'}
|
||||
onClick={() => setView('magic_link')}
|
||||
>
|
||||
Magic link
|
||||
</Button>
|
||||
</Space>
|
||||
<Auth.UserContextProvider supabaseClient={supabase}>
|
||||
<Container supabaseClient={supabase}>
|
||||
<Auth supabaseClient={supabase} view={view} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Default.args = {
|
||||
supabaseClient: supabase,
|
||||
}
|
||||
|
||||
withSocialAuth.args = {
|
||||
supabaseClient: supabase,
|
||||
providers: ['facebook', 'google'],
|
||||
}
|
||||
|
||||
withAllSocialAuth.args = {
|
||||
supabaseClient: supabase,
|
||||
providers: [
|
||||
'apple',
|
||||
'azure',
|
||||
'bitbucket',
|
||||
'discord',
|
||||
'facebook',
|
||||
'github',
|
||||
'gitlab',
|
||||
'google',
|
||||
'twitch',
|
||||
'twitter',
|
||||
],
|
||||
}
|
||||
|
||||
withSocialLargeButtons.args = {
|
||||
supabaseClient: supabase,
|
||||
providers: [
|
||||
'apple',
|
||||
'azure',
|
||||
'bitbucket',
|
||||
'discord',
|
||||
'facebook',
|
||||
'github',
|
||||
'gitlab',
|
||||
'google',
|
||||
'twitch',
|
||||
'twitter',
|
||||
],
|
||||
socialButtonSize: 'large',
|
||||
}
|
||||
|
||||
withColouredSocialAuth.args = {
|
||||
supabaseClient: supabase,
|
||||
socialColors: true,
|
||||
providers: [
|
||||
'apple',
|
||||
'azure',
|
||||
'bitbucket',
|
||||
'discord',
|
||||
'facebook',
|
||||
'github',
|
||||
'gitlab',
|
||||
'google',
|
||||
'twitch',
|
||||
'twitter',
|
||||
],
|
||||
}
|
||||
|
||||
withSocialAuthHorizontal.args = {
|
||||
supabaseClient: supabase,
|
||||
providers: ['facebook', 'google'],
|
||||
socialLayout: 'horizontal',
|
||||
}
|
||||
|
||||
updatePassword.args = {
|
||||
supabaseClient: supabase,
|
||||
}
|
||||
@@ -1,643 +0,0 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { SupabaseClient, Provider } from '@supabase/supabase-js'
|
||||
import {
|
||||
Input,
|
||||
Checkbox,
|
||||
Button,
|
||||
Space,
|
||||
Typography,
|
||||
Divider,
|
||||
IconKey,
|
||||
IconMail,
|
||||
IconInbox,
|
||||
IconLock,
|
||||
} from './../../index'
|
||||
import { UserContextProvider, useUser } from './UserContext'
|
||||
import * as SocialIcons from './Icons'
|
||||
// @ts-ignore
|
||||
import AuthStyles from './Auth.module.css'
|
||||
|
||||
const VIEWS: ViewsMap = {
|
||||
SIGN_IN: 'sign_in',
|
||||
SIGN_UP: 'sign_up',
|
||||
FORGOTTEN_PASSWORD: 'forgotten_password',
|
||||
MAGIC_LINK: 'magic_link',
|
||||
UPDATE_PASSWORD: 'update_password',
|
||||
}
|
||||
|
||||
interface ViewsMap {
|
||||
[key: string]: ViewType
|
||||
}
|
||||
|
||||
type ViewType =
|
||||
| 'sign_in'
|
||||
| 'sign_up'
|
||||
| 'forgotten_password'
|
||||
| 'magic_link'
|
||||
| 'update_password'
|
||||
|
||||
type RedirectTo = undefined | string
|
||||
|
||||
export interface Props {
|
||||
supabaseClient: SupabaseClient
|
||||
className?: string
|
||||
children?: React.ReactNode
|
||||
style?: React.CSSProperties
|
||||
socialLayout?: 'horizontal' | 'vertical'
|
||||
socialColors?: boolean
|
||||
socialButtonSize?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'
|
||||
providers?: Provider[]
|
||||
verticalSocialLayout?: any
|
||||
view?: ViewType
|
||||
redirectTo?: RedirectTo
|
||||
onlyThirdPartyProviders?: boolean
|
||||
magicLink?: boolean
|
||||
}
|
||||
|
||||
function Auth({
|
||||
supabaseClient,
|
||||
className,
|
||||
style,
|
||||
socialLayout = 'vertical',
|
||||
socialColors = false,
|
||||
socialButtonSize = 'medium',
|
||||
providers,
|
||||
view = 'sign_in',
|
||||
redirectTo,
|
||||
onlyThirdPartyProviders = false,
|
||||
magicLink = false,
|
||||
}: Props): JSX.Element | null {
|
||||
const [authView, setAuthView] = useState(view)
|
||||
const [defaultEmail, setDefaultEmail] = useState('')
|
||||
const [defaultPassword, setDefaultPassword] = useState('')
|
||||
|
||||
const verticalSocialLayout = socialLayout === 'vertical' ? true : false
|
||||
|
||||
let containerClasses = [AuthStyles['sbui-auth']]
|
||||
if (className) {
|
||||
containerClasses.push(className)
|
||||
}
|
||||
|
||||
const Container = (props: any) => (
|
||||
<div className={containerClasses.join(' ')} style={style}>
|
||||
<Space size={8} direction={'vertical'}>
|
||||
<SocialAuth
|
||||
supabaseClient={supabaseClient}
|
||||
verticalSocialLayout={verticalSocialLayout}
|
||||
providers={providers}
|
||||
socialLayout={socialLayout}
|
||||
socialButtonSize={socialButtonSize}
|
||||
socialColors={socialColors}
|
||||
redirectTo={redirectTo}
|
||||
onlyThirdPartyProviders={onlyThirdPartyProviders}
|
||||
magicLink={magicLink}
|
||||
/>
|
||||
{!onlyThirdPartyProviders && props.children}
|
||||
</Space>
|
||||
</div>
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
// handle view override
|
||||
setAuthView(view)
|
||||
}, [view])
|
||||
|
||||
switch (authView) {
|
||||
case VIEWS.SIGN_IN:
|
||||
case VIEWS.SIGN_UP:
|
||||
return (
|
||||
<Container>
|
||||
<EmailAuth
|
||||
id={authView === VIEWS.SIGN_UP ? 'auth-sign-up' : 'auth-sign-in'}
|
||||
supabaseClient={supabaseClient}
|
||||
authView={authView}
|
||||
setAuthView={setAuthView}
|
||||
defaultEmail={defaultEmail}
|
||||
defaultPassword={defaultPassword}
|
||||
setDefaultEmail={setDefaultEmail}
|
||||
setDefaultPassword={setDefaultPassword}
|
||||
redirectTo={redirectTo}
|
||||
magicLink={magicLink}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
case VIEWS.FORGOTTEN_PASSWORD:
|
||||
return (
|
||||
<Container>
|
||||
<ForgottenPassword
|
||||
supabaseClient={supabaseClient}
|
||||
setAuthView={setAuthView}
|
||||
redirectTo={redirectTo}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
|
||||
case VIEWS.MAGIC_LINK:
|
||||
return (
|
||||
<Container>
|
||||
<MagicLink
|
||||
supabaseClient={supabaseClient}
|
||||
setAuthView={setAuthView}
|
||||
redirectTo={redirectTo}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
|
||||
case VIEWS.UPDATE_PASSWORD:
|
||||
return (
|
||||
<Container>
|
||||
<UpdatePassword supabaseClient={supabaseClient} />
|
||||
</Container>
|
||||
)
|
||||
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function SocialAuth({
|
||||
className,
|
||||
style,
|
||||
supabaseClient,
|
||||
children,
|
||||
socialLayout = 'vertical',
|
||||
socialColors = false,
|
||||
socialButtonSize,
|
||||
providers,
|
||||
verticalSocialLayout,
|
||||
redirectTo,
|
||||
onlyThirdPartyProviders,
|
||||
magicLink,
|
||||
...props
|
||||
}: Props) {
|
||||
const buttonStyles: any = {
|
||||
azure: {
|
||||
backgroundColor: '#008AD7',
|
||||
color: 'white',
|
||||
},
|
||||
bitbucket: {
|
||||
backgroundColor: '#205081',
|
||||
color: 'white',
|
||||
},
|
||||
facebook: {
|
||||
backgroundColor: '#4267B2',
|
||||
color: 'white',
|
||||
},
|
||||
github: {
|
||||
backgroundColor: '#333',
|
||||
color: 'white',
|
||||
},
|
||||
gitlab: {
|
||||
backgroundColor: '#FC6D27',
|
||||
},
|
||||
google: {
|
||||
backgroundColor: '#ce4430',
|
||||
color: 'white',
|
||||
},
|
||||
twitter: {
|
||||
backgroundColor: '#1DA1F2',
|
||||
color: 'white',
|
||||
},
|
||||
apple: {
|
||||
backgroundColor: '#000',
|
||||
color: 'white',
|
||||
},
|
||||
discord: {
|
||||
backgroundColor: '#404fec',
|
||||
color: 'white',
|
||||
},
|
||||
twitch: {
|
||||
backgroundColor: '#9146ff',
|
||||
color: 'white',
|
||||
},
|
||||
}
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
|
||||
const handleProviderSignIn = async (provider: Provider) => {
|
||||
setLoading(true)
|
||||
const { error } = await supabaseClient.auth.signIn(
|
||||
{ provider },
|
||||
{ redirectTo }
|
||||
)
|
||||
if (error) setError(error.message)
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Space size={8} direction={'vertical'}>
|
||||
{providers && providers.length > 0 && (
|
||||
<React.Fragment>
|
||||
<Space size={4} direction={'vertical'}>
|
||||
<Typography.Text
|
||||
type="secondary"
|
||||
className={AuthStyles['sbui-auth-label']}
|
||||
>
|
||||
Sign in with
|
||||
</Typography.Text>
|
||||
<Space size={2} direction={socialLayout}>
|
||||
{providers.map((provider) => {
|
||||
// @ts-ignore
|
||||
const AuthIcon = SocialIcons[provider]
|
||||
return (
|
||||
<div
|
||||
key={provider}
|
||||
style={!verticalSocialLayout ? { flexGrow: 1 } : {}}
|
||||
>
|
||||
<Button
|
||||
block
|
||||
type="default"
|
||||
shadow
|
||||
size={socialButtonSize}
|
||||
style={socialColors ? buttonStyles[provider] : {}}
|
||||
icon={<AuthIcon />}
|
||||
loading={loading}
|
||||
onClick={() => handleProviderSignIn(provider)}
|
||||
className="flex items-center"
|
||||
>
|
||||
{verticalSocialLayout && 'Sign up with ' + provider}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Space>
|
||||
</Space>
|
||||
{!onlyThirdPartyProviders && <Divider>or continue with</Divider>}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
|
||||
function EmailAuth({
|
||||
authView,
|
||||
defaultEmail,
|
||||
defaultPassword,
|
||||
id,
|
||||
setAuthView,
|
||||
setDefaultEmail,
|
||||
setDefaultPassword,
|
||||
supabaseClient,
|
||||
redirectTo,
|
||||
magicLink,
|
||||
}: {
|
||||
authView: ViewType
|
||||
defaultEmail: string
|
||||
defaultPassword: string
|
||||
id: 'auth-sign-up' | 'auth-sign-in'
|
||||
setAuthView: any
|
||||
setDefaultEmail: (email: string) => void
|
||||
setDefaultPassword: (password: string) => void
|
||||
supabaseClient: SupabaseClient
|
||||
redirectTo?: RedirectTo
|
||||
magicLink?: boolean
|
||||
}) {
|
||||
const isMounted = useRef<boolean>(true)
|
||||
const [email, setEmail] = useState(defaultEmail)
|
||||
const [password, setPassword] = useState(defaultPassword)
|
||||
const [rememberMe, setRememberMe] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [message, setMessage] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
setEmail(defaultEmail)
|
||||
setPassword(defaultPassword)
|
||||
|
||||
return () => {
|
||||
isMounted.current = false
|
||||
}
|
||||
}, [authView])
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setLoading(true)
|
||||
switch (authView) {
|
||||
case 'sign_in':
|
||||
const { error: signInError } = await supabaseClient.auth.signIn(
|
||||
{
|
||||
email,
|
||||
password,
|
||||
},
|
||||
{ redirectTo }
|
||||
)
|
||||
if (signInError) setError(signInError.message)
|
||||
break
|
||||
case 'sign_up':
|
||||
const { error: signUpError, data: signUpData } =
|
||||
await supabaseClient.auth.signUp(
|
||||
{
|
||||
email,
|
||||
password,
|
||||
},
|
||||
{ redirectTo }
|
||||
)
|
||||
if (signUpError) setError(signUpError.message)
|
||||
// checking if it has access_token to know if email verification is disabled
|
||||
else if (signUpData?.hasOwnProperty('confirmation_sent_at'))
|
||||
setMessage('Check your email for the confirmation link.')
|
||||
break
|
||||
}
|
||||
|
||||
/*
|
||||
* it is possible the auth component may have been unmounted at this point
|
||||
* check if component is mounted before setting a useState
|
||||
*/
|
||||
if (isMounted.current) setLoading(false)
|
||||
}
|
||||
|
||||
const handleViewChange = (newView: ViewType) => {
|
||||
setDefaultEmail(email)
|
||||
setDefaultPassword(password)
|
||||
setAuthView(newView)
|
||||
}
|
||||
|
||||
return (
|
||||
<form id={id} onSubmit={handleSubmit}>
|
||||
<Space size={6} direction={'vertical'}>
|
||||
<Space size={3} direction={'vertical'}>
|
||||
<Input
|
||||
label="Email address"
|
||||
autoComplete="email"
|
||||
defaultValue={email}
|
||||
icon={<IconMail size={21} stroke={'#666666'} />}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setEmail(e.target.value)
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
label="Password"
|
||||
type="password"
|
||||
defaultValue={password}
|
||||
autoComplete="current-password"
|
||||
icon={<IconKey size={21} stroke={'#666666'} />}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setPassword(e.target.value)
|
||||
}
|
||||
/>
|
||||
</Space>
|
||||
<Space direction="vertical" size={6}>
|
||||
<Space style={{ justifyContent: 'space-between' }}>
|
||||
<Checkbox
|
||||
label="Remember me"
|
||||
name="remember_me"
|
||||
id="remember_me"
|
||||
onChange={(value: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setRememberMe(value.target.checked)
|
||||
}
|
||||
/>
|
||||
{authView === VIEWS.SIGN_IN && (
|
||||
<Typography.Link
|
||||
href="#auth-forgot-password"
|
||||
onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault()
|
||||
setAuthView(VIEWS.FORGOTTEN_PASSWORD)
|
||||
}}
|
||||
>
|
||||
Forgot your password?
|
||||
</Typography.Link>
|
||||
)}
|
||||
</Space>
|
||||
<Button
|
||||
htmlType="submit"
|
||||
type="primary"
|
||||
size="large"
|
||||
icon={<IconLock size={21} />}
|
||||
loading={loading}
|
||||
block
|
||||
>
|
||||
{authView === VIEWS.SIGN_IN ? 'Sign in' : 'Sign up'}
|
||||
</Button>
|
||||
</Space>
|
||||
<Space direction="vertical" style={{ textAlign: 'center' }}>
|
||||
{authView === VIEWS.SIGN_IN && magicLink && (
|
||||
<Typography.Link
|
||||
href="#auth-magic-link"
|
||||
onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault()
|
||||
setAuthView(VIEWS.MAGIC_LINK)
|
||||
}}
|
||||
>
|
||||
Sign in with magic link
|
||||
</Typography.Link>
|
||||
)}
|
||||
{authView === VIEWS.SIGN_IN ? (
|
||||
<Typography.Link
|
||||
href="#auth-sign-up"
|
||||
onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault()
|
||||
handleViewChange(VIEWS.SIGN_UP)
|
||||
}}
|
||||
>
|
||||
Don't have an account? Sign up
|
||||
</Typography.Link>
|
||||
) : (
|
||||
<Typography.Link
|
||||
href="#auth-sign-in"
|
||||
onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault()
|
||||
handleViewChange(VIEWS.SIGN_IN)
|
||||
}}
|
||||
>
|
||||
Do you have an account? Sign in
|
||||
</Typography.Link>
|
||||
)}
|
||||
{message && <Typography.Text>{message}</Typography.Text>}
|
||||
{error && <Typography.Text type="danger">{error}</Typography.Text>}
|
||||
</Space>
|
||||
</Space>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function MagicLink({
|
||||
setAuthView,
|
||||
supabaseClient,
|
||||
redirectTo,
|
||||
}: {
|
||||
setAuthView: any
|
||||
supabaseClient: SupabaseClient
|
||||
redirectTo?: RedirectTo
|
||||
}) {
|
||||
const [email, setEmail] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [message, setMessage] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const handleMagicLinkSignIn = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setMessage('')
|
||||
setLoading(true)
|
||||
const { error } = await supabaseClient.auth.signIn(
|
||||
{ email },
|
||||
{ redirectTo }
|
||||
)
|
||||
if (error) setError(error.message)
|
||||
else setMessage('Check your email for the magic link')
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<form id="auth-magic-link" onSubmit={handleMagicLinkSignIn}>
|
||||
<Space size={4} direction={'vertical'}>
|
||||
<Space size={3} direction={'vertical'}>
|
||||
<Input
|
||||
label="Email address"
|
||||
placeholder="Your email address"
|
||||
icon={<IconMail size={21} stroke={'#666666'} />}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setEmail(e.target.value)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
block
|
||||
size="large"
|
||||
htmlType="submit"
|
||||
icon={<IconInbox size={21} />}
|
||||
loading={loading}
|
||||
>
|
||||
Send magic link
|
||||
</Button>
|
||||
</Space>
|
||||
<Typography.Link
|
||||
href="#auth-sign-in"
|
||||
onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault()
|
||||
setAuthView(VIEWS.SIGN_IN)
|
||||
}}
|
||||
>
|
||||
Sign in with password
|
||||
</Typography.Link>
|
||||
{message && <Typography.Text>{message}</Typography.Text>}
|
||||
{error && <Typography.Text type="danger">{error}</Typography.Text>}
|
||||
</Space>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function ForgottenPassword({
|
||||
setAuthView,
|
||||
supabaseClient,
|
||||
redirectTo,
|
||||
}: {
|
||||
setAuthView: any
|
||||
supabaseClient: SupabaseClient
|
||||
redirectTo?: RedirectTo
|
||||
}) {
|
||||
const [email, setEmail] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [message, setMessage] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const handlePasswordReset = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setMessage('')
|
||||
setLoading(true)
|
||||
const { error } = await supabaseClient.auth.api.resetPasswordForEmail(
|
||||
email,
|
||||
{ redirectTo }
|
||||
)
|
||||
if (error) setError(error.message)
|
||||
else setMessage('Check your email for the password reset link')
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<form id="auth-forgot-password" onSubmit={handlePasswordReset}>
|
||||
<Space size={4} direction={'vertical'}>
|
||||
<Space size={3} direction={'vertical'}>
|
||||
<Input
|
||||
label="Email address"
|
||||
placeholder="Your email address"
|
||||
icon={<IconMail size={21} stroke={'#666666'} />}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setEmail(e.target.value)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
block
|
||||
size="large"
|
||||
htmlType="submit"
|
||||
icon={<IconInbox size={21} />}
|
||||
loading={loading}
|
||||
>
|
||||
Send reset password instructions
|
||||
</Button>
|
||||
</Space>
|
||||
<Typography.Link
|
||||
href="#auth-sign-in"
|
||||
onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault()
|
||||
setAuthView(VIEWS.SIGN_IN)
|
||||
}}
|
||||
>
|
||||
Go back to sign in
|
||||
</Typography.Link>
|
||||
{message && <Typography.Text>{message}</Typography.Text>}
|
||||
{error && <Typography.Text type="danger">{error}</Typography.Text>}
|
||||
</Space>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function UpdatePassword({
|
||||
supabaseClient,
|
||||
}: {
|
||||
supabaseClient: SupabaseClient
|
||||
}) {
|
||||
const [password, setPassword] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [message, setMessage] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const handlePasswordReset = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setMessage('')
|
||||
setLoading(true)
|
||||
const { error } = await supabaseClient.auth.update({ password })
|
||||
if (error) setError(error.message)
|
||||
else setMessage('Your password has been updated')
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<form id="auth-update-password" onSubmit={handlePasswordReset}>
|
||||
<Space size={4} direction={'vertical'}>
|
||||
<Space size={3} direction={'vertical'}>
|
||||
<Input
|
||||
label="New password"
|
||||
placeholder="Enter your new password"
|
||||
type="password"
|
||||
icon={<IconKey size={21} stroke={'#666666'} />}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setPassword(e.target.value)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
block
|
||||
size="large"
|
||||
htmlType="submit"
|
||||
icon={<IconKey size={21} />}
|
||||
loading={loading}
|
||||
>
|
||||
Update password
|
||||
</Button>
|
||||
</Space>
|
||||
{message && <Typography.Text>{message}</Typography.Text>}
|
||||
{error && <Typography.Text type="danger">{error}</Typography.Text>}
|
||||
</Space>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
Auth.ForgottenPassword = ForgottenPassword
|
||||
Auth.UpdatePassword = UpdatePassword
|
||||
Auth.MagicLink = MagicLink
|
||||
Auth.UserContextProvider = UserContextProvider
|
||||
Auth.useUser = useUser
|
||||
|
||||
export default Auth
|
||||
@@ -1,236 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const size = 21
|
||||
|
||||
export const google = () => (
|
||||
<svg
|
||||
width={size}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fab"
|
||||
data-icon="google"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 488 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const facebook = () => (
|
||||
<svg
|
||||
width={size}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fab"
|
||||
data-icon="facebook-square"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M400 32H48A48 48 0 0 0 0 80v352a48 48 0 0 0 48 48h137.25V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.27c-30.81 0-40.42 19.12-40.42 38.73V256h68.78l-11 71.69h-57.78V480H400a48 48 0 0 0 48-48V80a48 48 0 0 0-48-48z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const twitter = () => (
|
||||
<svg
|
||||
width={size}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fab"
|
||||
data-icon="twitter"
|
||||
className="svg-inline--fa fa-twitter fa-w-16"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const apple = () => (
|
||||
<svg
|
||||
width={size}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fab"
|
||||
data-icon="apple"
|
||||
className="svg-inline--fa fa-apple fa-w-16"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const github = () => (
|
||||
<svg
|
||||
width={size}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fab"
|
||||
data-icon="github"
|
||||
className="svg-inline--fa fa-github fa-w-16"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 496 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const gitlab = () => (
|
||||
<svg
|
||||
width={size}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fab"
|
||||
data-icon="gitlab"
|
||||
className="svg-inline--fa fa-gitlab fa-w-16"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M105.2 24.9c-3.1-8.9-15.7-8.9-18.9 0L29.8 199.7h132c-.1 0-56.6-174.8-56.6-174.8zM.9 287.7c-2.6 8 .3 16.9 7.1 22l247.9 184-226.2-294zm160.8-88l94.3 294 94.3-294zm349.4 88l-28.8-88-226.3 294 247.9-184c6.9-5.1 9.7-14 7.2-22zM425.7 24.9c-3.1-8.9-15.7-8.9-18.9 0l-56.6 174.8h132z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
export const bitbucket = () => (
|
||||
<svg
|
||||
width={size}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fab"
|
||||
data-icon="bitbucket"
|
||||
className="svg-inline--fa fa-bitbucket fa-w-16"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22.2 32A16 16 0 0 0 6 47.8a26.35 26.35 0 0 0 .2 2.8l67.9 412.1a21.77 21.77 0 0 0 21.3 18.2h325.7a16 16 0 0 0 16-13.4L505 50.7a16 16 0 0 0-13.2-18.3 24.58 24.58 0 0 0-2.8-.2L22.2 32zm285.9 297.8h-104l-28.1-147h157.3l-25.2 147z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const discord = () => (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 71 55"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0)">
|
||||
<path
|
||||
d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const azure = () => (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 96 96"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="e399c19f-b68f-429d-b176-18c2117ff73c"
|
||||
x1="-1032.172"
|
||||
x2="-1059.213"
|
||||
y1="145.312"
|
||||
y2="65.426"
|
||||
gradientTransform="matrix(1 0 0 -1 1075 158)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#fff"></stop>
|
||||
<stop offset="1" stopColor="#fff"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="ac2a6fc2-ca48-4327-9a3c-d4dcc3256e15"
|
||||
x1="-1023.725"
|
||||
x2="-1029.98"
|
||||
y1="108.083"
|
||||
y2="105.968"
|
||||
gradientTransform="matrix(1 0 0 -1 1075 158)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopOpacity=".3"></stop>
|
||||
<stop offset=".071" stopOpacity=".2"></stop>
|
||||
<stop offset=".321" stopOpacity=".1"></stop>
|
||||
<stop offset=".623" stopOpacity=".05"></stop>
|
||||
<stop offset="1" stopOpacity="0"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="a7fee970-a784-4bb1-af8d-63d18e5f7db9"
|
||||
x1="-1027.165"
|
||||
x2="-997.482"
|
||||
y1="147.642"
|
||||
y2="68.561"
|
||||
gradientTransform="matrix(1 0 0 -1 1075 158)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#fff"></stop>
|
||||
<stop offset="1" stopColor="#fff"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path
|
||||
fill="url(#e399c19f-b68f-429d-b176-18c2117ff73c)"
|
||||
d="M33.338 6.544h26.038l-27.03 80.087a4.152 4.152 0 0 1-3.933 2.824H8.149a4.145 4.145 0 0 1-3.928-5.47L29.404 9.368a4.152 4.152 0 0 1 3.934-2.825z"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M71.175 60.261h-41.29a1.911 1.911 0 0 0-1.305 3.309l26.532 24.764a4.171 4.171 0 0 0 2.846 1.121h23.38z"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M33.338 6.544a4.118 4.118 0 0 0-3.943 2.879L4.252 83.917a4.14 4.14 0 0 0 3.908 5.538h20.787a4.443 4.443 0 0 0 3.41-2.9l5.014-14.777 17.91 16.705a4.237 4.237 0 0 0 2.666.972H81.24L71.024 60.261l-29.781.007L59.47 6.544z"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M66.595 9.364a4.145 4.145 0 0 0-3.928-2.82H33.648a4.146 4.146 0 0 1 3.928 2.82l25.184 74.62a4.146 4.146 0 0 1-3.928 5.472h29.02a4.146 4.146 0 0 0 3.927-5.472z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const twitch = () => (
|
||||
<svg
|
||||
width={size}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fab"
|
||||
data-icon="twitch"
|
||||
className="svg-inline--fa fa-twitch fa-w-16"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M391.17,103.47H352.54v109.7h38.63ZM285,103H246.37V212.75H285ZM120.83,0,24.31,91.42V420.58H140.14V512l96.53-91.42h77.25L487.69,256V0ZM449.07,237.75l-77.22,73.12H294.61l-67.6,64v-64H140.14V36.58H449.07Z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
@@ -1,50 +0,0 @@
|
||||
import React, { useEffect, useState, createContext, useContext } from 'react'
|
||||
import { SupabaseClient, Session, User } from '@supabase/supabase-js'
|
||||
|
||||
export interface AuthSession {
|
||||
user: User | null
|
||||
session: Session | null
|
||||
}
|
||||
|
||||
const UserContext = createContext<AuthSession>({ user: null, session: null })
|
||||
|
||||
export interface Props {
|
||||
supabaseClient: SupabaseClient
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
export const UserContextProvider = (props: Props) => {
|
||||
const { supabaseClient } = props
|
||||
const [session, setSession] = useState<Session | null>(
|
||||
supabaseClient.auth.session()
|
||||
)
|
||||
const [user, setUser] = useState<User | null>(session?.user ?? null)
|
||||
|
||||
useEffect(() => {
|
||||
const { data: authListener } = supabaseClient.auth.onAuthStateChange(
|
||||
async (event, session) => {
|
||||
setSession(session)
|
||||
setUser(session?.user ?? null)
|
||||
}
|
||||
)
|
||||
|
||||
return () => {
|
||||
authListener?.unsubscribe()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
const value = {
|
||||
session,
|
||||
user,
|
||||
}
|
||||
return <UserContext.Provider value={value} {...props} />
|
||||
}
|
||||
|
||||
export const useUser = () => {
|
||||
const context = useContext(UserContext)
|
||||
if (context === undefined) {
|
||||
throw new Error(`useUser must be used within a UserContextProvider.`)
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default as Auth } from './Auth'
|
||||
@@ -1,13 +0,0 @@
|
||||
// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import React from 'react'
|
||||
// @ts-ignore
|
||||
import { Activity } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
|
||||
function IconActivity(props: any) {
|
||||
return <IconBase icon={Activity} {...props} />
|
||||
}
|
||||
|
||||
export default IconActivity
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"extends": "tsconfig/react-library.json",
|
||||
"include": ["."],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,3 +1,5 @@
|
||||
import * as React from 'react'
|
||||
|
||||
// // GENERAL
|
||||
|
||||
export * from './src/components/Button'
|
||||
@@ -13,6 +15,7 @@ export * from './src/components/Tabs'
|
||||
export * from './src/components/Alert'
|
||||
export * from './src/components/Accordion'
|
||||
export * from './src/components/Collapsible'
|
||||
// export * from './src/components/Breadcrumb'
|
||||
|
||||
// NAV
|
||||
|
||||
@@ -208,7 +211,7 @@ export * from './src/components/Icon/icons/IconLink'
|
||||
export * from './src/components/Icon/icons/IconLinkedin'
|
||||
export * from './src/components/Icon/icons/IconList'
|
||||
export * from './src/components/Icon/icons/IconLoader'
|
||||
export * from './src/components/Icon/icons/IconLoader'
|
||||
export * from './src/components/Icon/icons/IconLock'
|
||||
export * from './src/components/Icon/icons/IconLogIn'
|
||||
export * from './src/components/Icon/icons/IconLogOut'
|
||||
export * from './src/components/Icon/icons/IconMail'
|
||||
File renamed without changes.
File renamed without changes.
+1
-1
@@ -31,7 +31,7 @@ Object.values(icons).map((icon) => {
|
||||
`${dir}/Icon${icon.name}.tsx`,
|
||||
`// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import React from 'react'
|
||||
import * as React from 'react'
|
||||
// @ts-ignore
|
||||
import { ${icon.name} } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "common2",
|
||||
"name": "ui",
|
||||
"version": "0.0.0",
|
||||
"main": "./index.tsx",
|
||||
"types": "./index.tsx",
|
||||
@@ -27,14 +27,13 @@
|
||||
"lodash": "^4.17.20",
|
||||
"postcss": "^8.4.5",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-feather": "^2.0.10",
|
||||
"tailwindcss": "^3.0.15",
|
||||
"tailwindcss-radix": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.37",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"config": "*",
|
||||
"tsconfig": "*",
|
||||
"typescript": "^4.5.3"
|
||||
"typescript": "4.3.4"
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+12
-23
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
|
||||
import { Alert } from './../../index'
|
||||
import { Alert } from './../../../'
|
||||
|
||||
// import ThemeProvider from '../../theme/themeContext'
|
||||
|
||||
@@ -11,78 +11,67 @@ export default {
|
||||
|
||||
export const Neutral = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const Success = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const SuccessWithIcon = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const Danger = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const DangerWithIcon = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const Info = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const InfoWithIcon = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const Warning = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const WarningWithIcon = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const Closable = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
export const WithAction = (args: any) => (
|
||||
<Alert {...args}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet
|
||||
labore.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur amet labore.
|
||||
</Alert>
|
||||
)
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
-6
@@ -1,16 +1,12 @@
|
||||
import React from 'react'
|
||||
import { Breadcrumb } from '../Breadcrumb'
|
||||
import { Textarea } from '../Textarea'
|
||||
import Typography from '../Typography'
|
||||
import { Breadcrumb } from './../../../'
|
||||
|
||||
export default {
|
||||
title: 'Navigation/Breadcrumb',
|
||||
component: Breadcrumb,
|
||||
}
|
||||
|
||||
export const Default = ({ children, ...args }) => (
|
||||
<Breadcrumb {...args}>{children}</Breadcrumb>
|
||||
)
|
||||
export const Default = ({ children, ...args }: any) => <Breadcrumb {...args}>{children}</Breadcrumb>
|
||||
|
||||
Default.args = {
|
||||
children: [
|
||||
File renamed without changes.
+2
-11
@@ -9,12 +9,7 @@ interface Props {
|
||||
spacing?: 'small' | 'medium' | 'large'
|
||||
}
|
||||
|
||||
const Breadcrumb = ({
|
||||
className,
|
||||
style,
|
||||
children,
|
||||
spacing = 'small',
|
||||
}: Props) => {
|
||||
const Breadcrumb = ({ className, style, children, spacing = 'small' }: Props) => {
|
||||
let classes = [BreadcrumbStyle['sbui-breadcrumb--container']]
|
||||
let seperatorClasses = [BreadcrumbStyle['sbui-breadcrumb--separator']]
|
||||
|
||||
@@ -32,11 +27,7 @@ const Breadcrumb = ({
|
||||
<li className={BreadcrumbStyle['sbui-breadcrumb--item-container']}>
|
||||
{child}
|
||||
{idx + 1 < children!.length && (
|
||||
<IconChevronRight
|
||||
size={12}
|
||||
className={seperatorClasses.join(' ')}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<IconChevronRight size={12} className={seperatorClasses.join(' ')} aria-hidden="true" />
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -119,7 +119,7 @@ export const Button = forwardRef<RefHandle, ButtonProps>(
|
||||
const iconLoaderClasses = [__styles.loading]
|
||||
|
||||
// custom button tag
|
||||
const CustomButton: React.FC<CustomButtonProps> = ({ ...props }) => {
|
||||
const CustomButton = ({ ...props }) => {
|
||||
const Tag = as as keyof JSX.IntrinsicElements
|
||||
return <Tag {...props} />
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+4
-19
@@ -9,8 +9,7 @@ import defaultTheme from '../../lib/theme/defaultTheme'
|
||||
import { useFormContext } from '../Form/FormContext'
|
||||
import styleHandler from '../../lib/theme/styleHandler'
|
||||
|
||||
export interface InputProps
|
||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
||||
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
||||
afterLabel?: string
|
||||
beforeLabel?: string
|
||||
description?: string
|
||||
@@ -106,7 +105,6 @@ export function Checkbox({
|
||||
checked,
|
||||
value,
|
||||
onChange,
|
||||
onFocus,
|
||||
onBlur,
|
||||
size = 'medium',
|
||||
disabled = false,
|
||||
@@ -170,10 +168,8 @@ export function Checkbox({
|
||||
id={markupId}
|
||||
name={markupName}
|
||||
type="checkbox"
|
||||
// className={CheckboxStyles['sbui-checkbox']}
|
||||
className={[__styles.base, __styles.size[size]].join(' ')}
|
||||
onChange={onInputChange}
|
||||
onFocus={onFocus ? (event) => onFocus(event) : undefined}
|
||||
onBlur={handleBlurEvent}
|
||||
checked={active}
|
||||
value={value ? value : markupId}
|
||||
@@ -188,10 +184,7 @@ export function Checkbox({
|
||||
<span>
|
||||
{beforeLabel && (
|
||||
<span
|
||||
className={[
|
||||
__styles.label_before.base,
|
||||
__styles.label_before[size],
|
||||
].join(' ')}
|
||||
className={[__styles.label_before.base, __styles.label_before[size]].join(' ')}
|
||||
>
|
||||
{beforeLabel}
|
||||
</span>
|
||||
@@ -199,10 +192,7 @@ export function Checkbox({
|
||||
{label}
|
||||
{afterLabel && (
|
||||
<span
|
||||
className={[
|
||||
__styles.label_after.base,
|
||||
__styles.label_after[size],
|
||||
].join(' ')}
|
||||
className={[__styles.label_after.base, __styles.label_after[size]].join(' ')}
|
||||
>
|
||||
{afterLabel}
|
||||
</span>
|
||||
@@ -210,12 +200,7 @@ export function Checkbox({
|
||||
</span>
|
||||
|
||||
{description && (
|
||||
<p
|
||||
className={[
|
||||
__styles.description.base,
|
||||
__styles.description[size],
|
||||
].join(' ')}
|
||||
>
|
||||
<p className={[__styles.description.base, __styles.description[size]].join(' ')}>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+4
-18
@@ -1,7 +1,5 @@
|
||||
import React from 'react'
|
||||
import * as RadixCollapsible from '@radix-ui/react-collapsible'
|
||||
import { Button } from '../Button'
|
||||
import { IconChevronRight, IconGlobe } from '../..'
|
||||
import React from 'react'
|
||||
import styleHandler from '../../lib/theme/styleHandler'
|
||||
|
||||
export interface CollapsibleProps extends RadixCollapsible.CollapsibleProps {
|
||||
@@ -34,18 +32,8 @@ export const Collapsible = ({
|
||||
)
|
||||
}
|
||||
|
||||
export function Trigger({
|
||||
children,
|
||||
asChild,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
asChild?: boolean
|
||||
}) {
|
||||
return (
|
||||
<RadixCollapsible.Trigger asChild={asChild}>
|
||||
{children}
|
||||
</RadixCollapsible.Trigger>
|
||||
)
|
||||
export function Trigger({ children, asChild }: { children: React.ReactNode; asChild?: boolean }) {
|
||||
return <RadixCollapsible.Trigger asChild={asChild}>{children}</RadixCollapsible.Trigger>
|
||||
}
|
||||
|
||||
export function Content({
|
||||
@@ -57,9 +45,7 @@ export function Content({
|
||||
}) {
|
||||
const __styles = styleHandler('collapsible')
|
||||
return (
|
||||
<RadixCollapsible.Content
|
||||
className={[__styles.content, className].join(' ')}
|
||||
>
|
||||
<RadixCollapsible.Content className={[__styles.content, className].join(' ')}>
|
||||
{children}
|
||||
</RadixCollapsible.Content>
|
||||
)
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+162
-234
@@ -1,30 +1,23 @@
|
||||
import React, { useEffect, useReducer, useState } from 'react'
|
||||
import { Form } from './../'
|
||||
import React, { useReducer, useState } from 'react'
|
||||
import {
|
||||
Input,
|
||||
Button,
|
||||
InputNumber,
|
||||
Toggle,
|
||||
Checkbox,
|
||||
Radio,
|
||||
Select,
|
||||
Listbox,
|
||||
IconChevronUp,
|
||||
IconCheckCircle,
|
||||
IconCheck,
|
||||
IconArrowRight,
|
||||
IconX,
|
||||
Tabs,
|
||||
IconCheck,
|
||||
IconChevronUp,
|
||||
IconGlobe,
|
||||
IconTrash,
|
||||
IconAlertCircle,
|
||||
} from '../../../index'
|
||||
IconX,
|
||||
Input,
|
||||
InputNumber,
|
||||
Tabs,
|
||||
Toggle,
|
||||
} from '../../../../'
|
||||
import { Form } from './../'
|
||||
|
||||
import * as Yup from 'yup'
|
||||
import { Collapsible } from '../../Collapsible'
|
||||
|
||||
import AuthFormSchema from './AuthFormSchema.json'
|
||||
import { Modal } from '../../Modal'
|
||||
import AuthFormSchema from './AuthFormSchema.json'
|
||||
|
||||
// import GoogleIcon './../../../static/icons/google-icon.svg'
|
||||
|
||||
@@ -32,36 +25,33 @@ const DocsButton = () => {
|
||||
return (
|
||||
<button
|
||||
className="
|
||||
group
|
||||
w-full
|
||||
bg-scale-300
|
||||
dark:bg-scale-100
|
||||
border
|
||||
border-scale-500 hover:border-scale-700
|
||||
dark:border-scale-300 dark:hover:border-scale-500
|
||||
px-6 py-4
|
||||
my-6
|
||||
flex gap-6 items-center
|
||||
rounded-md shadow-sm
|
||||
bg-scale-300
|
||||
dark:bg-scale-100
|
||||
border-scale-500
|
||||
hover:border-scale-700
|
||||
dark:border-scale-300
|
||||
dark:hover:border-scale-500 group
|
||||
my-6 flex
|
||||
w-full items-center
|
||||
gap-6
|
||||
rounded-md border px-6
|
||||
py-4 text-left
|
||||
shadow-sm
|
||||
transition
|
||||
text-left
|
||||
"
|
||||
>
|
||||
<div className="transition duration-500 bg-brand-900 rounded p-1 w-10 h-10 group-hover:-rotate-3 group-hover:scale-110">
|
||||
<div className="bg-brand-900 h-10 w-10 rounded p-1 transition duration-500 group-hover:-rotate-3 group-hover:scale-110">
|
||||
{/* <img
|
||||
className="text-white w-12 h-12"
|
||||
src="/icons/docs-illustration.svg"
|
||||
/> */}
|
||||
</div>
|
||||
<div className="grow">
|
||||
<h3 className="text-scale-1200">
|
||||
Use authentication as the backbone of your app
|
||||
</h3>
|
||||
<h3 className="text-scale-1200">Use authentication as the backbone of your app</h3>
|
||||
<p className="text-scale-900 text-xs">
|
||||
Learn how to use Supabase Auth with Auth Policies to pick and choose
|
||||
what users see what.
|
||||
Learn how to use Supabase Auth with Auth Policies to pick and choose what users see what.
|
||||
</p>
|
||||
<p className="text-brand-900 mt-2 text-xs flex items-center gap-1">
|
||||
<p className="text-brand-900 mt-2 flex items-center gap-1 text-xs">
|
||||
See Documenation
|
||||
<span className="transition group-hover:translate-x-1">
|
||||
<IconArrowRight strokeWidth={2} width={12} />
|
||||
@@ -91,10 +81,10 @@ const CardForm = () => {
|
||||
bg-scale-100
|
||||
dark:bg-scale-300
|
||||
|
||||
border border-scale-400 rounded-md my-8 shadow overflow-hidden"
|
||||
border-scale-400 my-8 overflow-hidden rounded-md border shadow"
|
||||
>
|
||||
{header && (
|
||||
<div className="bg-scale-100 dark:bg-scale-200 px-8 py-4 border-b border-scale-400">
|
||||
<div className="bg-scale-100 dark:bg-scale-200 border-scale-400 border-b px-8 py-4">
|
||||
{header}
|
||||
</div>
|
||||
)}
|
||||
@@ -146,13 +136,9 @@ const CardForm = () => {
|
||||
<Panel
|
||||
footer={
|
||||
<>
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="py-3 px-6 flex gap-2 justify-end">
|
||||
<Button
|
||||
type="default"
|
||||
htmlType="reset"
|
||||
onClick={() => handleReset()}
|
||||
>
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
<div className="flex justify-end gap-2 py-3 px-6">
|
||||
<Button type="default" htmlType="reset" onClick={() => handleReset()}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
@@ -168,11 +154,7 @@ const CardForm = () => {
|
||||
}
|
||||
>
|
||||
<Section
|
||||
header={
|
||||
<label className="text-sm text-scale-1200 col-span-4">
|
||||
User Signups
|
||||
</label>
|
||||
}
|
||||
header={<label className="text-scale-1200 col-span-4 text-sm">User Signups</label>}
|
||||
>
|
||||
<Toggle
|
||||
id="enable_signups"
|
||||
@@ -182,13 +164,9 @@ const CardForm = () => {
|
||||
descriptionText="If this is disabled, new users will not be able to sign up to your application."
|
||||
/>
|
||||
</Section>
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
<Section
|
||||
header={
|
||||
<label className="text-sm text-scale-1200 col-span-4">
|
||||
User Sessions
|
||||
</label>
|
||||
}
|
||||
header={<label className="text-scale-1200 col-span-4 text-sm">User Sessions</label>}
|
||||
>
|
||||
<InputNumber
|
||||
className="col-span-8"
|
||||
@@ -208,8 +186,7 @@ const CardForm = () => {
|
||||
let initialState: any = {}
|
||||
|
||||
AuthFormSchema.map((provider) => {
|
||||
initialState[`${provider.name.toLowerCase()}-active`] =
|
||||
provider.name == 'Email' ? true : false
|
||||
initialState[`${provider.name.toLowerCase()}-active`] = provider.name == 'Email' ? true : false
|
||||
initialState[`${provider.name.toLowerCase()}-app-id`] = ''
|
||||
initialState[`${provider.name.toLowerCase()}-id-key`] = ''
|
||||
})
|
||||
@@ -228,10 +205,7 @@ function providersReducer(state, action) {
|
||||
}
|
||||
|
||||
const AuthForm = () => {
|
||||
const [providersFormState, dispatchProvidersForm] = useReducer(
|
||||
providersReducer,
|
||||
initialState
|
||||
)
|
||||
const [providersFormState, dispatchProvidersForm] = useReducer(providersReducer, initialState)
|
||||
|
||||
console.log('providersFormState from useState', providersFormState)
|
||||
|
||||
@@ -245,9 +219,9 @@ const AuthForm = () => {
|
||||
header?: React.ReactNode
|
||||
footer?: React.ReactNode
|
||||
}) => (
|
||||
<div className="bg-scale-300 border border-scale-400 rounded-md w-3/4 mx-auto my-8 shadow overflow-hidden">
|
||||
<div className="bg-scale-300 border-scale-400 mx-auto my-8 w-3/4 overflow-hidden rounded-md border shadow">
|
||||
{header && (
|
||||
<div className="bg-scale-100 dark:bg-scale-200 px-8 py-4 border-b border-scale-400">
|
||||
<div className="bg-scale-100 dark:bg-scale-200 border-scale-400 border-b px-8 py-4">
|
||||
{header}
|
||||
</div>
|
||||
)}
|
||||
@@ -279,12 +253,12 @@ const AuthForm = () => {
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
bg-scale-400 border border-scale-500 mx-auto shadow overflow-hidden
|
||||
first:rounded-tr first:rounded-tl
|
||||
last:rounded-br last:rounded-bl
|
||||
hover:border-scale-700
|
||||
hover:bg-scale-500
|
||||
transition
|
||||
bg-scale-400 border-scale-500 hover:border-scale-700 hover:bg-scale-500 mx-auto overflow-hidden
|
||||
border shadow
|
||||
transition first:rounded-tr
|
||||
first:rounded-tl
|
||||
last:rounded-br
|
||||
last:rounded-bl
|
||||
"
|
||||
>
|
||||
{children}
|
||||
@@ -322,19 +296,19 @@ const AuthForm = () => {
|
||||
bg-scale-100 dark:bg-scale-300
|
||||
hover:bg-scale-200 dark:hover:bg-scale-500
|
||||
data-open:bg-scale-200 dark:data-open:bg-scale-500
|
||||
border
|
||||
border-scale-300 dark:border-scale-500
|
||||
hover:border-scale-500 dark:hover:border-scale-700
|
||||
border-scale-300
|
||||
dark:border-scale-500 hover:border-scale-500
|
||||
dark:hover:border-scale-700 data-open:border-scale-700
|
||||
|
||||
mx-auto shadow overflow-hidden
|
||||
first:rounded-tr first:rounded-tl
|
||||
last:rounded-br last:rounded-bl
|
||||
data-open:pb-px col-span-12 mx-auto
|
||||
-space-y-px overflow-hidden
|
||||
border shadow
|
||||
|
||||
data-open:border-scale-700
|
||||
data-open:pb-px
|
||||
|
||||
transition
|
||||
-space-y-px col-span-12
|
||||
first:rounded-tr
|
||||
|
||||
first:rounded-tl
|
||||
last:rounded-br last:rounded-bl
|
||||
hover:z-50
|
||||
"
|
||||
>
|
||||
@@ -343,13 +317,13 @@ const AuthForm = () => {
|
||||
type="button"
|
||||
className="
|
||||
|
||||
group text-scale-1200
|
||||
text-scale-1200 group
|
||||
flex
|
||||
justify-between items-center w-full rounded p-3 px-6"
|
||||
w-full items-center justify-between rounded p-3 px-6"
|
||||
>
|
||||
<div className="flex gap-3 items-center">
|
||||
<div className="flex items-center gap-3">
|
||||
<IconChevronUp
|
||||
className="text-scale-800 transition data-open-parent:rotate-0 data-closed-parent:rotate-180"
|
||||
className="text-scale-800 data-open-parent:rotate-0 data-closed-parent:rotate-180 transition"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
|
||||
@@ -362,16 +336,16 @@ const AuthForm = () => {
|
||||
|
||||
<span className="text-base">{provider.name}</span>
|
||||
</div>
|
||||
<div className="flex gap-3 items-center">
|
||||
<div className="flex items-center gap-3">
|
||||
{active ? (
|
||||
<div className="bg-brand-200 border border-brand-700 py-1 px-1 text-brand-900 text-xs rounded-full flex gap-1 items-center">
|
||||
<span className="text-xs bg-brand-900 rounded-full p-0.5 text-brand-200">
|
||||
<div className="bg-brand-200 border-brand-700 text-brand-900 flex items-center gap-1 rounded-full border py-1 px-1 text-xs">
|
||||
<span className="bg-brand-900 text-brand-200 rounded-full p-0.5 text-xs">
|
||||
<IconCheck strokeWidth={2} size={12} />
|
||||
</span>
|
||||
<span className="px-1">Enabled</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-scale-100 dark:bg-scale-300 border border-scale-500 dark:border-scale-700 py-1 px-3 text-scale-900 text-xs rounded-md">
|
||||
<div className="bg-scale-100 dark:bg-scale-300 border-scale-500 dark:border-scale-700 text-scale-900 rounded-md border py-1 px-3 text-xs">
|
||||
Disabled
|
||||
</div>
|
||||
)}
|
||||
@@ -400,11 +374,9 @@ const AuthForm = () => {
|
||||
const input_id_key = `${provider.name.toLowerCase()}-id-key`
|
||||
|
||||
if (values[input_app_id] && values[input_app_id].length < 10)
|
||||
errors[input_app_id] =
|
||||
'App ID must be at least 10 characters long'
|
||||
errors[input_app_id] = 'App ID must be at least 10 characters long'
|
||||
if (values[input_app_id] && values[input_id_key].length < 10)
|
||||
errors[input_id_key] =
|
||||
'Secret must be at least 10 characters long'
|
||||
errors[input_id_key] = 'Secret must be at least 10 characters long'
|
||||
|
||||
if (values[input_active]) {
|
||||
if (!values[input_app_id])
|
||||
@@ -432,17 +404,17 @@ const AuthForm = () => {
|
||||
<div
|
||||
className="
|
||||
bg-scale-100 dark:bg-scale-300
|
||||
group text-scale-1200 border-t border-scale-500 py-6 px-6
|
||||
text-scale-1200 border-scale-500 group border-t py-6 px-6
|
||||
"
|
||||
>
|
||||
<div className="space-y-6 max-w-md mx-auto">
|
||||
<div className="mx-auto max-w-md space-y-6">
|
||||
<Toggle
|
||||
id={`${provider.name.toLowerCase()}-active`}
|
||||
name={`${provider.name.toLowerCase()}-active`}
|
||||
label={`Enable ${provider.name} Provider`}
|
||||
layout="flex"
|
||||
/>
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
{provider.form.map((x) => {
|
||||
return (
|
||||
<Input
|
||||
@@ -455,8 +427,8 @@ const AuthForm = () => {
|
||||
/>
|
||||
)
|
||||
})}
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="flex items-center gap-3 justify-end">
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
<Button
|
||||
htmlType="reset"
|
||||
onClick={() => {
|
||||
@@ -493,10 +465,7 @@ const AuthForm = () => {
|
||||
}
|
||||
|
||||
// type to do later..
|
||||
let domainInitialState: any = [
|
||||
'https://summersmuir.com',
|
||||
'http://localhost:3000',
|
||||
]
|
||||
let domainInitialState: any = ['https://summersmuir.com', 'http://localhost:3000']
|
||||
|
||||
// AuthFormSchema.map((provider) => {
|
||||
// domainInitialState[`${provider.name.toLowerCase()}-active`] =
|
||||
@@ -548,10 +517,7 @@ function domainsReducer(state, action) {
|
||||
}
|
||||
|
||||
const DomainsForm = () => {
|
||||
const [domainsFormState, dispatchDomainsForm] = useReducer(
|
||||
domainsReducer,
|
||||
domainInitialState
|
||||
)
|
||||
const [domainsFormState, dispatchDomainsForm] = useReducer(domainsReducer, domainInitialState)
|
||||
|
||||
const [deleteOpen, setDeleteOpen] = useState(false)
|
||||
const [deleteLoading, setDeleteLoading] = useState(false)
|
||||
@@ -582,18 +548,14 @@ const DomainsForm = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center justify-between my-6">
|
||||
<div className="my-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-scale-1200 text-2xl mb-2">
|
||||
Authorised domains
|
||||
</h3>
|
||||
<p className="text-sm text-scale-900">
|
||||
Turn payment methods on and off in one click – no engineering time
|
||||
required.
|
||||
<h3 className="text-scale-1200 mb-2 text-2xl">Authorised domains</h3>
|
||||
<p className="text-scale-900 text-sm">
|
||||
Turn payment methods on and off in one click – no engineering time required.
|
||||
</p>
|
||||
<p className="text-sm text-scale-900">
|
||||
Use our guide to check which payment methods are compatible with
|
||||
your integration.
|
||||
<p className="text-scale-900 text-sm">
|
||||
Use our guide to check which payment methods are compatible with your integration.
|
||||
</p>
|
||||
</div>
|
||||
<Button onClick={() => setOpen(true)}>Add domain</Button>
|
||||
@@ -602,7 +564,7 @@ const DomainsForm = () => {
|
||||
visible={open}
|
||||
onCancel={() => setOpen(!open)}
|
||||
header={
|
||||
<div className="flex items-center gap-2 text-scale-1200">
|
||||
<div className="text-scale-1200 flex items-center gap-2">
|
||||
<div className="flex items-baseline gap-2">
|
||||
<h3 className="text-sm">Add a new domain</h3>
|
||||
</div>
|
||||
@@ -634,8 +596,7 @@ const DomainsForm = () => {
|
||||
values.domain
|
||||
)
|
||||
) {
|
||||
errors.domain =
|
||||
'Not a valid URL. Please use http:// or https://'
|
||||
errors.domain = 'Not a valid URL. Please use http:// or https://'
|
||||
}
|
||||
return errors
|
||||
}}
|
||||
@@ -644,15 +605,14 @@ const DomainsForm = () => {
|
||||
// console.log('errors in form', errors)
|
||||
// console.log('touched in form', touched)
|
||||
return (
|
||||
<div className="space-y-4 pt-4 mb-4">
|
||||
<div className="mb-4 space-y-4 pt-4">
|
||||
<div className="px-5">
|
||||
<p className="text-sm text-scale-1100">
|
||||
This will add a domain to a list of allowed domains that
|
||||
can interact with your Authenticaton services for this
|
||||
project.
|
||||
<p className="text-scale-1100 text-sm">
|
||||
This will add a domain to a list of allowed domains that can interact with
|
||||
your Authenticaton services for this project.
|
||||
</p>
|
||||
</div>
|
||||
<div className="border-t border-overlay-border"></div>
|
||||
<div className="border-overlay-border border-t"></div>
|
||||
<div className="px-5">
|
||||
<Input
|
||||
id="domain"
|
||||
@@ -661,7 +621,7 @@ const DomainsForm = () => {
|
||||
placeholder="https://mydomain.com"
|
||||
/>
|
||||
</div>
|
||||
<div className="border-t border-overlay-border"></div>
|
||||
<div className="border-overlay-border border-t"></div>
|
||||
<div className="px-5">
|
||||
<Button
|
||||
form="new-domain-form"
|
||||
@@ -693,14 +653,14 @@ const DomainsForm = () => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="bg-scale-300 px-6 py-4 border border-scale-500
|
||||
first:rounded-tr first:rounded-tl
|
||||
last:rounded-br last:rounded-bl
|
||||
text-sm text-scale-1200
|
||||
flex gap-2 items-center justify-between
|
||||
className="bg-scale-300 border-scale-500 text-scale-1200 flex items-center
|
||||
justify-between gap-2
|
||||
border px-6
|
||||
py-4 text-sm
|
||||
first:rounded-tr first:rounded-tl last:rounded-br last:rounded-bl
|
||||
"
|
||||
>
|
||||
<div className="flex gap-2 items-center font-mono">
|
||||
<div className="flex items-center gap-2 font-mono">
|
||||
<span className="text-scale-900">
|
||||
<IconGlobe strokeWidth={2} size={14} />
|
||||
</span>
|
||||
@@ -726,7 +686,7 @@ const DomainsForm = () => {
|
||||
visible={deleteOpen}
|
||||
onCancel={() => setDeleteOpen(!open)}
|
||||
header={
|
||||
<div className="flex items-center gap-2 text-scale-1200">
|
||||
<div className="text-scale-1200 flex items-center gap-2">
|
||||
<div className="flex items-baseline gap-2">
|
||||
<h3 className="text-sm">Remove domain</h3>
|
||||
</div>
|
||||
@@ -735,19 +695,18 @@ const DomainsForm = () => {
|
||||
contentStyle={{ padding: 0 }}
|
||||
hideFooter
|
||||
>
|
||||
<div className="space-y-4 pt-4 mb-4">
|
||||
<div className="mb-4 space-y-4 pt-4">
|
||||
<div className="px-5">
|
||||
<p className="text-sm text-scale-1100 mb-2">
|
||||
<p className="text-scale-1100 mb-2 text-sm">
|
||||
Are you sure you want to remove{' '}
|
||||
<span className="text-scale-1200">{selectedDomain}</span>?
|
||||
</p>
|
||||
<p className="text-sm text-scale-900">
|
||||
This domain will no longer work with your Authentication
|
||||
configuration.
|
||||
<p className="text-scale-900 text-sm">
|
||||
This domain will no longer work with your Authentication configuration.
|
||||
</p>
|
||||
</div>
|
||||
<div className="border-t border-overlay-border"></div>
|
||||
<div className="px-5 flex gap-3">
|
||||
<div className="border-overlay-border border-t"></div>
|
||||
<div className="flex gap-3 px-5">
|
||||
<Button
|
||||
type="secondary"
|
||||
block
|
||||
@@ -802,10 +761,10 @@ const SmtpForm = () => {
|
||||
bg-scale-100
|
||||
dark:bg-scale-300
|
||||
|
||||
border border-scale-400 rounded-md my-8 shadow overflow-hidden"
|
||||
border-scale-400 my-8 overflow-hidden rounded-md border shadow"
|
||||
>
|
||||
{header && (
|
||||
<div className="bg-scale-100 dark:bg-scale-200 px-8 py-4 border-b border-scale-400">
|
||||
<div className="bg-scale-100 dark:bg-scale-200 border-scale-400 border-b px-8 py-4">
|
||||
{header}
|
||||
</div>
|
||||
)}
|
||||
@@ -821,7 +780,7 @@ const SmtpForm = () => {
|
||||
children: React.ReactNode
|
||||
header?: React.ReactNode
|
||||
}) => (
|
||||
<div className="grid grid-cols-12 px-8 py-2 gap-8">
|
||||
<div className="grid grid-cols-12 gap-8 px-8 py-2">
|
||||
{header && <div className="col-span-4">{header}</div>}
|
||||
{children}
|
||||
</div>
|
||||
@@ -857,8 +816,8 @@ const SmtpForm = () => {
|
||||
<Panel
|
||||
footer={
|
||||
<>
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="py-3 px-6 flex gap-2 justify-end">
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
<div className="flex justify-end gap-2 py-3 px-6">
|
||||
<Button
|
||||
loading={isSubmitting}
|
||||
type="secondary"
|
||||
@@ -896,37 +855,22 @@ const SmtpForm = () => {
|
||||
descriptionText="If this is disabled, new users will not be able to sign up to your application."
|
||||
/>
|
||||
{/* </Section> */}
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
<Section
|
||||
header={
|
||||
<div className="w-full">
|
||||
<label className="text-sm text-scale-1100">
|
||||
SMTP details
|
||||
</label>
|
||||
<p className="text-sm text-scale-900">
|
||||
<label className="text-scale-1100 text-sm">SMTP details</label>
|
||||
<p className="text-scale-900 text-sm">
|
||||
These settings can be found in your SMTP provider config
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="space-y-6 col-span-8">
|
||||
<Input
|
||||
label="Sender address"
|
||||
type="url"
|
||||
disabled={!values.enable_smtp}
|
||||
/>
|
||||
<Input
|
||||
label="SMTP server host"
|
||||
disabled={!values.enable_smtp}
|
||||
/>
|
||||
<InputNumber
|
||||
label="SMTP server port"
|
||||
disabled={!values.enable_smtp}
|
||||
/>
|
||||
<Input
|
||||
label="SMTP account username"
|
||||
disabled={!values.enable_smtp}
|
||||
/>
|
||||
<div className="col-span-8 space-y-6">
|
||||
<Input label="Sender address" type="url" disabled={!values.enable_smtp} />
|
||||
<Input label="SMTP server host" disabled={!values.enable_smtp} />
|
||||
<InputNumber label="SMTP server port" disabled={!values.enable_smtp} />
|
||||
<Input label="SMTP account username" disabled={!values.enable_smtp} />
|
||||
<Input
|
||||
label="SMTP account password"
|
||||
type="password"
|
||||
@@ -963,10 +907,10 @@ const TemplatesForm = () => {
|
||||
className="
|
||||
bg-scale-100
|
||||
dark:bg-scale-300
|
||||
border border-scale-400 rounded-md mb-8 shadow overflow-hidden"
|
||||
border-scale-400 mb-8 overflow-hidden rounded-md border shadow"
|
||||
>
|
||||
{header && (
|
||||
<div className="bg-scale-100 dark:bg-scale-200 px-8 py-4 border-b border-scale-400">
|
||||
<div className="bg-scale-100 dark:bg-scale-200 border-scale-400 border-b px-8 py-4">
|
||||
{header}
|
||||
</div>
|
||||
)}
|
||||
@@ -982,7 +926,7 @@ const TemplatesForm = () => {
|
||||
children: React.ReactNode
|
||||
header?: React.ReactNode
|
||||
}) => (
|
||||
<div className="grid grid-cols-12 px-8 py-2 gap-8">
|
||||
<div className="grid grid-cols-12 gap-8 px-8 py-2">
|
||||
{header && <div className="col-span-4">{header}</div>}
|
||||
{children}
|
||||
</div>
|
||||
@@ -1026,18 +970,15 @@ const TemplatesForm = () => {
|
||||
<Tabs.Panel id={'confirm_signup'} label="Confirm Signup" />
|
||||
<Tabs.Panel id={'reset_password'} label="Reset Password" />
|
||||
<Tabs.Panel id={'magic_link'} label="Magic Link" />
|
||||
<Tabs.Panel
|
||||
id={'change_email_address'}
|
||||
label="Change Email Address"
|
||||
/>
|
||||
<Tabs.Panel id={'change_email_address'} label="Change Email Address" />
|
||||
<Tabs.Panel id={'invite_user'} label="Invite User" />
|
||||
</Tabs>
|
||||
</div>
|
||||
<Panel
|
||||
footer={
|
||||
<>
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="py-3 px-6 flex gap-2 justify-end">
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
<div className="flex justify-end gap-2 py-3 px-6">
|
||||
<Button
|
||||
loading={isSubmitting}
|
||||
type="secondary"
|
||||
@@ -1079,18 +1020,15 @@ const TemplatesForm = () => {
|
||||
<Section
|
||||
header={
|
||||
<div className="w-full">
|
||||
<h3 className="text-base text-scale-1200 mb-4">
|
||||
Confirm Signup
|
||||
</h3>
|
||||
<p className="text-sm text-scale-900">
|
||||
When a user signs up using an email address and password,
|
||||
you can send them a confirmation email to verify their
|
||||
registered email address. Learn more
|
||||
<h3 className="text-scale-1200 mb-4 text-base">Confirm Signup</h3>
|
||||
<p className="text-scale-900 text-sm">
|
||||
When a user signs up using an email address and password, you can send them a
|
||||
confirmation email to verify their registered email address. Learn more
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="space-y-6 col-span-8">
|
||||
<div className="col-span-8 space-y-6">
|
||||
<Input label="Sender address" type="url" />
|
||||
<Input label="SMTP server host" />
|
||||
<InputNumber label="SMTP server port" />
|
||||
@@ -1125,34 +1063,28 @@ export function WholeForm() {
|
||||
<div style={{ width: '820px' }} className="mx-auto">
|
||||
<Tabs defaultActiveId="one" type="underlined" size="medium">
|
||||
<Tabs.Panel id="one" label="Sign-in method">
|
||||
<div className="space-y-12 py-12 animate-fade-in">
|
||||
<div className="animate-fade-in space-y-12 py-12">
|
||||
<div>
|
||||
<h1 className="text-3xl text-scale-1200">Sign-in method</h1>
|
||||
<h1 className="text-scale-1200 text-3xl">Sign-in method</h1>
|
||||
</div>
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
<div>
|
||||
<h3 className="text-scale-1200 text-2xl mb-2">
|
||||
General settings
|
||||
</h3>
|
||||
<p className="text-sm text-scale-900">
|
||||
Turn payment methods on and off in one click – no engineering
|
||||
time required.
|
||||
<h3 className="text-scale-1200 mb-2 text-2xl">General settings</h3>
|
||||
<p className="text-scale-900 text-sm">
|
||||
Turn payment methods on and off in one click – no engineering time required.
|
||||
</p>
|
||||
<p className="text-sm text-scale-900">
|
||||
Use our guide to check which payment methods are compatible with
|
||||
your integration.
|
||||
<p className="text-scale-900 text-sm">
|
||||
Use our guide to check which payment methods are compatible with your integration.
|
||||
</p>
|
||||
<CardForm />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-scale-1200 text-2xl mb-2">Providers</h3>
|
||||
<p className="text-sm text-scale-900">
|
||||
Turn payment methods on and off in one click – no engineering
|
||||
time required.
|
||||
<h3 className="text-scale-1200 mb-2 text-2xl">Providers</h3>
|
||||
<p className="text-scale-900 text-sm">
|
||||
Turn payment methods on and off in one click – no engineering time required.
|
||||
</p>
|
||||
<p className="text-sm text-scale-900">
|
||||
Use our guide to check which payment methods are compatible with
|
||||
your integration.
|
||||
<p className="text-scale-900 text-sm">
|
||||
Use our guide to check which payment methods are compatible with your integration.
|
||||
</p>
|
||||
<AuthForm />
|
||||
</div>
|
||||
@@ -1161,42 +1093,40 @@ export function WholeForm() {
|
||||
</div>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel id="two" label="Emails">
|
||||
<div className="space-y-12 py-12 animate-fade-in">
|
||||
<div className="animate-fade-in space-y-12 py-12">
|
||||
<div>
|
||||
<h1 className="text-3xl text-scale-1200">Emails</h1>
|
||||
<h1 className="text-scale-1200 text-3xl">Emails</h1>
|
||||
</div>
|
||||
<button
|
||||
className="
|
||||
group
|
||||
w-full
|
||||
bg-scale-300
|
||||
dark:bg-scale-100
|
||||
border
|
||||
border-scale-500 hover:border-scale-700
|
||||
dark:border-scale-300 dark:hover:border-scale-500
|
||||
px-6 py-4
|
||||
my-6
|
||||
flex gap-6 items-center
|
||||
rounded-md shadow-sm
|
||||
bg-scale-300
|
||||
dark:bg-scale-100
|
||||
border-scale-500
|
||||
hover:border-scale-700
|
||||
dark:border-scale-300
|
||||
dark:hover:border-scale-500 group
|
||||
my-6 flex
|
||||
w-full items-center
|
||||
gap-6
|
||||
rounded-md border px-6
|
||||
py-4 text-left
|
||||
shadow-sm
|
||||
transition
|
||||
text-left
|
||||
"
|
||||
>
|
||||
<div className="transition duration-500 bg-brand-900 rounded p-1 w-10 h-10 group-hover:-rotate-3 group-hover:scale-110">
|
||||
<div className="bg-brand-900 h-10 w-10 rounded p-1 transition duration-500 group-hover:-rotate-3 group-hover:scale-110">
|
||||
{/* <img
|
||||
className="text-white w-12 h-12"
|
||||
src="/icons/docs-illustration.svg"
|
||||
/> */}
|
||||
</div>
|
||||
<div className="grow">
|
||||
<h3 className="text-scale-1200">
|
||||
Use authentication as the backbone of your app
|
||||
</h3>
|
||||
<h3 className="text-scale-1200">Use authentication as the backbone of your app</h3>
|
||||
<p className="text-scale-900 text-xs">
|
||||
Learn how to use Supabase Auth with Auth Policies to pick and
|
||||
choose what users see what.
|
||||
Learn how to use Supabase Auth with Auth Policies to pick and choose what users
|
||||
see what.
|
||||
</p>
|
||||
<p className="text-brand-900 mt-2 text-xs flex items-center gap-1">
|
||||
<p className="text-brand-900 mt-2 flex items-center gap-1 text-xs">
|
||||
See Documenation
|
||||
<span className="transition group-hover:translate-x-1">
|
||||
<IconArrowRight strokeWidth={2} width={12} />
|
||||
@@ -1207,20 +1137,18 @@ export function WholeForm() {
|
||||
<IconX />
|
||||
</div>
|
||||
</button>
|
||||
<div className="border-t border-scale-400"></div>
|
||||
<div className="border-scale-400 border-t"></div>
|
||||
<div>
|
||||
<h3 className="text-scale-1200 text-2xl mb-2">Custom SMTP</h3>
|
||||
<p className="text-sm text-scale-900">
|
||||
You can use your own SMTP server instead of the built-in email
|
||||
service.
|
||||
<h3 className="text-scale-1200 mb-2 text-2xl">Custom SMTP</h3>
|
||||
<p className="text-scale-900 text-sm">
|
||||
You can use your own SMTP server instead of the built-in email service.
|
||||
</p>
|
||||
<SmtpForm />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-scale-1200 text-2xl mb-2">Templates</h3>
|
||||
<p className="text-sm text-scale-900">
|
||||
You can use your own SMTP server instead of the built-in email
|
||||
service.
|
||||
<h3 className="text-scale-1200 mb-2 text-2xl">Templates</h3>
|
||||
<p className="text-scale-900 text-sm">
|
||||
You can use your own SMTP server instead of the built-in email service.
|
||||
</p>
|
||||
<TemplatesForm />
|
||||
</div>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,12 @@
|
||||
// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import * as React from 'react'
|
||||
// @ts-ignore
|
||||
import { Activity } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
|
||||
function IconActivity(props: any) {
|
||||
return <IconBase icon={Activity} {...props} />
|
||||
}
|
||||
|
||||
export default IconActivity
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import React from 'react'
|
||||
import * as React from 'react'
|
||||
// @ts-ignore
|
||||
import { Airplay } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import React from 'react'
|
||||
import * as React from 'react'
|
||||
// @ts-ignore
|
||||
import { AlertCircle } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import React from 'react'
|
||||
import * as React from 'react'
|
||||
// @ts-ignore
|
||||
import { AlertOctagon } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import React from 'react'
|
||||
import * as React from 'react'
|
||||
// @ts-ignore
|
||||
import { AlertTriangle } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import React from 'react'
|
||||
import * as React from 'react'
|
||||
// @ts-ignore
|
||||
import { AlignCenter } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
// DO NOT EDIT
|
||||
// this file is generated by /internals/populate-icons script
|
||||
import React from 'react'
|
||||
import * as React from 'react'
|
||||
// @ts-ignore
|
||||
import { AlignJustify } from 'react-feather'
|
||||
import IconBase from './../../IconBase'
|
||||
File renamed without changes.
Loaded 100 of 1124 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user