update look and feel of login

This commit is contained in:
2025-10-03 20:26:35 -04:00
parent e63615eb46
commit 56ec490159
4 changed files with 364 additions and 84 deletions

View File

@@ -1,39 +1,67 @@
import { useState } from 'react'; import { useState } from 'react';
import ILoginFormPops from './ILoginFormProps'; import type { ILoginFormProps } from './ILoginFormProps';
import { Input } from './Styled'; import { FlexForm, Input, Button, FormTitle, FormSubtitle, InputContainer, ErrorMessage } from './Styled';
export function LoginForm({ onSubmit }: ILoginFormProps) { export function LoginForm({ onSubmit }: ILoginFormProps) {
const [username, setUsername] = useState<string>(''); const [username, setUsername] = useState<string>('');
const [secret, setSecret] = useState<string>(''); const [secret, setSecret] = useState<string>('');
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<string>('');
// The submit handler now correctly uses 'event' const handleFormSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
const handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault(); event.preventDefault();
onSubmit(username, secret);
if (!username.trim() || !secret.trim()) {
setError('Please fill in all fields');
return;
}
setIsLoading(true);
setError('');
try {
await onSubmit(username, secret);
} catch (err) {
setError('Login failed. Please try again.');
} finally {
setIsLoading(false);
}
}; };
return ( return (
<form onSubmit={handleFormSubmit}> <FlexForm onSubmit={handleFormSubmit}>
{/* <FormTitle>Welcome Back</FormTitle>
- The 'placeholder' prop is now lowercase. <FormSubtitle>Sign in to your account to continue</FormSubtitle>
- The 'onChange' handler correctly destructures {target}.
*/} <InputContainer>
<Input <Input
type="text" type="text"
placeholder="Username" placeholder="Enter your username"
autoComplete="username" autoComplete="username"
value={username} value={username}
onChange={({ target }) => setUsername(target.value)} onChange={({ target }) => setUsername(target.value)}
disabled={isLoading}
required
/> />
</InputContainer>
<InputContainer>
<Input <Input
type="password" type="password"
placeholder="Password" placeholder="Enter your password"
autoComplete="current-password" autoComplete="current-password"
value={secret} value={secret}
onChange={({ target }) => setSecret(target.value)} onChange={({ target }) => setSecret(target.value)}
disabled={isLoading}
required
/> />
</InputContainer>
<button type="submit">Login</button> {error && <ErrorMessage>{error}</ErrorMessage>}
</form>
<Button type="submit" disabled={isLoading}>
{isLoading ? 'Signing In...' : 'Sign In'}
</Button>
</FlexForm>
); );
} }

View File

@@ -1,15 +1,154 @@
import styled from 'styled-components'; import styled, { keyframes } from 'styled-components';
const fadeIn = keyframes`
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
`;
const industrialGlow = keyframes`
0% {
box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.1);
}
50% {
box-shadow: 0 0 0 8px rgba(255, 255, 255, 0.05);
}
100% {
box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.1);
}
`;
export const FlexForm = styled.form`
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 3rem 3rem 3rem 3rem;
background: #2a2a2a;
border: 2px solid #111111;
border-radius: 0;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
animation: ${fadeIn} 0.6s ease-out;
width: 450px;
box-sizing: border-box;
&:focus {
outline: none;
}
`;
export const Input = styled.input` export const Input = styled.input`
width: 100%; width: 100%;
heght: 1.3rem; padding: 1rem 1.25rem;
backgroundColor: blue font-size: 0.9rem;
` font-weight: 400;
font-family: 'Courier New', monospace;
background: #0a0a0a;
border: 1px solid #404040;
border-radius: 0;
color: #ffffff;
transition: all 0.2s ease;
text-transform: uppercase;
letter-spacing: 1px;
box-sizing: border-box;
&::placeholder {
color: #666666;
font-weight: 400;
text-transform: uppercase;
letter-spacing: 1px;
}
&:focus {
outline: none;
border-color: #ffffff;
background: #000000;
}
&:hover {
border-color: #666666;
}
`;
export const Button = styled.button` export const Button = styled.button`
width: fit-content; width: 100%;
margin: auto; padding: 1.1rem 1.5rem;
text-align: center; font-size: 0.95rem;
background-color: #a7c42; font-weight: 600;
font-family: 'Courier New', monospace;
background: #000000;
color: #ffffff;
border: 2px solid #ffffff;
border-radius: 0;
cursor: pointer;
transition: all 0.2s ease;
text-transform: uppercase;
letter-spacing: 2px;
margin-top: 0.5rem;
box-sizing: border-box;
` &:hover {
background: #ffffff;
color: #000000;
}
&:active {
background: #333333;
color: #ffffff;
border-color: #cccccc;
}
&:disabled {
opacity: 0.4;
cursor: not-allowed;
border-color: #666666;
color: #666666;
}
`;
export const FormTitle = styled.h1`
font-size: 1.4rem;
font-weight: 700;
font-family: 'Courier New', monospace;
color: #ffffff;
text-align: center;
margin: 0 0 0.5rem 0;
text-transform: uppercase;
letter-spacing: 3px;
`;
export const FormSubtitle = styled.p`
font-size: 0.75rem;
font-family: 'Courier New', monospace;
color: #999999;
text-align: center;
margin: 0 0 1.5rem 0;
font-weight: 400;
line-height: 1.5;
text-transform: uppercase;
letter-spacing: 1px;
`;
export const InputContainer = styled.div`
width: 100%;
`;
export const ErrorMessage = styled.div`
color: #ffffff;
font-size: 0.8rem;
font-weight: 400;
font-family: 'Courier New', monospace;
text-align: center;
padding: 0.75rem 1rem;
background: #000000;
border: 1px solid #333333;
border-radius: 0;
margin: 0.5rem 0;
text-transform: uppercase;
letter-spacing: 1px;
animation: ${fadeIn} 0.3s ease-out;
`;

