diff --git a/README.md b/README.md index 6dae0d0..f716cf7 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,12 @@ Use [Netlify Identity](https://www.netlify.com/docs/identity/?utm_source=github&utm_medium=swyx-RNI&utm_campaign=devex) easier with React! This is a thin wrapper over the [gotrue-js](https://github.com/netlify/gotrue-js) library for easily accessing Netlify Identity functionality in your app, with React Context and Hooks. Types are provided. -Two demos: +Three demos: - [a full demo here](https://netlify-gotrue-in-react.netlify.com/) with [source code](https://github.com/netlify/create-react-app-lambda/tree/reachRouterAndGoTrueDemo/src) -- the `example` folder here has [a demo hosted here](https://react-netlify-identity.netlify.com) with [deploy logs here](https://app.netlify.com/sites/react-netlify-identity/deploys) +- [example with Reach Router](https://github.com/sw-yx/react-netlify-identity/tree/master/examples/example-reach-router) with [a demo hosted here](https://react-netlify-identity.netlify.com) and [deployed logs here](https://app.netlify.com/sites/react-netlify-identity/deploys) +- [example with React Router](https://github.com/sw-yx/react-netlify-identity/tree/master/examples/example-react-router) with [a demo hosted here](https://react-netlify-identity-example.netlify.com) + **This library is not officially maintained by Netlify.** This is written by swyx for his own use (and others with like minds 😎) and will be maintained as a personal project unless formally adopted by Netlify. See below for official alternatives. diff --git a/example/.gitignore b/examples/example-reach-router/.gitignore similarity index 100% rename from example/.gitignore rename to examples/example-reach-router/.gitignore diff --git a/example/README.md b/examples/example-reach-router/README.md similarity index 100% rename from example/README.md rename to examples/example-reach-router/README.md diff --git a/example/functions/async-dadjoke/async-dadjoke.js b/examples/example-reach-router/functions/async-dadjoke/async-dadjoke.js similarity index 100% rename from example/functions/async-dadjoke/async-dadjoke.js rename to examples/example-reach-router/functions/async-dadjoke/async-dadjoke.js diff --git a/example/functions/async-dadjoke/package.json b/examples/example-reach-router/functions/async-dadjoke/package.json similarity index 100% rename from example/functions/async-dadjoke/package.json rename to examples/example-reach-router/functions/async-dadjoke/package.json diff --git a/example/functions/authEndPoint/authEndPoint.js b/examples/example-reach-router/functions/authEndPoint/authEndPoint.js similarity index 100% rename from example/functions/authEndPoint/authEndPoint.js rename to examples/example-reach-router/functions/authEndPoint/authEndPoint.js diff --git a/example/functions/authEndPoint/package.json b/examples/example-reach-router/functions/authEndPoint/package.json similarity index 100% rename from example/functions/authEndPoint/package.json rename to examples/example-reach-router/functions/authEndPoint/package.json diff --git a/example/index.html b/examples/example-reach-router/index.html similarity index 100% rename from example/index.html rename to examples/example-reach-router/index.html diff --git a/example/package.json b/examples/example-reach-router/package.json similarity index 100% rename from example/package.json rename to examples/example-reach-router/package.json diff --git a/example/public/_redirects b/examples/example-reach-router/public/_redirects similarity index 100% rename from example/public/_redirects rename to examples/example-reach-router/public/_redirects diff --git a/example/public/favicon.ico b/examples/example-reach-router/public/favicon.ico similarity index 100% rename from example/public/favicon.ico rename to examples/example-reach-router/public/favicon.ico diff --git a/example/public/index.html b/examples/example-reach-router/public/index.html similarity index 100% rename from example/public/index.html rename to examples/example-reach-router/public/index.html diff --git a/example/public/manifest.json b/examples/example-reach-router/public/manifest.json similarity index 100% rename from example/public/manifest.json rename to examples/example-reach-router/public/manifest.json diff --git a/example/src/App.css b/examples/example-reach-router/src/App.css similarity index 100% rename from example/src/App.css rename to examples/example-reach-router/src/App.css diff --git a/example/src/App.tsx b/examples/example-reach-router/src/App.tsx similarity index 100% rename from example/src/App.tsx rename to examples/example-reach-router/src/App.tsx diff --git a/example/src/index.css b/examples/example-reach-router/src/index.css similarity index 100% rename from example/src/index.css rename to examples/example-reach-router/src/index.css diff --git a/example/src/index.tsx b/examples/example-reach-router/src/index.tsx similarity index 100% rename from example/src/index.tsx rename to examples/example-reach-router/src/index.tsx diff --git a/example/src/logo.svg b/examples/example-reach-router/src/logo.svg similarity index 100% rename from example/src/logo.svg rename to examples/example-reach-router/src/logo.svg diff --git a/example/src/useLoading.tsx b/examples/example-reach-router/src/useLoading.tsx similarity index 100% rename from example/src/useLoading.tsx rename to examples/example-reach-router/src/useLoading.tsx diff --git a/example/src/useLocalState.tsx b/examples/example-reach-router/src/useLocalState.tsx similarity index 100% rename from example/src/useLocalState.tsx rename to examples/example-reach-router/src/useLocalState.tsx diff --git a/example/tsconfig.json b/examples/example-reach-router/tsconfig.json similarity index 100% rename from example/tsconfig.json rename to examples/example-reach-router/tsconfig.json diff --git a/example/yarn.lock b/examples/example-reach-router/yarn.lock similarity index 100% rename from example/yarn.lock rename to examples/example-reach-router/yarn.lock diff --git a/examples/example-react-router/README.md b/examples/example-react-router/README.md new file mode 100644 index 0000000..a2db1a3 --- /dev/null +++ b/examples/example-react-router/README.md @@ -0,0 +1,14 @@ +# React Netlify Identity Example + +This is an example of using `react-netlify-identity` with: + +- TypeScript +- React +- React Router +- Netlify Identity + +Additionally, styling with: + +- styled-components + +Deployed demo site [here](https://react-netlify-identity-example.netlify.com/). diff --git a/examples/example-react-router/global.d.ts b/examples/example-react-router/global.d.ts new file mode 100644 index 0000000..bff9471 --- /dev/null +++ b/examples/example-react-router/global.d.ts @@ -0,0 +1 @@ +declare module '*.svg'; diff --git a/examples/example-react-router/package.json b/examples/example-react-router/package.json new file mode 100644 index 0000000..3c3aa27 --- /dev/null +++ b/examples/example-react-router/package.json @@ -0,0 +1,19 @@ +{ + "name": "react-netlify-identity-example", + "version": "1.0.0", + "author": "Lewis Llobera ", + "license": "MIT", + "dependencies": { + "react": "^16.10.1", + "react-dom": "^16.10.1", + "react-netlify-identity": "^0.1.9", + "react-router-dom": "^5.1.2" + }, + "devDependencies": { + "@types/react": "^16.9.4", + "@types/react-dom": "^16.9.1", + "@types/react-router-dom": "^5.1.0", + "styled-components": "^4.4.0", + "typescript": "^3.6.2" + } +} diff --git a/examples/example-react-router/src/App.tsx b/examples/example-react-router/src/App.tsx new file mode 100644 index 0000000..dbca76d --- /dev/null +++ b/examples/example-react-router/src/App.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom'; +import { + IdentityContextProvider, + useIdentityContext, +} from 'react-netlify-identity'; + +import { GlobalStyles } from './components'; +import { CreateAccount, Home, LogIn, Welcome } from './views'; + +interface Props { + component: React.FunctionComponent; + exact?: boolean; + path: string; +} + +const PublicRoute: React.FunctionComponent = (props: Props) => { + const { isLoggedIn } = useIdentityContext(); + return isLoggedIn ? : ; +}; + +const PrivateRoute: React.FunctionComponent = (props: Props) => { + const { isLoggedIn } = useIdentityContext(); + return isLoggedIn ? : ; +}; + +export const App: React.FunctionComponent = () => { + const url = 'https://react-netlify-identity-example.netlify.com'; + + return ( + <> + + + + + + + + + + + + + + ); +}; diff --git a/examples/example-react-router/src/assets/googleLogo.svg b/examples/example-react-router/src/assets/googleLogo.svg new file mode 100644 index 0000000..8464cb2 --- /dev/null +++ b/examples/example-react-router/src/assets/googleLogo.svg @@ -0,0 +1,50 @@ + + + + btn_google_dark_normal_ios + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/example-react-router/src/assets/index.ts b/examples/example-react-router/src/assets/index.ts new file mode 100644 index 0000000..2b3a5a2 --- /dev/null +++ b/examples/example-react-router/src/assets/index.ts @@ -0,0 +1,3 @@ +import googleLogo from './googleLogo.svg'; + +export { googleLogo }; diff --git a/examples/example-react-router/src/components/AuthOption/AuthOption.styles.ts b/examples/example-react-router/src/components/AuthOption/AuthOption.styles.ts new file mode 100644 index 0000000..decad23 --- /dev/null +++ b/examples/example-react-router/src/components/AuthOption/AuthOption.styles.ts @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +export const AuthOption = styled.div` + align-items: center; + display: flex; + flex-direction: column; + margin: 0 auto 10vh auto; + width: 100%; +`; diff --git a/examples/example-react-router/src/components/AuthOption/index.ts b/examples/example-react-router/src/components/AuthOption/index.ts new file mode 100644 index 0000000..671b3d2 --- /dev/null +++ b/examples/example-react-router/src/components/AuthOption/index.ts @@ -0,0 +1 @@ +export { AuthOption } from './AuthOption.styles'; diff --git a/examples/example-react-router/src/components/AuthText/AuthText.styles.ts b/examples/example-react-router/src/components/AuthText/AuthText.styles.ts new file mode 100644 index 0000000..c1c8a0a --- /dev/null +++ b/examples/example-react-router/src/components/AuthText/AuthText.styles.ts @@ -0,0 +1,11 @@ +import styled from 'styled-components'; + +export const AuthText = styled.p` + border-bottom: 1px solid lightgray; + display: block; + font-weight: 700; + line-height: 1.4; + margin-bottom: 3vh; + text-align: center; + width: 100%; +`; diff --git a/examples/example-react-router/src/components/AuthText/index.ts b/examples/example-react-router/src/components/AuthText/index.ts new file mode 100644 index 0000000..786e31f --- /dev/null +++ b/examples/example-react-router/src/components/AuthText/index.ts @@ -0,0 +1 @@ +export { AuthText } from './AuthText.styles'; diff --git a/examples/example-react-router/src/components/Button/Button.styles.ts b/examples/example-react-router/src/components/Button/Button.styles.ts new file mode 100644 index 0000000..965b076 --- /dev/null +++ b/examples/example-react-router/src/components/Button/Button.styles.ts @@ -0,0 +1,44 @@ +import styled, { keyframes } from 'styled-components'; + +import { BREAKPOINT } from '../../constants/constants'; + +const animation = keyframes` + from { + transform: scale(1); + } + to { + transform: scale(0.9); + } +`; + +interface Props { + secondary?: boolean; +} + +export const Button = styled.button` + align-items: center; + background-color: ${(props: Props): string => + props.secondary ? 'transparent' : 'var(--color-accent)'}; + border-radius: var(--radius-l); + color: var(--color-dark); + display: flex; + font-weight: 700; + height: 52px; + justify-content: center; + margin: 0 auto; + transition: 0.5s; + width: 300px; + + &:disabled { + cursor: not-allowed; + opacity: 0.5; + } + + :active { + animation: ${animation} 0.3s cubic-bezier(0.19, 1, 0.22, 1); + } + + @media (max-width: ${BREAKPOINT}px) { + width: 280px; + } +`; diff --git a/examples/example-react-router/src/components/Button/index.ts b/examples/example-react-router/src/components/Button/index.ts new file mode 100644 index 0000000..a314f05 --- /dev/null +++ b/examples/example-react-router/src/components/Button/index.ts @@ -0,0 +1 @@ +export { Button } from './Button.styles'; diff --git a/examples/example-react-router/src/components/ButtonGoogle/ButtonGoogle.styles.ts b/examples/example-react-router/src/components/ButtonGoogle/ButtonGoogle.styles.ts new file mode 100644 index 0000000..dc52aa3 --- /dev/null +++ b/examples/example-react-router/src/components/ButtonGoogle/ButtonGoogle.styles.ts @@ -0,0 +1,13 @@ +import styled from 'styled-components'; + +import { Button } from '../../components'; + +export const Logo = styled.img` + margin-right: 24px; +`; + +export const StyledButton = styled(Button)` + background-color: #4285f4; + background-image: none; + color: #ffffff; +`; diff --git a/examples/example-react-router/src/components/ButtonGoogle/ButtonGoogle.tsx b/examples/example-react-router/src/components/ButtonGoogle/ButtonGoogle.tsx new file mode 100644 index 0000000..8f5e367 --- /dev/null +++ b/examples/example-react-router/src/components/ButtonGoogle/ButtonGoogle.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { useIdentityContext } from 'react-netlify-identity'; + +import { Logo, StyledButton } from './ButtonGoogle.styles'; +import { googleLogo } from '../../assets'; + +interface Props { + children: string; +} + +export const ButtonGoogle: React.FunctionComponent = (props: Props) => { + const { loginProvider } = useIdentityContext(); + + const logInWithGoogle = (): void => { + loginProvider('google'); + }; + + return ( + + + {props.children} + + ); +}; diff --git a/examples/example-react-router/src/components/ButtonGoogle/index.ts b/examples/example-react-router/src/components/ButtonGoogle/index.ts new file mode 100644 index 0000000..acc94ee --- /dev/null +++ b/examples/example-react-router/src/components/ButtonGoogle/index.ts @@ -0,0 +1 @@ +export { ButtonGoogle } from './ButtonGoogle'; diff --git a/examples/example-react-router/src/components/Container/Container.styles.ts b/examples/example-react-router/src/components/Container/Container.styles.ts new file mode 100644 index 0000000..0d48d2e --- /dev/null +++ b/examples/example-react-router/src/components/Container/Container.styles.ts @@ -0,0 +1,35 @@ +import styled from 'styled-components'; + +import { PAGE_WIDTH } from '../../constants/constants'; + +interface Props { + between?: boolean; + paddingBottom?: string; + partial?: boolean; + row?: boolean; +} + +export const Container = styled.div` + align-items: center; + display: flex; + flex-direction: ${(props: Props): string => (props.row ? 'row' : 'column')}; + justify-content: ${(props: Props): string => + props.between ? 'space-between' : 'center'}; + height: ${(props: Props): string => (props.partial ? '80vh' : '100%')}; + margin-left: auto; + margin-right: auto; + max-width: ${PAGE_WIDTH}px; + padding-bottom: ${(props: Props): string => { + switch (props.paddingBottom) { + case 'large': + return '200px'; + case 'medium': + return '120px'; + default: + return 'auto'; + } + }}; + padding-left: var(--padding); + padding-right: var(--padding); + width: 100%; +`; diff --git a/examples/example-react-router/src/components/Container/index.ts b/examples/example-react-router/src/components/Container/index.ts new file mode 100644 index 0000000..44c7512 --- /dev/null +++ b/examples/example-react-router/src/components/Container/index.ts @@ -0,0 +1 @@ +export { Container } from './Container.styles'; diff --git a/examples/example-react-router/src/components/Form/Form.styles.ts b/examples/example-react-router/src/components/Form/Form.styles.ts new file mode 100644 index 0000000..1eb1086 --- /dev/null +++ b/examples/example-react-router/src/components/Form/Form.styles.ts @@ -0,0 +1,20 @@ +import styled from 'styled-components'; + +import { BREAKPOINT } from '../../constants/constants'; + +interface Props { + narrow?: boolean; +} + +export const Form = styled.form` + backdrop-filter: blur(2px); + background-color: var(--color-background-translucent); + display: flex; + flex-direction: column; + justify-content: center; + width: ${(props: Props): string => (props.narrow ? '60%' : '100%')}; + + @media (max-width: ${BREAKPOINT}px) { + width: 100%; + } +`; diff --git a/examples/example-react-router/src/components/Form/index.ts b/examples/example-react-router/src/components/Form/index.ts new file mode 100644 index 0000000..25842a1 --- /dev/null +++ b/examples/example-react-router/src/components/Form/index.ts @@ -0,0 +1 @@ +export { Form } from './Form.styles'; diff --git a/examples/example-react-router/src/components/GlobalStyles/GlobalStyles.styles.ts b/examples/example-react-router/src/components/GlobalStyles/GlobalStyles.styles.ts new file mode 100644 index 0000000..3988fa8 --- /dev/null +++ b/examples/example-react-router/src/components/GlobalStyles/GlobalStyles.styles.ts @@ -0,0 +1,129 @@ +import { createGlobalStyle } from 'styled-components'; + +import { BREAKPOINT } from '../../constants/constants'; + +export const GlobalStyles = createGlobalStyle` + :root { + --color-accent: hsl(165, 100%, 50%); + --color-dark: hsl(0, 0%, 10%); + --color-error: hsl(343, 100%, 45%); + --color-light: hsl(70, 0%, 95%); + --color-light-translucent: hsla(70, 0%, 95%, 0.85); + --font-size-xxs: 15px; + --font-size-xs: 17px; + --font-size-s: 18px; + --font-size-m: 22px; + --font-size-l: 30px; + --font-size-xl: 46px; + --font-size-xxl: 60px; + --padding: 4%; + --radius-l: 10px; + --radius-m: 6px; + } + + html + body { + background-color: var(--color-light); + color: var(--color-dark); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + font-size: var(--font-size-s); + padding-top: 80px; + -webkit-touch-callout: none; + -webkit-user-select: none; + + @media (max-width: ${BREAKPOINT}px) { + font-size: var(--font-size-xs); + } + } + + a { + color: inherit; + text-decoration: none; + } + + [contenteditable] { + user-select: text; + } + + /* CSS Reset */ + + * { + box-sizing: border-box; + -webkit-box-sizing: border-box; + -webkit-tap-highlight-color: hsla(0,0%,0%,0); + -webkit-tap-highlight-color: transparent; + } + + html, + body { + margin: 0; + height: 100%; + width: 100%; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + h1, + h2, + h3, + h4, + h5, + h6, + p { + font-size: inherit; + font-weight: inherit; + margin: 0; + margin-block-end: 0; + margin-block-start: 0; + margin-inline-end: 0; + margin-inline-start: 0; + -webkit-margin-after: 0; + -webkit-margin-before: 0; + -webkit-margin-end: 0; + -webkit-margin-start: 0; + } + + button { + background-color: inherit; + border: none; + color: inherit; + cursor: pointer; + display: inline-block; + font-family: inherit; + font-size: inherit; + margin: 0; + padding: 0; + text-align: center; + text-decoration: none; + -webkit-appearance: none; + -moz-appearance: none; + } + + button:focus { + outline: 0; + } + + input { + border-color: initial; + border-image: initial; + border-style: none; + color: inherit; + display: block; + font: inherit; + padding: 10px; + margin: 0; + width: 100%; + } + + input:focus { + outline: 0; + } + + input:not([type=checkbox]):not([type=radio]) { + appearance: none; + } + + ::-webkit-scrollbar { + display: none; + } +`; diff --git a/examples/example-react-router/src/components/GlobalStyles/index.ts b/examples/example-react-router/src/components/GlobalStyles/index.ts new file mode 100644 index 0000000..f3afa12 --- /dev/null +++ b/examples/example-react-router/src/components/GlobalStyles/index.ts @@ -0,0 +1 @@ +export { GlobalStyles } from './GlobalStyles.styles'; diff --git a/examples/example-react-router/src/components/Header/Header.styles.ts b/examples/example-react-router/src/components/Header/Header.styles.ts new file mode 100644 index 0000000..7fcff32 --- /dev/null +++ b/examples/example-react-router/src/components/Header/Header.styles.ts @@ -0,0 +1,25 @@ +import styled from 'styled-components'; + +import { BREAKPOINT } from '../../constants/constants'; + +export const FixedBar = styled.div` + background-color: var(--color-light-translucent); + backdrop-filter: blur(2px); + height: 60px; + left: 0; + padding: 10px 0; + position: fixed; + right: 0; + top: 0; + z-index: 2; +`; + +export const Title = styled.h1` + font-size: var(--font-size-xl); + font-weight: 700; + margin-top: -5px; + + @media (max-width: ${BREAKPOINT}px) { + font-size: var(--font-size-l); + } +`; diff --git a/examples/example-react-router/src/components/Header/Header.tsx b/examples/example-react-router/src/components/Header/Header.tsx new file mode 100644 index 0000000..ad0003d --- /dev/null +++ b/examples/example-react-router/src/components/Header/Header.tsx @@ -0,0 +1,28 @@ +import React from 'react'; + +import { FixedBar, Title } from './Header.styles'; +import { Container } from '../../components'; + +interface Props { + name?: string; +} + +export const Header: React.FunctionComponent = (props: Props) => { + if (props.name) { + return ( + + + {props.name} + + + ); + } else { + return ( + + + Home + + + ); + } +}; diff --git a/examples/example-react-router/src/components/Header/index.ts b/examples/example-react-router/src/components/Header/index.ts new file mode 100644 index 0000000..29429dc --- /dev/null +++ b/examples/example-react-router/src/components/Header/index.ts @@ -0,0 +1 @@ +export { Header } from './Header'; diff --git a/examples/example-react-router/src/components/Input/Input.styles.ts b/examples/example-react-router/src/components/Input/Input.styles.ts new file mode 100644 index 0000000..64ef89c --- /dev/null +++ b/examples/example-react-router/src/components/Input/Input.styles.ts @@ -0,0 +1,15 @@ +import styled from 'styled-components'; + +export const Input = styled.input` + background-color: white; + border: 3px solid transparent; + border-radius: var(--radius-m); + height: 50px; + margin: 0 auto 15px auto; + padding: 0px 20px; + + :focus { + border: 3px solid var(--color-accent-light); + transition: border 0.2s ease-in; + } +`; diff --git a/examples/example-react-router/src/components/Input/index.ts b/examples/example-react-router/src/components/Input/index.ts new file mode 100644 index 0000000..bc444ee --- /dev/null +++ b/examples/example-react-router/src/components/Input/index.ts @@ -0,0 +1 @@ +export { Input } from './Input.styles'; diff --git a/examples/example-react-router/src/components/Label/Label.styles.ts b/examples/example-react-router/src/components/Label/Label.styles.ts new file mode 100644 index 0000000..cdf9d86 --- /dev/null +++ b/examples/example-react-router/src/components/Label/Label.styles.ts @@ -0,0 +1,13 @@ +import styled from 'styled-components'; + +import { BREAKPOINT } from '../../constants/constants'; + +export const Label = styled.label` + color: var(--color-text-lighter); + font-size: var(--font-size-s); + margin-bottom: 3px; + + @media (max-width: ${BREAKPOINT}px) { + font-size: var(--font-size-xs); + } +`; diff --git a/examples/example-react-router/src/components/Label/index.ts b/examples/example-react-router/src/components/Label/index.ts new file mode 100644 index 0000000..ab71219 --- /dev/null +++ b/examples/example-react-router/src/components/Label/index.ts @@ -0,0 +1 @@ +export { Label } from './Label.styles'; diff --git a/examples/example-react-router/src/components/TextError/TextError.styles.ts b/examples/example-react-router/src/components/TextError/TextError.styles.ts new file mode 100644 index 0000000..2847440 --- /dev/null +++ b/examples/example-react-router/src/components/TextError/TextError.styles.ts @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +export const TextError = styled.p` + color: var(--color-error); + font-weight: 700; + line-height: 1.4; + margin-top: 3vh; + text-align: center; +`; diff --git a/examples/example-react-router/src/components/TextError/index.ts b/examples/example-react-router/src/components/TextError/index.ts new file mode 100644 index 0000000..059eae9 --- /dev/null +++ b/examples/example-react-router/src/components/TextError/index.ts @@ -0,0 +1 @@ +export { TextError } from './TextError.styles'; diff --git a/examples/example-react-router/src/components/index.ts b/examples/example-react-router/src/components/index.ts new file mode 100644 index 0000000..cb16001 --- /dev/null +++ b/examples/example-react-router/src/components/index.ts @@ -0,0 +1,11 @@ +export { AuthOption } from './AuthOption'; +export { AuthText } from './AuthText'; +export { Button } from './Button'; +export { ButtonGoogle } from './ButtonGoogle'; +export { Container } from './Container'; +export { Form } from './Form'; +export { GlobalStyles } from './GlobalStyles'; +export { Header } from './Header'; +export { Input } from './Input'; +export { Label } from './Label'; +export { TextError } from './TextError'; diff --git a/examples/example-react-router/src/constants/constants.ts b/examples/example-react-router/src/constants/constants.ts new file mode 100644 index 0000000..6b02613 --- /dev/null +++ b/examples/example-react-router/src/constants/constants.ts @@ -0,0 +1,3 @@ +export const BREAKPOINT = 600; + +export const PAGE_WIDTH = 800; diff --git a/examples/example-react-router/src/index.tsx b/examples/example-react-router/src/index.tsx new file mode 100755 index 0000000..b4fb4f8 --- /dev/null +++ b/examples/example-react-router/src/index.tsx @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { App } from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/examples/example-react-router/src/public/index.html b/examples/example-react-router/src/public/index.html new file mode 100755 index 0000000..a9effc1 --- /dev/null +++ b/examples/example-react-router/src/public/index.html @@ -0,0 +1,21 @@ + + + + + + React Netlify Identity Example + + + + +
+ + + diff --git a/examples/example-react-router/src/public/robots.txt b/examples/example-react-router/src/public/robots.txt new file mode 100644 index 0000000..b21f088 --- /dev/null +++ b/examples/example-react-router/src/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: / diff --git a/examples/example-react-router/src/views/CreateAccount/CreateAccount.styles.ts b/examples/example-react-router/src/views/CreateAccount/CreateAccount.styles.ts new file mode 100644 index 0000000..99c1d61 --- /dev/null +++ b/examples/example-react-router/src/views/CreateAccount/CreateAccount.styles.ts @@ -0,0 +1,12 @@ +import styled from 'styled-components'; + +import { BREAKPOINT } from '../../constants/constants'; + +export const PasswordTip = styled.span` + color: var(--color-dark-lighter); + font-size: var(--font-size-xs); + + @media (max-width: ${BREAKPOINT}px) { + font-size: var(--font-size-xxs); + } +`; diff --git a/examples/example-react-router/src/views/CreateAccount/CreateAccount.tsx b/examples/example-react-router/src/views/CreateAccount/CreateAccount.tsx new file mode 100644 index 0000000..6d782ad --- /dev/null +++ b/examples/example-react-router/src/views/CreateAccount/CreateAccount.tsx @@ -0,0 +1,98 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Redirect } from 'react-router-dom'; +import { useIdentityContext } from 'react-netlify-identity'; + +import { PasswordTip } from './CreateAccount.styles'; +import { + AuthOption, + AuthText, + Button, + ButtonGoogle, + Container, + Form, + Input, + Label, + Header, + TextError, +} from '../../components'; + +export const CreateAccount: React.FunctionComponent = () => { + const { loginUser, signupUser } = useIdentityContext(); + const [error, setError] = useState(false); + const emailInput = useRef(null!); + const passwordInput = useRef(null!); + const signUpButton = useRef(null!); + + useEffect(() => { + signUpButton.current.disabled = true; + }, [emailInput, passwordInput]); + + const passwordPattern = /^.{6,}$/; + + const handleChange = (): void => { + const email = emailInput.current.value; + const password = passwordInput.current.value; + if (email && passwordPattern.test(password)) { + signUpButton.current.disabled = false; + } else { + signUpButton.current.disabled = true; + } + }; + + const signUp = (event: React.FormEvent): void => { + event.preventDefault(); + const email = emailInput.current.value; + const password = passwordInput.current.value; + signupUser(email, password, {}) + .then(() => { + loginUser(email, password, true); + ; + }) + .catch((error) => { + setError(true); + console.log(error); + }); + }; + + return ( + <> +
+ + + Sign up with email: +
+ + + + + {error ? ( + + The email and/or password seems to be incorrect. Please check it + and try again. + + ) : null} + +
+
+ + Or sign up with Google: + Sign up with Google + +
+ + ); +}; diff --git a/examples/example-react-router/src/views/CreateAccount/index.ts b/examples/example-react-router/src/views/CreateAccount/index.ts new file mode 100644 index 0000000..b76a294 --- /dev/null +++ b/examples/example-react-router/src/views/CreateAccount/index.ts @@ -0,0 +1 @@ +export { CreateAccount } from './CreateAccount'; diff --git a/examples/example-react-router/src/views/Home/Home.styles.ts b/examples/example-react-router/src/views/Home/Home.styles.ts new file mode 100644 index 0000000..73b229b --- /dev/null +++ b/examples/example-react-router/src/views/Home/Home.styles.ts @@ -0,0 +1,8 @@ +import styled from 'styled-components'; + +import { Button } from '../../components'; + +export const LogOutButton = styled(Button)` + color: var(--color-error); + margin-top: 10vh; +`; diff --git a/examples/example-react-router/src/views/Home/Home.tsx b/examples/example-react-router/src/views/Home/Home.tsx new file mode 100755 index 0000000..33004f7 --- /dev/null +++ b/examples/example-react-router/src/views/Home/Home.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { useIdentityContext } from 'react-netlify-identity'; +import { Redirect } from 'react-router-dom'; + +import { Container, Header } from '../../components'; +import { LogOutButton } from './Home.styles'; + +export const Home: React.FunctionComponent = () => { + const { user, logoutUser } = useIdentityContext(); + + const logOut = (): void => { + logoutUser(); + ; + }; + + return ( + <> +
+ +

+ Hello {JSON.stringify(user!.email)} +

+ + Log out + +
+ + ); +}; diff --git a/examples/example-react-router/src/views/Home/index.ts b/examples/example-react-router/src/views/Home/index.ts new file mode 100644 index 0000000..af9c1c6 --- /dev/null +++ b/examples/example-react-router/src/views/Home/index.ts @@ -0,0 +1 @@ +export { Home } from './Home'; diff --git a/examples/example-react-router/src/views/LogIn/LogIn.tsx b/examples/example-react-router/src/views/LogIn/LogIn.tsx new file mode 100644 index 0000000..baf5c1a --- /dev/null +++ b/examples/example-react-router/src/views/LogIn/LogIn.tsx @@ -0,0 +1,92 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Redirect } from 'react-router-dom'; +import { useIdentityContext } from 'react-netlify-identity'; + +import { + AuthOption, + AuthText, + Button, + ButtonGoogle, + Container, + Form, + Input, + Label, + Header, + TextError, +} from '../../components'; + +export const LogIn: React.FunctionComponent = () => { + const { loginUser } = useIdentityContext(); + const [error, setError] = useState(false); + const emailInput = useRef(null!); + const passwordInput = useRef(null!); + const logInButton = useRef(null!); + + useEffect(() => { + logInButton.current.disabled = true; + }, [emailInput, passwordInput]); + + const handleChange = (): void => { + const email = emailInput.current.value; + const password = passwordInput.current.value; + if (email && password) { + logInButton.current.disabled = false; + } else { + logInButton.current.disabled = true; + } + }; + + const logIn = (event: React.FormEvent): void => { + event.preventDefault(); + const email = emailInput.current.value; + const password = passwordInput.current.value; + loginUser(email, password, true) + .then(() => { + ; + }) + .catch((error) => { + setError(true); + console.log(error); + }); + }; + + return ( + <> +
+ + + Log in with email: +
+ + + + + {error ? ( + + The email and/or password seems to be incorrect. Please check it + and try again. + + ) : null} + +
+
+ + Or log in with Google: + Log in with Google + +
+ + ); +}; diff --git a/examples/example-react-router/src/views/LogIn/index.ts b/examples/example-react-router/src/views/LogIn/index.ts new file mode 100644 index 0000000..07d5e62 --- /dev/null +++ b/examples/example-react-router/src/views/LogIn/index.ts @@ -0,0 +1 @@ +export { LogIn } from './LogIn'; diff --git a/examples/example-react-router/src/views/Welcome/Welcome.styles.ts b/examples/example-react-router/src/views/Welcome/Welcome.styles.ts new file mode 100644 index 0000000..2b30f1c --- /dev/null +++ b/examples/example-react-router/src/views/Welcome/Welcome.styles.ts @@ -0,0 +1,20 @@ +import styled from 'styled-components'; + +import { BREAKPOINT } from '../../constants/constants'; + +export const Intro = styled.h1` + font-weight: 700; + font-size: var(--font-size-xxl); + margin-bottom: 2vh; + text-align: center; + + @media (max-width: ${BREAKPOINT}px) { + font-size: var(--font-size-xl); + } +`; + +export const Layout = styled.div` + display: flex; + justify-content: center; + width: 100%; +`; diff --git a/examples/example-react-router/src/views/Welcome/Welcome.tsx b/examples/example-react-router/src/views/Welcome/Welcome.tsx new file mode 100644 index 0000000..3ad42cb --- /dev/null +++ b/examples/example-react-router/src/views/Welcome/Welcome.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; + +import { Intro, Layout } from './Welcome.styles'; +import { Button, Container } from '../../components'; + +export const Welcome: React.FunctionComponent = () => { + return ( + <> + + React Netlify Identity Example +

+ This is made with: TypeScript, React, React Router, Netlify Identity, + and styled-components. +

+ + + + + + + + + + +
+ + ); +}; diff --git a/examples/example-react-router/src/views/Welcome/index.ts b/examples/example-react-router/src/views/Welcome/index.ts new file mode 100644 index 0000000..e45cb73 --- /dev/null +++ b/examples/example-react-router/src/views/Welcome/index.ts @@ -0,0 +1 @@ +export { Welcome } from './Welcome'; diff --git a/examples/example-react-router/src/views/index.tsx b/examples/example-react-router/src/views/index.tsx new file mode 100644 index 0000000..428388d --- /dev/null +++ b/examples/example-react-router/src/views/index.tsx @@ -0,0 +1,4 @@ +export { CreateAccount } from './CreateAccount'; +export { Home } from './Home'; +export { LogIn } from './LogIn'; +export { Welcome } from './Welcome'; diff --git a/examples/example-react-router/tsconfig.json b/examples/example-react-router/tsconfig.json new file mode 100644 index 0000000..0c87324 --- /dev/null +++ b/examples/example-react-router/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "jsx": "react", + "module": "esnext", + "moduleResolution": "node", + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "target": "es5" + } +}