mirror of
https://github.com/spacebarchat/client.git
synced 2024-11-25 03:32:54 +01:00
button component, input error changes
This commit is contained in:
parent
b3ea83a561
commit
ac6ded3387
91
src/components/Button.tsx
Normal file
91
src/components/Button.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
interface Props {
|
||||
variant?: "primary" | "secondary" | "danger" | "success" | "warning";
|
||||
outlined?: boolean;
|
||||
}
|
||||
|
||||
export default styled.button<Props>`
|
||||
background: ${(props) => {
|
||||
if (props.outlined) return "transparent";
|
||||
switch (props.variant) {
|
||||
case "primary":
|
||||
return "var(--button-primary)";
|
||||
case "secondary":
|
||||
return "var(--button-secondary)";
|
||||
case "danger":
|
||||
return "var(--button-danger)";
|
||||
case "success":
|
||||
return "var(--button-success)";
|
||||
case "warning":
|
||||
return "var(--button-warning)";
|
||||
default:
|
||||
return "var(--button-primary)";
|
||||
}
|
||||
}};
|
||||
|
||||
border: ${(props) => {
|
||||
if (!props.outlined) return "none";
|
||||
switch (props.variant) {
|
||||
case "primary":
|
||||
return "1px solid var(--button-primary)";
|
||||
case "secondary":
|
||||
return "1px solid var(--button-secondary)";
|
||||
case "danger":
|
||||
return "1px solid var(--button-danger)";
|
||||
case "success":
|
||||
return "1px solid var(--button-success)";
|
||||
case "warning":
|
||||
return "1px solid var(--button-warning)";
|
||||
default:
|
||||
return "1px solid var(--button-primary)";
|
||||
}
|
||||
}};
|
||||
|
||||
color: var(--text);
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: background 0.2s ease-in-out;
|
||||
pointer-events:${(props) => (props.disabled ? "none" : null)};
|
||||
opacity: ${(props) => (props.disabled ? 0.5 : 1)};
|
||||
|
||||
&:hover {
|
||||
background: ${(props) => {
|
||||
switch (props.variant) {
|
||||
case "primary":
|
||||
return "var(--button-primary-hover)";
|
||||
case "secondary":
|
||||
return "var(--button-secondary-hover)";
|
||||
case "danger":
|
||||
return "var(--button-danger-hover)";
|
||||
case "success":
|
||||
return "var(--button-success-hover)";
|
||||
case "warning":
|
||||
return "var(--button-warning-hover)";
|
||||
default:
|
||||
return "var(--button-primary-hover)";
|
||||
}
|
||||
}};
|
||||
|
||||
&:active {
|
||||
background: ${(props) => {
|
||||
switch (props.variant) {
|
||||
case "primary":
|
||||
return "var(--button-primary-active)";
|
||||
case "secondary":
|
||||
return "var(--button-secondary-active)";
|
||||
case "danger":
|
||||
return "var(--button-danger-active)";
|
||||
case "success":
|
||||
return "var(--button-success-active)";
|
||||
case "warning":
|
||||
return "var(--button-warning-active)";
|
||||
default:
|
||||
return "var(--button-primary-active)";
|
||||
}
|
||||
}};
|
||||
`;
|
@ -11,7 +11,23 @@ export type ThemeVariables =
|
||||
| "tertiary"
|
||||
| "text"
|
||||
| "textMuted"
|
||||
| "inputBackground";
|
||||
| "inputBackground"
|
||||
| "error"
|
||||
| "buttonPrimary"
|
||||
| "buttonPrimaryHover"
|
||||
| "buttonPrimaryActive"
|
||||
| "buttonSecondary"
|
||||
| "buttonSecondaryHover"
|
||||
| "buttonSecondaryActive"
|
||||
| "buttonDanger"
|
||||
| "buttonDangerHover"
|
||||
| "buttonDangerActive"
|
||||
| "buttonSuccess"
|
||||
| "buttonSuccessHover"
|
||||
| "buttonSuccessActive"
|
||||
| "buttonWarning"
|
||||
| "buttonWarningHover"
|
||||
| "buttonWarningActive";
|
||||
|
||||
export type Overrides = {
|
||||
[variable in ThemeVariables]: string;
|
||||
@ -32,6 +48,22 @@ export const ThemePresets: Record<string, Theme> = {
|
||||
text: "#000000",
|
||||
textMuted: "#232120",
|
||||
inputBackground: "#757575",
|
||||
error: "#e83f36",
|
||||
buttonPrimary: "",
|
||||
buttonPrimaryHover: "",
|
||||
buttonPrimaryActive: "",
|
||||
buttonSecondary: "",
|
||||
buttonSecondaryHover: "",
|
||||
buttonSecondaryActive: "",
|
||||
buttonDanger: "",
|
||||
buttonDangerHover: "",
|
||||
buttonDangerActive: "",
|
||||
buttonSuccess: "",
|
||||
buttonSuccessHover: "",
|
||||
buttonSuccessActive: "",
|
||||
buttonWarning: "",
|
||||
buttonWarningHover: "",
|
||||
buttonWarningActive: "",
|
||||
},
|
||||
dark: {
|
||||
brandPrimary: "#FF5F00",
|
||||
@ -43,6 +75,23 @@ export const ThemePresets: Record<string, Theme> = {
|
||||
text: "#e9e2e1",
|
||||
textMuted: "#85898f",
|
||||
inputBackground: "#121212",
|
||||
error: "#e83f36",
|
||||
// buttons
|
||||
buttonPrimary: "#FF5F00",
|
||||
buttonPrimaryHover: "#ff3d00",
|
||||
buttonPrimaryActive: "#BA4500",
|
||||
buttonSecondary: "#4a4544",
|
||||
buttonSecondaryHover: "#746d69",
|
||||
buttonSecondaryActive: "#5f5a59",
|
||||
buttonDanger: "#ff3a3b",
|
||||
buttonDangerHover: "#ff2d2f",
|
||||
buttonDangerActive: "#ff2425",
|
||||
buttonSuccess: "#34af65",
|
||||
buttonSuccessHover: "#31a660",
|
||||
buttonSuccessActive: "#2d9657",
|
||||
buttonWarning: "#faa61a",
|
||||
buttonWarningHover: "#e69105",
|
||||
buttonWarningActive: "#c27b04",
|
||||
},
|
||||
};
|
||||
|
||||
@ -52,6 +101,9 @@ const GlobalTheme = createGlobalStyle<{ theme: Theme }>`
|
||||
}
|
||||
`;
|
||||
|
||||
const toDashed = (str: string) =>
|
||||
str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
||||
|
||||
export const generateVariables = (theme: Theme) => {
|
||||
return (Object.keys(theme) as ThemeVariables[]).map((key) => {
|
||||
const colour = theme[key];
|
||||
@ -59,9 +111,11 @@ export const generateVariables = (theme: Theme) => {
|
||||
const r = parseInt(colour.substring(1, 3), 16);
|
||||
const g = parseInt(colour.substring(3, 5), 16);
|
||||
const b = parseInt(colour.substring(5, 7), 16);
|
||||
return `--${key}: ${theme[key]}; --${key}-rgb: rgb(${r}, ${g}, ${b});`;
|
||||
return `--${toDashed(key)}: ${theme[key]}; --${toDashed(
|
||||
key
|
||||
)}-rgb: rgb(${r}, ${g}, ${b});`;
|
||||
} catch {
|
||||
return `--${key}: ${theme[key]};`;
|
||||
return `--${toDashed(key)}: ${theme[key]};`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { useForm } from "react-hook-form";
|
||||
import styled from "styled-components";
|
||||
import Button from "../components/Button";
|
||||
import Container from "../components/Container";
|
||||
|
||||
const Wrapper = styled(Container)`
|
||||
@ -11,10 +12,10 @@ const Wrapper = styled(Container)`
|
||||
`;
|
||||
|
||||
const LoginBox = styled(Container)`
|
||||
background-color: var(--primaryAlt);
|
||||
background-color: var(--primary-alt);
|
||||
padding: 32px;
|
||||
font-size: 18px;
|
||||
color: var(--textMuted);
|
||||
color: var(--text-muted);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@ -43,7 +44,7 @@ const Header = styled.h1`
|
||||
`;
|
||||
|
||||
const SubHeader = styled.h2`
|
||||
color: var(--textMuted);
|
||||
color: var(--text-muted);
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
`;
|
||||
@ -59,9 +60,20 @@ const InputContainer = styled.h1<{ marginBottom: boolean }>`
|
||||
align-items: flex-start;
|
||||
`;
|
||||
|
||||
const InputLabel = styled.label`
|
||||
color: #b1b5bc;
|
||||
const LabelWrapper = styled.div<{ error?: boolean }>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 8px;
|
||||
color: ${(props) => (props.error ? "var(--error)" : "#b1b5bc")};
|
||||
`;
|
||||
|
||||
const InputErrorText = styled.label`
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
`;
|
||||
|
||||
const InputLabel = styled.label`
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
`;
|
||||
@ -71,7 +83,7 @@ const InputWrapper = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const Input = styled.input<{invalid?: boolean}>`
|
||||
const Input = styled.input<{ error?: boolean }>`
|
||||
outline: none;
|
||||
background: var(--secondary);
|
||||
padding: 10px;
|
||||
@ -80,8 +92,8 @@ const Input = styled.input<{invalid?: boolean}>`
|
||||
border-radius: 12px;
|
||||
color: var(--text);
|
||||
margin: 0;
|
||||
border: ${(props) => props.invalid ? "1px solid red" : "none"};
|
||||
aria-invalid: ${(props) => props.invalid ? "true" : "false"};
|
||||
border: none;
|
||||
aria-invalid: ${(props) => (props.error ? "true" : "false")};
|
||||
`;
|
||||
|
||||
const PasswordResetLink = styled.a`
|
||||
@ -93,16 +105,11 @@ const PasswordResetLink = styled.a`
|
||||
text-decoration: none;
|
||||
`;
|
||||
|
||||
const Button = styled.button`
|
||||
background: var(--brandPrimary);
|
||||
color: var(--text);
|
||||
font-size: 16px;
|
||||
const LoginButton = styled(Button)`
|
||||
margin-bottom: 8px;
|
||||
width: 100%;
|
||||
min-width: 130px;
|
||||
min-height: 44px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
`;
|
||||
|
||||
const RegisterContainer = styled.div`
|
||||
@ -123,11 +130,18 @@ const RegisterLink = styled.a`
|
||||
}
|
||||
`;
|
||||
|
||||
function LoginPage() {
|
||||
const { register, handleSubmit, watch, formState: { errors } } = useForm();
|
||||
const onSubmit = (data: any) => console.log(data);
|
||||
const Divider = styled.span`
|
||||
padding: 0 4px;
|
||||
`;
|
||||
|
||||
console.log(errors)
|
||||
function LoginPage() {
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
watch,
|
||||
formState: { errors },
|
||||
} = useForm();
|
||||
const onSubmit = (data: any) => console.log(data);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
@ -139,21 +153,46 @@ function LoginPage() {
|
||||
|
||||
<FormContainer onSubmit={handleSubmit(onSubmit)}>
|
||||
<InputContainer marginBottom={true} style={{ marginTop: 0 }}>
|
||||
<LabelWrapper error={!!errors.email}>
|
||||
<InputLabel>Email</InputLabel>
|
||||
{errors.email && (
|
||||
<InputErrorText>
|
||||
<Divider>-</Divider>Email error here
|
||||
</InputErrorText>
|
||||
)}
|
||||
</LabelWrapper>
|
||||
<InputWrapper>
|
||||
<Input type="email" autoFocus {...register("email", {required: true})} invalid={!!errors.email} />
|
||||
<Input
|
||||
type="email"
|
||||
autoFocus
|
||||
{...register("email", { required: true })}
|
||||
error={!!errors.email}
|
||||
/>
|
||||
</InputWrapper>
|
||||
</InputContainer>
|
||||
|
||||
<InputContainer marginBottom={false}>
|
||||
<LabelWrapper error={!!errors.password}>
|
||||
<InputLabel>Password</InputLabel>
|
||||
{errors.password && (
|
||||
<InputErrorText>
|
||||
<Divider>-</Divider>Password error here
|
||||
</InputErrorText>
|
||||
)}
|
||||
</LabelWrapper>
|
||||
<InputWrapper>
|
||||
<Input type="password" {...register("password", {required: true})} invalid={!!errors.password} />
|
||||
<Input
|
||||
type="password"
|
||||
{...register("password", { required: true })}
|
||||
error={!!errors.password}
|
||||
/>
|
||||
</InputWrapper>
|
||||
</InputContainer>
|
||||
|
||||
<PasswordResetLink href="#">Forgot your password?</PasswordResetLink>
|
||||
<Button type="submit">Log In</Button>
|
||||
<LoginButton variant="primary" type="submit">
|
||||
Log In
|
||||
</LoginButton>
|
||||
|
||||
<RegisterContainer>
|
||||
<RegisterLabel>Don't have an account? </RegisterLabel>
|
||||
|
Loading…
Reference in New Issue
Block a user