View File

@@ -1,11 +1,13 @@
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700;800;900&display=swap');
:root { :root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; font-family: 'JetBrains Mono', 'Courier New', monospace;
line-height: 1.5; line-height: 1.4;
font-weight: 400; font-weight: 400;
color-scheme: light dark; color-scheme: dark;
color: rgba(255, 255, 255, 0.87); color: #ffffff;
background-color: #242424; background-color: #000000;
font-synthesis: none; font-synthesis: none;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
@@ -13,56 +15,142 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
a { * {
font-weight: 500; box-sizing: border-box;
color: #646cff; margin: 0;
text-decoration: inherit; padding: 0;
} }
a:hover {
color: #535bf2; html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow-x: hidden;
background-color: #000000;
} }
body { body {
margin: 0; margin: 0;
display: flex; padding: 0;
place-items: center; width: 100%;
min-width: 320px; height: 100%;
min-height: 100vh; overflow-x: hidden;
background:
radial-gradient(circle at 25% 25%, rgba(255, 255, 255, 0.01) 0%, transparent 50%),
radial-gradient(circle at 75% 75%, rgba(255, 255, 255, 0.01) 0%, transparent 50%),
linear-gradient(135deg, #000000 0%, #0a0a0a 50%, #000000 100%);
background-attachment: fixed;
}
#root {
margin: 0;
padding: 0;
width: 100%;
height: 100vh;
overflow-x: hidden;
}
a {
font-weight: 600;
color: #ffffff;
text-decoration: none;
text-transform: uppercase;
letter-spacing: 1px;
transition: all 0.2s ease;
}
a:hover {
color: #cccccc;
text-shadow: 0 0 5px rgba(255, 255, 255, 0.3);
}
h1, h2, h3, h4, h5, h6 {
font-family: 'JetBrains Mono', 'Courier New', monospace;
font-weight: 700;
color: #ffffff;
margin: 0;
text-transform: uppercase;
letter-spacing: 1px;
} }
h1 { h1 {
font-size: 3.2em; font-size: 2.5rem;
line-height: 1.1; line-height: 1.1;
font-weight: 900;
letter-spacing: 3px;
}
p {
font-family: 'JetBrains Mono', 'Courier New', monospace;
color: #cccccc;
line-height: 1.5;
} }
button { button {
border-radius: 8px; font-family: 'JetBrains Mono', 'Courier New', monospace;
border: 1px solid transparent; font-weight: 600;
padding: 0.6em 1.2em; text-transform: uppercase;
font-size: 1em; letter-spacing: 1px;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
} }
@media (prefers-color-scheme: light) { input, textarea {
:root { font-family: 'JetBrains Mono', 'Courier New', monospace;
color: #213547;
background-color: #ffffff;
} }
a:hover {
color: #747bff; /* Scrollbar styling for post-industrial feel */
::-webkit-scrollbar {
width: 8px;
} }
button {
background-color: #f9f9f9; ::-webkit-scrollbar-track {
background: #000000;
border: 1px solid #333333;
} }
::-webkit-scrollbar-thumb {
background: #666666;
border: 1px solid #000000;
}
::-webkit-scrollbar-thumb:hover {
background: #888888;
}
/* Selection styling */
::selection {
background: rgba(255, 255, 255, 0.2);
color: #ffffff;
}
::-moz-selection {
background: rgba(255, 255, 255, 0.2);
color: #ffffff;
}
/* Focus styling */
:focus-visible {
outline: 2px solid #ffffff;
outline-offset: 2px;
}
/* Utility classes */
.text-center {
text-align: center;
}
.text-uppercase {
text-transform: uppercase;
}
.font-mono {
font-family: 'JetBrains Mono', 'Courier New', monospace;
}
.font-weight-bold {
font-weight: 700;
}
.letter-spacing {
letter-spacing: 1px;
} }

View File

@@ -1,14 +1,39 @@
import styled from 'styled-components';
import {LoginForm} from '../../components'; import {LoginForm} from '../../components';
const FlexContainer = styled.div`
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
background: #000000;
background-image:
linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
linear-gradient(180deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
background-size: 50px 50px;
overflow: hidden;
`;
const LoginFormContainer = styled.div`
display: flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
`;
export function LoginView() { export function LoginView() {
const handleLoginSubmit = (username: string, secret: string) => { const handleLoginSubmit = (username: string, secret: string) => {
console.log('handling login submit username [%o] secret [%o]', username, secret) console.log('handling login submit username [%o] secret [%o]', username, secret)
}; };
console.log('LoginView...') return <FlexContainer>
<LoginFormContainer>
return <>
<LoginForm onSubmit={handleLoginSubmit} /> <LoginForm onSubmit={handleLoginSubmit} />
</> </LoginFormContainer>
</FlexContainer>
} }