|
|
@@ -1,96 +1,89 @@
|
|
|
-import React, { ChangeEvent, Component } from "react";
|
|
|
+import React, { useEffect, useState, useContext } from "react";
|
|
|
import styled from "styled-components";
|
|
|
-import logo from "assets/logo.png";
|
|
|
+
|
|
|
import github from "assets/github-icon.png";
|
|
|
+import logo from "assets/logo.png";
|
|
|
import GoogleIcon from "assets/GoogleIcon";
|
|
|
|
|
|
import api from "shared/api";
|
|
|
import { emailRegex } from "shared/regex";
|
|
|
import { Context } from "shared/Context";
|
|
|
|
|
|
-type PropsType = {
|
|
|
- authenticate: () => void;
|
|
|
-};
|
|
|
+import Heading from "components/form-components/Heading";
|
|
|
+import Button from "components/porter/Button";
|
|
|
+import Container from "components/porter/Container";
|
|
|
+import Input from "components/porter/Input";
|
|
|
+import Spacer from "components/porter/Spacer";
|
|
|
+import Text from "components/porter/Text";
|
|
|
+import Link from "components/porter/Link";
|
|
|
|
|
|
-type StateType = {
|
|
|
- email: string;
|
|
|
- password: string;
|
|
|
- confirmPassword: string;
|
|
|
- emailError: boolean;
|
|
|
- confirmPasswordError: boolean;
|
|
|
- hasGithub: boolean;
|
|
|
- hasGoogle: boolean;
|
|
|
- hasBasic: boolean;
|
|
|
+type Props = {
|
|
|
+ authenticate: () => void;
|
|
|
};
|
|
|
|
|
|
-export default class Register extends Component<PropsType, StateType> {
|
|
|
- state = {
|
|
|
- email: "",
|
|
|
- password: "",
|
|
|
- confirmPassword: "",
|
|
|
- emailError: false,
|
|
|
- confirmPasswordError: false,
|
|
|
- hasBasic: true,
|
|
|
- hasGithub: true,
|
|
|
- hasGoogle: false,
|
|
|
- };
|
|
|
-
|
|
|
- handleKeyDown = (e: any) => {
|
|
|
- e.key === "Enter" ? this.handleRegister() : null;
|
|
|
- };
|
|
|
-
|
|
|
- componentDidMount() {
|
|
|
- document.addEventListener("keydown", this.handleKeyDown);
|
|
|
-
|
|
|
- // get capabilities to case on github
|
|
|
- api
|
|
|
- .getMetadata("", {}, {})
|
|
|
- .then((res) => {
|
|
|
- this.setState({
|
|
|
- hasGithub: res.data?.github_login,
|
|
|
- hasGoogle: res.data?.google_login,
|
|
|
- hasBasic: res.data?.basic_login,
|
|
|
- });
|
|
|
- })
|
|
|
- .catch((err) => console.log(err));
|
|
|
- }
|
|
|
-
|
|
|
- componentWillUnmount() {
|
|
|
- document.removeEventListener("keydown", this.handleKeyDown);
|
|
|
- }
|
|
|
+const getWindowDimensions = () => {
|
|
|
+ const { innerWidth: width, innerHeight: height } = window;
|
|
|
+ return { width, height };
|
|
|
+}
|
|
|
|
|
|
- githubRedirect = () => {
|
|
|
- let redirectUrl = `/api/oauth/login/github`;
|
|
|
- window.location.href = redirectUrl;
|
|
|
- };
|
|
|
+const Register: React.FC<Props> = ({
|
|
|
+ authenticate,
|
|
|
+}) => {
|
|
|
+ const { setUser, setCurrentError } = useContext(Context);
|
|
|
+ const [firstName, setFirstName] = useState("");
|
|
|
+ const [firstNameError, setFirstNameError] = useState(false);
|
|
|
+ const [lastName, setLastName] = useState("");
|
|
|
+ const [lastNameError, setLastNameError] = useState(false);
|
|
|
+ const [companyName, setCompanyName] = useState("");
|
|
|
+ const [companyNameError, setCompanyNameError] = useState(false);
|
|
|
+ const [email, setEmail] = useState("");
|
|
|
+ const [emailError, setEmailError] = useState(false);
|
|
|
+ const [password, setPassword] = useState("");
|
|
|
+ const [passwordError, setPasswordError] = useState(false);
|
|
|
+ const [hasBasic, setHasBasic] = useState(true);
|
|
|
+ const [hasGithub, setHasGithub] = useState(true);
|
|
|
+ const [hasGoogle, setHasGoogle] = useState(false);
|
|
|
+ const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
|
|
|
+
|
|
|
+ const handleRegister = (): void => {
|
|
|
+ if (!emailRegex.test(email)) {
|
|
|
+ setEmailError(true);
|
|
|
+ }
|
|
|
|
|
|
- googleRedirect = () => {
|
|
|
- let redirectUrl = `/api/oauth/login/google`;
|
|
|
- window.location.href = redirectUrl;
|
|
|
- };
|
|
|
+ if (firstName === "") {
|
|
|
+ setFirstNameError(true);
|
|
|
+ }
|
|
|
|
|
|
- handleRegister = (): void => {
|
|
|
- let { email, password, confirmPassword } = this.state;
|
|
|
- let { authenticate } = this.props;
|
|
|
- let { setCurrentError, setUser } = this.context;
|
|
|
+ if (lastName === "") {
|
|
|
+ setLastNameError(true);
|
|
|
+ }
|
|
|
|
|
|
- if (!emailRegex.test(email)) {
|
|
|
- this.setState({ emailError: true });
|
|
|
+ if (password === "") {
|
|
|
+ setPasswordError(true);
|
|
|
}
|
|
|
|
|
|
- if (confirmPassword !== password) {
|
|
|
- this.setState({ confirmPasswordError: true });
|
|
|
+ if (companyName === "") {
|
|
|
+ setCompanyNameError(true);
|
|
|
}
|
|
|
|
|
|
// Check for valid input
|
|
|
- if (emailRegex.test(email) && confirmPassword === password) {
|
|
|
+ if (
|
|
|
+ emailRegex.test(email) &&
|
|
|
+ firstName !== "" &&
|
|
|
+ lastName !== "" &&
|
|
|
+ password !== "" &&
|
|
|
+ companyName !== ""
|
|
|
+ ) {
|
|
|
// Attempt user registration
|
|
|
api
|
|
|
.registerUser(
|
|
|
"",
|
|
|
- {
|
|
|
+ {
|
|
|
email: email,
|
|
|
password: password,
|
|
|
+ first_name: firstName,
|
|
|
+ last_name: lastName,
|
|
|
+ company_name: companyName,
|
|
|
},
|
|
|
{}
|
|
|
)
|
|
|
@@ -106,183 +99,269 @@ export default class Register extends Component<PropsType, StateType> {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- renderEmailError = () => {
|
|
|
- let { emailError } = this.state;
|
|
|
- if (emailError) {
|
|
|
- return (
|
|
|
- <ErrorHelper>
|
|
|
- <div />
|
|
|
- Please enter a valid email
|
|
|
- </ErrorHelper>
|
|
|
- );
|
|
|
- }
|
|
|
+ const handleResize = () => {
|
|
|
+ setWindowDimensions(getWindowDimensions());
|
|
|
};
|
|
|
|
|
|
- renderConfirmPasswordError = () => {
|
|
|
- let { confirmPasswordError } = this.state;
|
|
|
- if (confirmPasswordError) {
|
|
|
- return (
|
|
|
- <ErrorHelper>
|
|
|
- <div />
|
|
|
- Passwords do not match
|
|
|
- </ErrorHelper>
|
|
|
- );
|
|
|
- }
|
|
|
+ const handleKeyDown = (e: any) => {
|
|
|
+ if (e.key === "Enter") {
|
|
|
+ handleRegister();
|
|
|
+ };
|
|
|
};
|
|
|
|
|
|
- renderGithubSection = () => {
|
|
|
- if (this.state.hasGithub) {
|
|
|
- return (
|
|
|
- <OAuthButton onClick={this.githubRedirect}>
|
|
|
- <IconWrapper>
|
|
|
- <Icon src={github} />
|
|
|
- Sign up with GitHub
|
|
|
- </IconWrapper>
|
|
|
- </OAuthButton>
|
|
|
- );
|
|
|
- }
|
|
|
+ // Manually re-register event listener on email/password change
|
|
|
+ useEffect(() => {
|
|
|
+ document.removeEventListener("keydown", handleKeyDown);
|
|
|
+ document.addEventListener("keydown", handleKeyDown);
|
|
|
+ return () => {
|
|
|
+ document.removeEventListener("keydown", handleKeyDown);
|
|
|
+ };
|
|
|
+ }, [email, password, firstName, lastName]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+
|
|
|
+ // Get capabilities to case on login methods
|
|
|
+ api.getMetadata("", {}, {})
|
|
|
+ .then((res) => {
|
|
|
+ setHasBasic(res.data?.basic_login);
|
|
|
+ setHasGithub(res.data?.github_login);
|
|
|
+ setHasGoogle(res.data?.google_login);
|
|
|
+ })
|
|
|
+ .catch((err) => console.log(err));
|
|
|
+
|
|
|
+ window.addEventListener('resize', handleResize);
|
|
|
+ return () => window.removeEventListener('resize', handleResize);
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const githubRedirect = () => {
|
|
|
+ let redirectUrl = `/api/oauth/login/github`;
|
|
|
+ window.location.href = redirectUrl;
|
|
|
};
|
|
|
|
|
|
- renderGoogleSection = () => {
|
|
|
- if (this.state.hasGoogle) {
|
|
|
- return (
|
|
|
- <OAuthButton onClick={this.googleRedirect}>
|
|
|
- <IconWrapper>
|
|
|
- <StyledGoogleIcon />
|
|
|
- Sign up with Google
|
|
|
- </IconWrapper>
|
|
|
- </OAuthButton>
|
|
|
- );
|
|
|
- }
|
|
|
+ const googleRedirect = () => {
|
|
|
+ let redirectUrl = `/api/oauth/login/google`;
|
|
|
+ window.location.href = redirectUrl;
|
|
|
};
|
|
|
|
|
|
- renderBasicSection = () => {
|
|
|
- let {
|
|
|
- email,
|
|
|
- password,
|
|
|
- confirmPassword,
|
|
|
- emailError,
|
|
|
- confirmPasswordError,
|
|
|
- } = this.state;
|
|
|
-
|
|
|
- if (this.state.hasBasic) {
|
|
|
- return (
|
|
|
- <div>
|
|
|
- <InputWrapper>
|
|
|
+ return (
|
|
|
+ <StyledRegister>
|
|
|
+ {windowDimensions.width > windowDimensions.height && (
|
|
|
+ <Wrapper>
|
|
|
+ <Logo src={logo} />
|
|
|
+ <Spacer y={2} />
|
|
|
+ <Jumbotron>
|
|
|
+ Deploy and scale <Shiny>effortlessly</Shiny> with Porter
|
|
|
+ </Jumbotron>
|
|
|
+ <Spacer y={2} />
|
|
|
+ <CheckRow>
|
|
|
+ <i className="material-icons">done</i> Generous free tier for small teams
|
|
|
+ </CheckRow>
|
|
|
+ <Spacer y={0.5} />
|
|
|
+ <CheckRow>
|
|
|
+ <i className="material-icons">done</i> Bring your own cloud (and cloud credits)
|
|
|
+ </CheckRow>
|
|
|
+ <Spacer y={0.5} />
|
|
|
+ <CheckRow>
|
|
|
+ <i className="material-icons">done</i> Fully automated setup and deployment
|
|
|
+ </CheckRow>
|
|
|
+ </Wrapper>
|
|
|
+ )}
|
|
|
+ <Wrapper>
|
|
|
+ {windowDimensions.width <= windowDimensions.height && (
|
|
|
+ <Flex>
|
|
|
+ <Logo src={logo} />
|
|
|
+ <Spacer y={2} />
|
|
|
+ </Flex>
|
|
|
+ )}
|
|
|
+ <Heading isAtTop>
|
|
|
+ Create your Porter account
|
|
|
+ </Heading>
|
|
|
+ <Spacer y={1} />
|
|
|
+ {(hasGithub || hasGoogle) && (
|
|
|
+ <>
|
|
|
+ <Container row>
|
|
|
+ {hasGithub && (
|
|
|
+ <OAuthButton onClick={githubRedirect}>
|
|
|
+ <Icon src={github} />
|
|
|
+ Sign up with GitHub
|
|
|
+ </OAuthButton>
|
|
|
+ )}
|
|
|
+ {hasGithub && hasGoogle && (
|
|
|
+ <Spacer inline x={2} />
|
|
|
+ )}
|
|
|
+ {hasGoogle && (
|
|
|
+ <OAuthButton onClick={googleRedirect}>
|
|
|
+ <StyledGoogleIcon />
|
|
|
+ Sign up with Google
|
|
|
+ </OAuthButton>
|
|
|
+ )}
|
|
|
+ </Container>
|
|
|
+ {hasBasic && (
|
|
|
+ <OrWrapper>
|
|
|
+ <Line />
|
|
|
+ <Or>or</Or>
|
|
|
+ </OrWrapper>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+ {hasBasic && (
|
|
|
+ <>
|
|
|
+ <Container row>
|
|
|
+ <RowWrapper>
|
|
|
+ <Input
|
|
|
+ placeholder="First name"
|
|
|
+ label="First name"
|
|
|
+ value={firstName}
|
|
|
+ setValue={(x) => {
|
|
|
+ setFirstName(x);
|
|
|
+ setFirstNameError(false);
|
|
|
+ }}
|
|
|
+ width="100%"
|
|
|
+ height="40px"
|
|
|
+ error={(firstNameError && "First name cannot be blank")}
|
|
|
+ />
|
|
|
+ {!firstNameError && lastNameError && (
|
|
|
+ <Spacer height="27px" />
|
|
|
+ )}
|
|
|
+ </RowWrapper>
|
|
|
+ <Spacer inline x={2} />
|
|
|
+ <RowWrapper>
|
|
|
+ <Input
|
|
|
+ placeholder="Last name"
|
|
|
+ label="Last name"
|
|
|
+ value={lastName}
|
|
|
+ setValue={(x) => {
|
|
|
+ setLastName(x);
|
|
|
+ setLastNameError(false);
|
|
|
+ }}
|
|
|
+ width="100%"
|
|
|
+ height="40px"
|
|
|
+ error={(lastNameError && "Last name cannot be blank")}
|
|
|
+ />
|
|
|
+ {!lastNameError && firstNameError && (
|
|
|
+ <Spacer height="27px" />
|
|
|
+ )}
|
|
|
+ </RowWrapper>
|
|
|
+ </Container>
|
|
|
+ <Spacer y={1} />
|
|
|
+ <Input
|
|
|
+ placeholder="Company name"
|
|
|
+ label="Company name"
|
|
|
+ value={companyName}
|
|
|
+ setValue={(x) => {
|
|
|
+ setCompanyName(x);
|
|
|
+ setCompanyNameError(false);
|
|
|
+ }}
|
|
|
+ width="100%"
|
|
|
+ height="40px"
|
|
|
+ error={(companyNameError && "")}
|
|
|
+ />
|
|
|
+ <Spacer y={1} />
|
|
|
<Input
|
|
|
type="email"
|
|
|
placeholder="Email"
|
|
|
+ label="Email"
|
|
|
value={email}
|
|
|
- onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
|
|
- this.setState({ email: e.target.value, emailError: false })
|
|
|
- }
|
|
|
- valid={!emailError}
|
|
|
+ setValue={(x) => {
|
|
|
+ setEmail(x);
|
|
|
+ setEmailError(false);
|
|
|
+ }}
|
|
|
+ width="100%"
|
|
|
+ height="40px"
|
|
|
+ error={(emailError && "Please enter a valid email")}
|
|
|
/>
|
|
|
- {this.renderEmailError()}
|
|
|
- </InputWrapper>
|
|
|
- <Input
|
|
|
- type="password"
|
|
|
- placeholder="Password"
|
|
|
- value={password}
|
|
|
- onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
|
|
- this.setState({
|
|
|
- password: e.target.value,
|
|
|
- confirmPasswordError: false,
|
|
|
- })
|
|
|
- }
|
|
|
- valid={true}
|
|
|
- />
|
|
|
- <InputWrapper>
|
|
|
+ <Spacer y={1} />
|
|
|
<Input
|
|
|
+ placeholder="Password"
|
|
|
+ label="Password"
|
|
|
+ value={password}
|
|
|
+ setValue={setPassword}
|
|
|
+ width="100%"
|
|
|
+ height="40px"
|
|
|
type="password"
|
|
|
- placeholder="Confirm Password"
|
|
|
- value={confirmPassword}
|
|
|
- onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
|
|
- this.setState({
|
|
|
- confirmPassword: e.target.value,
|
|
|
- confirmPasswordError: false,
|
|
|
- })
|
|
|
- }
|
|
|
- valid={!confirmPasswordError}
|
|
|
+ error={(passwordError && "")}
|
|
|
/>
|
|
|
- {this.renderConfirmPasswordError()}
|
|
|
- </InputWrapper>
|
|
|
- <Button onClick={this.handleRegister}>Continue</Button>
|
|
|
- </div>
|
|
|
- );
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- render() {
|
|
|
- return (
|
|
|
- <StyledRegister>
|
|
|
- <LoginPanel
|
|
|
- hasBasic={this.state.hasBasic}
|
|
|
- numOAuth={+this.state.hasGithub + +this.state.hasGoogle}
|
|
|
+ <Spacer height="30px" />
|
|
|
+ <Button onClick={handleRegister} width="100%" height="40px">
|
|
|
+ Continue
|
|
|
+ </Button>
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+ <Spacer y={1} />
|
|
|
+ <Text
|
|
|
+ size={13}
|
|
|
+ color="helper"
|
|
|
>
|
|
|
- <OverflowWrapper>
|
|
|
- <GradientBg />
|
|
|
- </OverflowWrapper>
|
|
|
- <FormWrapper>
|
|
|
- <Logo src={logo} />
|
|
|
- <Prompt>Sign up for Porter</Prompt>
|
|
|
- {this.renderGithubSection()}
|
|
|
- {this.renderGoogleSection()}
|
|
|
- {(this.state.hasGithub || this.state.hasGoogle) &&
|
|
|
- this.state.hasBasic ? (
|
|
|
- <OrWrapper>
|
|
|
- <Line />
|
|
|
- <Or>or</Or>
|
|
|
- </OrWrapper>
|
|
|
- ) : null}
|
|
|
- <DarkMatter />
|
|
|
- {this.renderBasicSection()}
|
|
|
- <Helper>
|
|
|
- Have an account?
|
|
|
- <Link href="/login">Sign in</Link>
|
|
|
- </Helper>
|
|
|
- </FormWrapper>
|
|
|
- </LoginPanel>
|
|
|
- <Footer>
|
|
|
- © 2021 Porter Technologies Inc. •
|
|
|
- <Link
|
|
|
- href="https://docs.getporter.dev/docs/terms-of-service"
|
|
|
- target="_blank"
|
|
|
- >
|
|
|
- Terms & Privacy
|
|
|
- </Link>
|
|
|
- </Footer>
|
|
|
- </StyledRegister>
|
|
|
- );
|
|
|
- }
|
|
|
-}
|
|
|
+ Already have an account? <Link to="/login">Log in</Link>
|
|
|
+ </Text>
|
|
|
+ </Wrapper>
|
|
|
+ </StyledRegister>
|
|
|
+ );
|
|
|
+};
|
|
|
|
|
|
-Register.contextType = Context;
|
|
|
+export default Register;
|
|
|
|
|
|
-const Footer = styled.div`
|
|
|
- position: absolute;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- margin-bottom: 30px;
|
|
|
- width: 100vw;
|
|
|
- text-align: center;
|
|
|
+const RowWrapper = styled.div`
|
|
|
+ width: 100%;
|
|
|
+`;
|
|
|
+
|
|
|
+const Flex = styled.div`
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ flex-direction: column;
|
|
|
+`;
|
|
|
+
|
|
|
+const CheckRow = styled.div`
|
|
|
+ font-size: 14px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
color: #aaaabb;
|
|
|
- font-size: 13px;
|
|
|
- padding-right: 8px;
|
|
|
- font: Work Sans, sans-serif;
|
|
|
+ > i {
|
|
|
+ font-size: 18px;
|
|
|
+ margin-right: 10px;
|
|
|
+ float: left;
|
|
|
+ color: #4797ff;
|
|
|
+ }
|
|
|
`;
|
|
|
|
|
|
-const DarkMatter = styled.div`
|
|
|
- margin-top: -10px;
|
|
|
+const Shiny = styled.span`
|
|
|
+ background-image: linear-gradient(225deg, #fff, #7980ff);
|
|
|
+ -webkit-background-clip: text;
|
|
|
+ background-clip: text;
|
|
|
+ -webkit-text-fill-color: transparent;
|
|
|
+`;
|
|
|
+
|
|
|
+const Jumbotron = styled.div`
|
|
|
+ font-size: 32px;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 1.5;
|
|
|
+`;
|
|
|
+
|
|
|
+const Logo = styled.img`
|
|
|
+ height: 24px;
|
|
|
+ user-select: none;
|
|
|
+`;
|
|
|
+
|
|
|
+const StyledGoogleIcon = styled(GoogleIcon)`
|
|
|
+ width: 38px;
|
|
|
+ height: 38px;
|
|
|
+`;
|
|
|
+
|
|
|
+const Line = styled.div`
|
|
|
+ height: 2px;
|
|
|
+ width: 100%;
|
|
|
+ background: #ffffff22;
|
|
|
+ margin: 35px 0px 30px;
|
|
|
`;
|
|
|
|
|
|
const Or = styled.div`
|
|
|
position: absolute;
|
|
|
- width: 30px;
|
|
|
+ width: 50px;
|
|
|
text-align: center;
|
|
|
background: #111114;
|
|
|
z-index: 999;
|
|
|
- left: calc(50% - 15px);
|
|
|
+ left: calc(50% - 25px);
|
|
|
margin-top: -1px;
|
|
|
`;
|
|
|
|
|
|
@@ -294,192 +373,35 @@ const OrWrapper = styled.div`
|
|
|
position: relative;
|
|
|
`;
|
|
|
|
|
|
-const IconWrapper = styled.div`
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 0 10px;
|
|
|
- height: 100%;
|
|
|
-`;
|
|
|
-
|
|
|
const Icon = styled.img`
|
|
|
height: 18px;
|
|
|
margin: 14px;
|
|
|
`;
|
|
|
|
|
|
-const StyledGoogleIcon = styled(GoogleIcon)`
|
|
|
- width: 38px;
|
|
|
- height: 38px;
|
|
|
-`;
|
|
|
-
|
|
|
const OAuthButton = styled.div`
|
|
|
- width: 200px;
|
|
|
- height: 30px;
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
display: flex;
|
|
|
background: #ffffff;
|
|
|
align-items: center;
|
|
|
- border-radius: 3px;
|
|
|
+ border-radius: 5px;
|
|
|
color: #000000;
|
|
|
cursor: pointer;
|
|
|
user-select: none;
|
|
|
font-weight: 500;
|
|
|
font-size: 13px;
|
|
|
- margin: 10px 0;
|
|
|
- overflow: hidden;
|
|
|
:hover {
|
|
|
background: #ffffffdd;
|
|
|
}
|
|
|
`;
|
|
|
|
|
|
-const Link = styled.a`
|
|
|
- margin-left: 5px;
|
|
|
- color: #819bfd;
|
|
|
-`;
|
|
|
-
|
|
|
-const Helper = styled.div`
|
|
|
- position: absolute;
|
|
|
- bottom: 30px;
|
|
|
- width: 100%;
|
|
|
- text-align: center;
|
|
|
- font-size: 13px;
|
|
|
- font-family: "Work Sans", sans-serif;
|
|
|
- color: #ffffff44;
|
|
|
-`;
|
|
|
-
|
|
|
-const OverflowWrapper = styled.div`
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- overflow: hidden;
|
|
|
- border-radius: 10px;
|
|
|
-`;
|
|
|
-
|
|
|
-const InputWrapper = styled.div`
|
|
|
- position: relative;
|
|
|
-`;
|
|
|
-
|
|
|
-const ErrorHelper = styled.div`
|
|
|
- position: absolute;
|
|
|
- right: -185px;
|
|
|
- top: 8px;
|
|
|
- height: 30px;
|
|
|
- width: 170px;
|
|
|
- user-select: none;
|
|
|
- background: #272731;
|
|
|
- font-family: "Work Sans", sans-serif;
|
|
|
- font-size: 12px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- color: #ff3b62;
|
|
|
- border-radius: 3px;
|
|
|
-
|
|
|
- > div {
|
|
|
- background: #272731;
|
|
|
- height: 15px;
|
|
|
- width: 15px;
|
|
|
- position: absolute;
|
|
|
- left: -3px;
|
|
|
- top: 7px;
|
|
|
- transform: rotate(45deg);
|
|
|
- z-index: -1;
|
|
|
- }
|
|
|
-`;
|
|
|
-
|
|
|
-const Line = styled.div`
|
|
|
- height: 3px;
|
|
|
- width: 100px;
|
|
|
- background: #ffffff22;
|
|
|
- margin: 35px 0px 30px;
|
|
|
-`;
|
|
|
-
|
|
|
-const Button = styled.button`
|
|
|
- width: 200px;
|
|
|
- height: 30px;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- font-family: "Work Sans", sans-serif;
|
|
|
- cursor: pointer;
|
|
|
- margin-top: 9px;
|
|
|
- border-radius: 2px;
|
|
|
- border: 0;
|
|
|
- background: #819bfd;
|
|
|
- color: white;
|
|
|
- font-weight: 500;
|
|
|
- font-size: 14px;
|
|
|
-`;
|
|
|
-
|
|
|
-const Input = styled.input`
|
|
|
- width: 200px;
|
|
|
- font-family: "Work Sans", sans-serif;
|
|
|
- margin: 8px 0px;
|
|
|
- height: 30px;
|
|
|
- padding: 8px;
|
|
|
- background: #ffffff12;
|
|
|
- color: #ffffff;
|
|
|
- border: ${(props: { valid?: boolean }) =>
|
|
|
- props.valid ? "0" : "1px solid #ff3b62"};
|
|
|
- border-radius: 2px;
|
|
|
- font-size: 14px;
|
|
|
-`;
|
|
|
-
|
|
|
-const Prompt = styled.div`
|
|
|
- font-family: "Work Sans", sans-serif;
|
|
|
- font-weight: 500;
|
|
|
- font-size: 15px;
|
|
|
- margin-bottom: 18px;
|
|
|
-`;
|
|
|
-
|
|
|
-const Logo = styled.img`
|
|
|
- width: 110px;
|
|
|
- margin-top: 45px;
|
|
|
- margin-bottom: 30px;
|
|
|
- user-select: none;
|
|
|
-`;
|
|
|
-
|
|
|
-const FormWrapper = styled.div`
|
|
|
- width: calc(100% - 8px);
|
|
|
- height: calc(100% - 8px);
|
|
|
- background: #111114;
|
|
|
- z-index: 1;
|
|
|
- border-radius: 10px;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
-`;
|
|
|
-
|
|
|
-const GradientBg = styled.div`
|
|
|
- background: linear-gradient(#8ce1ff, #a59eff, #fba8ff);
|
|
|
- width: 200%;
|
|
|
- height: 200%;
|
|
|
- position: absolute;
|
|
|
- top: -50%;
|
|
|
- left: -50%;
|
|
|
- animation: flip 6s infinite linear;
|
|
|
- @keyframes flip {
|
|
|
- from {
|
|
|
- transform: rotate(0deg);
|
|
|
- }
|
|
|
- to {
|
|
|
- transform: rotate(360deg);
|
|
|
- }
|
|
|
- }
|
|
|
-`;
|
|
|
-
|
|
|
-const LoginPanel = styled.div`
|
|
|
- width: 330px;
|
|
|
- height: ${(props: { numOAuth: number; hasBasic: boolean }) =>
|
|
|
- 270 + +props.hasBasic * 180 + props.numOAuth * 50}px;
|
|
|
- background: white;
|
|
|
+const Wrapper = styled.div`
|
|
|
+ width: 500px;
|
|
|
margin-top: -20px;
|
|
|
- border-radius: 10px;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
position: relative;
|
|
|
- align-items: center;
|
|
|
+ padding: 25px;
|
|
|
+ border-radius: 5px;
|
|
|
+ font-size: 13px;
|
|
|
`;
|
|
|
|
|
|
const StyledRegister = styled.div`
|
|
|
@@ -492,4 +414,4 @@ const StyledRegister = styled.div`
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
background: #111114;
|
|
|
-`;
|
|
|
+`;
|