feat(improvements): improve landing page & add new components + forms validation
improve landing page, improve register component (add proffesional validation, change styles + etc), add footer component (with small rotated cube as logo), improve formGeneratorfeat/x_gpu/new_version
parent
b91896e6a5
commit
9da564e2e6
|
|
@ -0,0 +1,91 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import '../styles/general.scss';
|
||||||
|
|
||||||
|
import SmallCubeComponent from './smallCube.js';
|
||||||
|
|
||||||
|
|
||||||
|
const FootComponent = () => {
|
||||||
|
return (
|
||||||
|
<footer>
|
||||||
|
<div className="content-container">
|
||||||
|
<div className="content">
|
||||||
|
<div className="section">
|
||||||
|
<SmallCubeComponent />
|
||||||
|
</div>
|
||||||
|
<div className="section">
|
||||||
|
<h4>
|
||||||
|
<a>
|
||||||
|
BUSINESS
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
<h4>
|
||||||
|
<a>
|
||||||
|
SIGN IN
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
<h4>
|
||||||
|
<a>
|
||||||
|
SIGN UP
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
<div className="section">
|
||||||
|
<h4>
|
||||||
|
Company
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div className="section">
|
||||||
|
<a>
|
||||||
|
About Us
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="section">
|
||||||
|
<a>
|
||||||
|
Contact Us
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
<div className="section">
|
||||||
|
<h4>
|
||||||
|
Resources
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div className="section">
|
||||||
|
<a>
|
||||||
|
Blog
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="section">
|
||||||
|
<a>
|
||||||
|
Help Center
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
<div className="section">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
<div className="section">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
<div className="section">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bottom">
|
||||||
|
<p>
|
||||||
|
© {new Date().getFullYear()} FehuDev. All rights reserved.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default FootComponent
|
||||||
|
|
@ -109,6 +109,8 @@ export const FormGenerator = ({
|
||||||
? <></>
|
? <></>
|
||||||
: <button
|
: <button
|
||||||
type='submit'
|
type='submit'
|
||||||
|
disabled={ info.allowButtonAction }
|
||||||
|
className={ info.allowButtonAction === false ? "button-disabled" : "" }
|
||||||
>
|
>
|
||||||
{ info.button_value }
|
{ info.button_value }
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -145,7 +147,17 @@ const TextInputGenerator = ({
|
||||||
id={input.name + info.action + info.endpoint + 'Input'}
|
id={input.name + info.action + info.endpoint + 'Input'}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
ref={input.ref}
|
ref={input.ref}
|
||||||
|
onChange={input.onChange}
|
||||||
|
className={ [ "Empty", "Success"].includes(input.validationInfo) ? "" : "input-incorrect" }
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
className="popup"
|
||||||
|
style={ [ "Empty", "Success"].includes(input.validationInfo) ? {"display": "none", "height": "0px"} : {"display": "block"} }
|
||||||
|
>
|
||||||
|
<div className="popup-content">
|
||||||
|
{ input.validationInfo }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -178,7 +190,17 @@ const PasswordInputGenerator = ({
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
ref={input.ref}
|
ref={input.ref}
|
||||||
type='password'
|
type='password'
|
||||||
|
onChange={input.onChange}
|
||||||
|
className={ [ "Empty", "Success"].includes(input.validationInfo) ? "" : "input-incorrect" }
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
className="popup"
|
||||||
|
style={ [ "Empty", "Success"].includes(input.validationInfo) ? {"display": "none", "height": "0px"} : {"display": "block"} }
|
||||||
|
>
|
||||||
|
<div className="popup-content">
|
||||||
|
{ input.validationInfo }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const UserLoginForm = () => {
|
||||||
|
|
||||||
// const dispatch = useDispatch()
|
// const dispatch = useDispatch()
|
||||||
// const { info } = useSelector( userAuthSelector )
|
// const { info } = useSelector( userAuthSelector )
|
||||||
const info = ""
|
const info = "" // if redux is integrated - delete this line
|
||||||
|
|
||||||
let refList = [
|
let refList = [
|
||||||
usernameInput,
|
usernameInput,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
||||||
import { useSelector, useDispatch } from 'react-redux'
|
// import { useSelector, useDispatch } from 'react-redux'
|
||||||
|
|
||||||
import { userCrudSelector } from '../../../redux/slices/userCrudSlice'
|
// import { userCrudSelector } from '../../../redux/slices/userCrudSlice'
|
||||||
import userCrudAsyncThunk from '../../../redux/asyncThunks/userCrudAsyncThunk'
|
// import userCrudAsyncThunk from '../../../redux/asyncThunks/userCrudAsyncThunk'
|
||||||
|
|
||||||
import FormGenerator from '../formGenerator'
|
import FormGenerator from '../formGenerator'
|
||||||
|
|
||||||
|
|
@ -12,52 +12,126 @@ const UserRegisterForm = () => {
|
||||||
|
|
||||||
const usernameInput = React.createRef()
|
const usernameInput = React.createRef()
|
||||||
const passwordInput = React.createRef()
|
const passwordInput = React.createRef()
|
||||||
const emailInput = React.createRef()
|
const confirmPasswordInput = React.createRef()
|
||||||
|
|
||||||
const dispatch = useDispatch()
|
const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||||
const { info } = useSelector( userCrudSelector )
|
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
|
||||||
|
|
||||||
|
const [usernameValidationInfo, setUsernameValidationInfo] = useState("Empty")
|
||||||
|
const [passwordValidationInfo, setPasswordValidationInfo] = useState("Empty")
|
||||||
|
const [confirmPasswordValidationInfo, setConfirmPasswordValidationInfo] = useState("Empty")
|
||||||
|
|
||||||
|
const [password, setPassword] = useState("")
|
||||||
|
const [confirmPassword, setConfirmPassword] = useState("")
|
||||||
|
|
||||||
|
const [allowButtonAction, setAllowButtonAction] = useState(false)
|
||||||
|
|
||||||
|
const usernameValidation = (event) => {
|
||||||
|
if (event.target.value === "") {
|
||||||
|
setUsernameValidationInfo("Email is required.")
|
||||||
|
} else if(!emailRegex.test(event.target.value)) {
|
||||||
|
setUsernameValidationInfo("Please provide correct email")
|
||||||
|
} else {
|
||||||
|
setUsernameValidationInfo("Success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const passwordValidation = (event) => {
|
||||||
|
|
||||||
|
setPassword(event.target.value)
|
||||||
|
|
||||||
|
if (event.target.value === "") {
|
||||||
|
setPasswordValidationInfo("Password is required.")
|
||||||
|
} else if(!passwordRegex.test(event.target.value)) {
|
||||||
|
setPasswordValidationInfo("Password require:\n - At least 8 characters,\n - At least one uppercase letter,\n - At least one lowercase letter,\n - At least one digit,\n - At least one special character.")
|
||||||
|
} else {
|
||||||
|
setPasswordValidationInfo("Success")
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event.target.value !== confirmPassword) {
|
||||||
|
setConfirmPasswordValidationInfo("Passwords are different.")
|
||||||
|
} else {
|
||||||
|
setConfirmPasswordValidationInfo("Success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmPasswordValidation = (event) => {
|
||||||
|
|
||||||
|
setConfirmPassword(event.target.value)
|
||||||
|
|
||||||
|
if(event.target.value !== password) {
|
||||||
|
setConfirmPasswordValidationInfo("Passwords are different.")
|
||||||
|
} else {
|
||||||
|
setConfirmPasswordValidationInfo("Success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setAllowButtonAction(
|
||||||
|
usernameValidationInfo === "Success"
|
||||||
|
&& passwordValidationInfo === "Success"
|
||||||
|
&& confirmPasswordValidationInfo === "Success"
|
||||||
|
)
|
||||||
|
}, [
|
||||||
|
allowButtonAction,
|
||||||
|
usernameValidationInfo,
|
||||||
|
passwordValidationInfo,
|
||||||
|
confirmPasswordValidationInfo
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// const dispatch = useDispatch()
|
||||||
|
// const { info } = useSelector( userCrudSelector )
|
||||||
|
const info = "" // if redux is integrated - delete this line
|
||||||
|
|
||||||
let refList = [
|
let refList = [
|
||||||
usernameInput,
|
usernameInput,
|
||||||
passwordInput,
|
passwordInput,
|
||||||
emailInput
|
confirmPasswordInput
|
||||||
]
|
]
|
||||||
|
|
||||||
let inputList = [
|
let inputList = [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
action: 'Create',
|
action: 'Create',
|
||||||
endpint: 'user/auth/login',
|
endpint: 'user/auth/register',
|
||||||
button_value: 'Sign Up'
|
button_value: 'SIGN UP',
|
||||||
|
allowButtonAction: allowButtonAction
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
name: 'Username',
|
name: 'EMAIL',
|
||||||
ref: usernameInput
|
ref: usernameInput,
|
||||||
|
onChange: usernameValidation,
|
||||||
|
validationInfo: usernameValidationInfo
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'password',
|
type: 'password',
|
||||||
name: 'Password',
|
name: 'PASSWORD',
|
||||||
ref: passwordInput
|
ref: passwordInput,
|
||||||
|
onChange: passwordValidation,
|
||||||
|
validationInfo: passwordValidationInfo
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'password',
|
||||||
name: 'Email',
|
name: 'CONFIRM PASSWORD',
|
||||||
ref: emailInput
|
ref: confirmPasswordInput,
|
||||||
|
onChange: confirmPasswordValidation,
|
||||||
|
validationInfo: confirmPasswordValidationInfo
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const register = async ( refs ) => {
|
const register = async ( refs ) => {
|
||||||
let pass = {
|
let pass = {
|
||||||
username: refs[0].current.value,
|
username: refs[0].current.value,
|
||||||
password: refs[1].current.value,
|
password: refs[1].current.value
|
||||||
email: refs[2].current.value,
|
|
||||||
}
|
}
|
||||||
dispatch(
|
// dispatch(
|
||||||
userCrudAsyncThunk.fetchRegister(
|
// userCrudAsyncThunk.fetchRegister(
|
||||||
pass
|
// pass
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import '../styles/LoginPage.cube.scss';
|
import '../styles/large.cube.scss';
|
||||||
|
|
||||||
|
|
||||||
const GraphicContainerComponent = () => {
|
const LargeCubeComponent = () => {
|
||||||
return (
|
return (
|
||||||
<div className="graphic-container">
|
<div className="graphic-container">
|
||||||
<div className="cube">
|
<div className="cube">
|
||||||
|
|
@ -19,4 +19,4 @@ const GraphicContainerComponent = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default GraphicContainerComponent
|
export default LargeCubeComponent
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import '../styles/small.cube.scss';
|
||||||
|
|
||||||
|
|
||||||
|
const SmallCubeComponent = () => {
|
||||||
|
return (
|
||||||
|
<div className="graphic-container">
|
||||||
|
<div className="cube">
|
||||||
|
<div className="face-front"></div>
|
||||||
|
<div className="face-back"></div>
|
||||||
|
<div className="face-right"></div>
|
||||||
|
<div className="face-left"></div>
|
||||||
|
<div className="face-top"></div>
|
||||||
|
<div className="face-bottom"></div>
|
||||||
|
</div>
|
||||||
|
<div className="title">
|
||||||
|
XGPU
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default SmallCubeComponent
|
||||||
|
|
@ -2,36 +2,83 @@ import React from 'react';
|
||||||
|
|
||||||
import '../styles/general.scss';
|
import '../styles/general.scss';
|
||||||
|
|
||||||
import GraphicContainerComponent from '../components/graphic-container.js';
|
import UserRegisterForm from '../components/forms/user_auth/userRegister.js';
|
||||||
|
import FootComponent from '../components/foot.js';
|
||||||
|
|
||||||
const LandingPage = () => {
|
const LandingPage = () => {
|
||||||
return (
|
return (
|
||||||
<div className="login-container">
|
<div className="landing-container">
|
||||||
<header className="landing">
|
<header className="landing">
|
||||||
<h2>Affordable. Efficient. Accessible.</h2>
|
<h2>Affordable. Efficient. Accessible.</h2>
|
||||||
<h1>GUARANTED.</h1>
|
<h1>GUARANTED.</h1>
|
||||||
<p>
|
<p>
|
||||||
Minimize your expenses without compromising on quality.
|
Minimize your expenses without compromising on quality.
|
||||||
<br />
|
<br />
|
||||||
Our platform is built for individuals
|
Our platform is built for individuals who need top-tier rendering
|
||||||
|
<br />
|
||||||
<span className="span-white">
|
<span className="span-white">
|
||||||
who need top-tier rendering without the top-tier investment.
|
without the top-tier investment.
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<button>
|
<button>
|
||||||
GET A DEMO
|
GET A DEMO
|
||||||
</button>
|
</button>
|
||||||
|
<h4>
|
||||||
|
GPU IS IMPORTANT...
|
||||||
|
</h4>
|
||||||
<p>
|
<p>
|
||||||
<span className="span-first-color">
|
...But <span className="span-white">GPU server can be very expensive.</span>
|
||||||
GPU Is Important...
|
<br />
|
||||||
|
Configuration and administration<span className="span-white"> take too long time.</span>
|
||||||
|
<br />
|
||||||
|
<span className="span-white">
|
||||||
|
Everything of that needs so much additional knowledge.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<h2>
|
||||||
|
We Offer Ready Solution.
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Boost your GPU power for your 3D and AI models stuff
|
||||||
|
<br />
|
||||||
|
<span className="span-white">
|
||||||
|
without overpay for servers...
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
...but
|
<span className="span-white">
|
||||||
|
...without overtime for environment adjustments!
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<h2>
|
||||||
|
"OK... So What Makes You So Different?"
|
||||||
|
</h2>
|
||||||
|
<h4>
|
||||||
|
GUARANTED
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
We only win if you win. You won't carry all the risk, we'll share it
|
||||||
|
</p>
|
||||||
|
<h4>
|
||||||
|
RESLUTS
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
Our first priority is to get you results.
|
||||||
|
</p>
|
||||||
|
<h4>
|
||||||
|
LOCAL
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
</p>
|
||||||
|
<h4>
|
||||||
|
SPECIALIZED
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
<main className="main-content">
|
<main className="secondary-content">
|
||||||
<GraphicContainerComponent />
|
<UserRegisterForm />
|
||||||
</main>
|
</main>
|
||||||
|
<FootComponent />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import '../../styles/general.scss';
|
import '../../styles/general.scss';
|
||||||
import '../../styles/LoginPage.cube.scss';
|
|
||||||
|
|
||||||
import GraphicContainerComponent from '../../components/graphic-container.js';
|
import LargeCubeComponent from '../../components/largeCube.js';
|
||||||
import UserLoginForm from '../../components/forms/user_auth/userLogin.js';
|
import UserLoginForm from '../../components/forms/user_auth/userLogin.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -14,7 +13,7 @@ const LoginPage = () => {
|
||||||
<h1>XGPU</h1>
|
<h1>XGPU</h1>
|
||||||
</header>
|
</header>
|
||||||
<main className="main-content">
|
<main className="main-content">
|
||||||
<GraphicContainerComponent />
|
<LargeCubeComponent />
|
||||||
<UserLoginForm />
|
<UserLoginForm />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ $font-family-default: neue-haas-unica, sans-serif;
|
||||||
|
|
||||||
body, html {
|
body, html {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
height: 100%;
|
overflow-x: hidden;
|
||||||
overflow: hidden;
|
|
||||||
font-family: $font-family-default;
|
font-family: $font-family-default;
|
||||||
tab-size: 4;
|
tab-size: 4;
|
||||||
background: $background-color;
|
background: $background-color;
|
||||||
|
|
@ -33,8 +32,6 @@ body, html {
|
||||||
// #0a670a 60%,
|
// #0a670a 60%,
|
||||||
// black 100%
|
// black 100%
|
||||||
// );
|
// );
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -49,9 +46,15 @@ body, html {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.landing-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
.landing {
|
.landing {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
background: $header-background;
|
background: $header-background;
|
||||||
color: $title-color;
|
color: $title-color;
|
||||||
z-index: 3; // Ensure the login form is above the cube
|
z-index: 3; // Ensure the login form is above the cube
|
||||||
|
|
@ -69,6 +72,19 @@ body, html {
|
||||||
color: $title-color;
|
color: $title-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 45px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $title-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $title-color;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
@ -111,13 +127,23 @@ body, html {
|
||||||
color: black
|
color: black
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
//flex: 1;
|
|
||||||
//display: flex;
|
|
||||||
margin-top: 0%;
|
margin-top: 0%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-content {
|
||||||
|
width: 100%;
|
||||||
|
background: $form-background;
|
||||||
|
|
||||||
|
.form {
|
||||||
|
background: none;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.form {
|
.form {
|
||||||
background: $form-background;
|
background: $form-background;
|
||||||
|
|
@ -140,6 +166,8 @@ body, html {
|
||||||
label {
|
label {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
|
@ -157,7 +185,33 @@ body, html {
|
||||||
}
|
}
|
||||||
|
|
||||||
input:active {
|
input:active {
|
||||||
background-color: rgba(0,128,0,1);
|
background-color: rgba(0,120,0,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-correct {
|
||||||
|
background: rgba(0,120,0,1);
|
||||||
|
border: 1px solid $border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-incorrect {
|
||||||
|
background: rgba(120,8,0,1);
|
||||||
|
border: 1px solid red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup {
|
||||||
|
margin-top: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 15px;
|
||||||
|
background: rgba(120,8,0,0.5);
|
||||||
|
border: 1px solid red;
|
||||||
|
border-radius: 5px;
|
||||||
|
white-space: pre-line;
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
|
||||||
|
.popup-content {
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +222,7 @@ body, html {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background: $button-background;
|
background: $button-background;
|
||||||
font-family: $font-family-default;
|
font-family: $font-family-default;
|
||||||
font-weight: 800;
|
font-weight: 700;
|
||||||
color: rgba(0,0,0,0.5);
|
color: rgba(0,0,0,0.5);
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
@ -179,6 +233,63 @@ body, html {
|
||||||
background-color: green;
|
background-color: green;
|
||||||
color: black
|
color: black
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-disabled {
|
||||||
|
background: gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
width: 70%;
|
||||||
|
background: $form-background;
|
||||||
|
text-align: left;
|
||||||
|
padding: 20px 15%;
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.section {
|
||||||
|
flex: 1;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
color: $title-color;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graphic-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, a {
|
||||||
|
color: $subtitle-color;
|
||||||
|
line-height: 1.6;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: $title-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
border-top: 1px solid $subtitle-color;
|
||||||
|
padding-top: 10px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: $subtitle-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
$cube-size: 30px;
|
||||||
|
$cube-color: rgba(0, 140, 0, 0.5);
|
||||||
|
$perspective: 10000px;
|
||||||
|
$animation-duration: 20s;
|
||||||
|
|
||||||
|
@mixin cube-face {
|
||||||
|
position: absolute;
|
||||||
|
width: $cube-size - 4px;
|
||||||
|
height: $cube-size - 4px;
|
||||||
|
background: $cube-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotateCube {
|
||||||
|
0% {
|
||||||
|
transform: rotateX(0) rotateY(0) rotateZ(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.graphic-container {
|
||||||
|
display: flex;
|
||||||
|
perspective: $perspective;
|
||||||
|
perspective-origin: 50% 100px; // Adjusted for better 3D effect
|
||||||
|
z-index: 1; // Lower z-index than the login form to place it behind
|
||||||
|
|
||||||
|
.cube {
|
||||||
|
width: $cube-size;
|
||||||
|
height: $cube-size;
|
||||||
|
position: relative;
|
||||||
|
margin: auto; // Centers the cube within the graphic container
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transform-origin: center center; // Rotates around the center of the cube
|
||||||
|
animation: rotateCube $animation-duration infinite linear;
|
||||||
|
|
||||||
|
div {
|
||||||
|
@include cube-face;
|
||||||
|
}
|
||||||
|
|
||||||
|
.face-front { transform: translateZ($cube-size / 2); }
|
||||||
|
.face-back { transform: translateZ(-$cube-size / 2) rotateY(180deg); }
|
||||||
|
.face-right { transform: rotateY(90deg) translateZ($cube-size / 2); }
|
||||||
|
.face-left { transform: rotateY(-90deg) translateZ($cube-size / 2); }
|
||||||
|
.face-top { transform: rotateX(90deg) translateZ($cube-size / 2); }
|
||||||
|
.face-bottom { transform: rotateX(-90deg) translateZ($cube-size / 2); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: white;
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue