start normal disign

This commit is contained in:
maxnes3 2024-11-06 11:49:14 +04:00
parent bd9b192656
commit 244aed205b
20 changed files with 225 additions and 72 deletions

View File

@ -5,7 +5,7 @@ import Laptop from '@shared/assets/icons/laptop.svg';
const HomePage = () => { const HomePage = () => {
return ( return (
<div className={classes.home}> <div className={classes.home}>
<Laptop width={250} height={250} /> <Laptop className={classes.laptop} />
<div className={classes.container}> <div className={classes.container}>
<Form /> <Form />
</div> </div>

View File

@ -1,13 +1,36 @@
@use '../../shared/assets/styles/adaptive' as adaptive; @use '../../shared/assets/styles/adaptive' as adaptive;
$adaptive: (
desktop: (
flex-direction: row,
size: 250px,
container-width: 768px
),
table: (
flex-direction: row,
size: 250px,
container-width: 425px
),
mobile: (
flex-direction: column,
size: auto,
container-width: auto
),
);
.home { .home {
display: flex; display: flex;
flex-direction: column;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
@include adaptive.set-adaptive($adaptive, flex-direction, flex-direction);
.laptop {
@include adaptive.set-adaptive($adaptive, width, size);
@include adaptive.set-adaptive($adaptive, height, size);
}
.container { .container {
padding: 15px; padding: 15px;
@include adaptive.container; @include adaptive.set-adaptive($adaptive, width, container-width);
} }
} }

View File

@ -1,14 +1,14 @@
$breakpoints: ( $breakpoints: (
desktop: ( desktop: (
max: 1440px, max: 2560px,
min: 1024.1px min: 1024px
), ),
table: ( table: (
max: 1024px, max: 1023.99px,
min: 768.1px min: 768px
), ),
mobile: ( mobile: (
max: 768px, max: 767.99px,
min: 375px min: 375px
), ),
); );
@ -26,7 +26,7 @@ $breakpoints: (
@each $breakpoint, $settings in $adaptive { @each $breakpoint, $settings in $adaptive {
@include breakpoint($breakpoint) { @include breakpoint($breakpoint) {
@if $property and $attribute { @if $property and $attribute {
#{$property}: map-get($settings, $attribute); #{$property}: map-get($settings, $attribute);
} }
} }
} }

View File

@ -1,7 +1,7 @@
:root { :root {
--primary-black: #040404; --primary-black: #040404;
--transparent-black: rgba(0, 0, 0, 0.8);
--primary-white: #ffffff; --primary-white: #ffffff;
--secondary-gray: #D9D9D9; --secondary-gray: #D9D9D9;
--active-color: #007AFF; --active-color: #007AFF;
--transparent-black: rgba(0, 0, 0, 0.8);
} }

View File

@ -0,0 +1,17 @@
@mixin shadows () {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1),
0 1px 3px rgba(0, 0, 0, 0.08);
}
@mixin hoverElement {
background-color: var(--active-color);
color: var(--primary-white);
}
@mixin hoverBorder {
border: 2px solid var(--active-color);
}
@mixin hoverLink {
color: var(--active-color);
}

View File

@ -1,15 +1,15 @@
import React, { FormEvent } from 'react'; import React, { FormEvent, ReactNode } from 'react';
import classes from './styles.module.scss'; import classes from './styles.module.scss';
type ButtonProps = { type ButtonProps = {
label: string; children: ReactNode;
onClick: (e: FormEvent) => Promise<void>; onClick: (e: FormEvent) => Promise<void>;
}; };
const Button: React.FC<ButtonProps> = ({ label, onClick }) => { const Button: React.FC<ButtonProps> = ({ children, onClick }) => {
return ( return (
<button className={classes.button} onClick={onClick}> <button className={classes.button} onClick={onClick}>
{label} {children}
</button> </button>
); );
}; };

View File

@ -1,18 +1,19 @@
@use '../../assets/styles/fonts' as fonts; @use '../../assets/styles/fonts' as fonts;
@use '../../assets/styles/theme' as theme;
.button { .button {
background-color: var(--primary-white); background-color: var(--primary-white);
border: 2px solid var(--secondary-gray); // белая обводка border: none; // белая обводка
border-radius: 8px; // закруглённые углы border-radius: 2px 2px 16px 16px; // закруглённые углы
color: var(--primary-black); // белый текст color: var(--primary-black); // белый текст
padding: 10px 20px; // внутренних отступов padding: 10px 20px; // внутренних отступов
cursor: pointer; // курсор при наведении cursor: pointer; // курсор при наведении
transition: 0.3s ease; // плавный переход фона transition: 0.3s ease;
@include fonts.urbanist-font(20px, 600); @include fonts.urbanist-font(20px, 600);
@include theme.shadows();
&:hover { &:hover {
background-color: var(--active-color); @include theme.hoverElement();
color: var(--primary-white); // белый текст
} }
&:focus { &:focus {

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import classes from './styles.module.scss';
const Devider: FC = () => {
return <div className={classes.devider} />;
};
export default Devider;

View File

@ -0,0 +1 @@
export { default as Devider } from './devider.component';

View File

@ -0,0 +1,6 @@
.devider {
background-color: var(--secondary-gray);
width: 100%;
height: 2px;
border-radius: 50%;
}

View File

@ -0,0 +1,34 @@
import { FC, ReactNode, useState } from 'react';
import classes from './styles.module.scss';
import { Devider } from '@shared/components/devider';
type ExpanderProps = {
title: string;
children: ReactNode;
};
const Expander: FC<ExpanderProps> = ({ title, children }) => {
const [expanded, setExpanded] = useState(false);
const handleHeaderClick = () => {
setExpanded((expanded) => !expanded);
};
return (
<div className={classes.expander}>
<div className={classes.header} onClick={handleHeaderClick}>
<div className={classes.title}>{title}</div>
<span className={classes.title}>{expanded ? '▼' : ''}</span>
</div>
<div
className={
expanded ? classes.contentExpanded : classes.contentCollapsed
}
>
<Devider />
{children}
</div>
</div>
);
};
export default Expander;

View File

@ -0,0 +1 @@
export { default as Expander } from './expander.component';

View File

@ -0,0 +1,41 @@
@use '../../assets/styles/fonts' as fonts;
@use '../../assets/styles/theme' as theme;
.expander {
display: flex;
flex-direction: column;
gap: 8px;
background-color: var(--primary-white);
border: 2px solid var(--primary-white);
border-radius: 16px;
padding: 16px;
transition: 0.3s ease;
@include theme.shadows();
&:hover { @include theme.hoverBorder(); }
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.title {
@include fonts.urbanist-font(26px, 600);
}
}
.contentExpanded {
display: flex;
flex-direction: column;
gap: 16px;
filter: opacity(1);
height: auto;
}
.contentCollapsed {
display: none;
filter: opacity(0);
height: 0;
}
}

View File

@ -17,22 +17,20 @@ const Selector: FC<SelectorProps> = ({ field, handleSetValue, list }) => {
}; };
return ( return (
<div className={classes.selectorContainer}> <select
<select className={classes.selector}
className={classes.selector} onChange={handleChange}
onChange={handleChange} value={inputValue}
value={inputValue} >
> <option value="" disabled>
<option value="" disabled> Select an option
Select an option </option>
{list.map((item, index) => (
<option key={index} value={item}>
{item}
</option> </option>
{list.map((item, index) => ( ))}
<option key={index} value={item}> </select>
{item}
</option>
))}
</select>
</div>
); );
}; };

View File

@ -1,15 +1,22 @@
.selector { @use '../../assets/styles/fonts' as fonts;
background-color: rgba(255, 255, 255, 0.2); // прозрачный белый @use '../../assets/styles/theme' as theme;
border: 2px solid var(--primary-white); // белая рамка
border-radius: 8px; // закруглённые углы
color: var(--primary-white); // белый текст
padding: 8px;
font-size: 16px;
cursor: pointer;
option { .selector {
background-color: rgba(255, 255, 255, 0.2); // цвет фона для выпадающего списка background-color: var(--primary-white); // прозрачный белый
color: var(--primary-white); // белый текст в выпадающем списке border: 2px solid var(--secondary-gray); // белая рамка
} border-radius: 8px; // закруглённые углы
color: var(--primary-black); // белый текст
padding: 8px;
font-size: 16px;
cursor: pointer;
@include fonts.urbanist-font(20px, 600);
@include theme.shadows();
option {
color: var(--primary-black); // белый текст в выпадающем списке
} }
&:hover { @include theme.hoverBorder(); }
&:focus { @include theme.hoverBorder(); }
}

View File

@ -13,5 +13,5 @@ export type PredictRequestType = {
}; };
export type PredictResponseType = { export type PredictResponseType = {
predicted_price: number; predicted_price?: number;
}; };

View File

@ -8,6 +8,7 @@ import classes from './styles.module.scss';
import { Button } from '@/shared/components/button'; import { Button } from '@/shared/components/button';
import { Selector } from '@/shared/components/selector'; import { Selector } from '@/shared/components/selector';
import { mockUpOptions } from '@/shared/constants'; import { mockUpOptions } from '@/shared/constants';
import { Expander } from '@/shared/components/expander';
const Form = () => { const Form = () => {
const [request, setRequest] = useState<PredictRequestType>({ const [request, setRequest] = useState<PredictRequestType>({
@ -24,7 +25,7 @@ const Form = () => {
display_type: '4K', display_type: '4K',
}); });
const [response, setResponse] = useState<PredictResponseType>({ const [response, setResponse] = useState<PredictResponseType>({
predicted_price: -1, predicted_price: undefined,
}); });
const fields = Object.keys(request); const fields = Object.keys(request);
@ -54,19 +55,17 @@ const Form = () => {
<form className={classes.form}> <form className={classes.form}>
<div className={classes.selectorList}> <div className={classes.selectorList}>
{fields.map((field) => ( {fields.map((field) => (
<Selector <Expander key={field} title={field}>
key={field} <Selector
handleSetValue={updateField} handleSetValue={updateField}
list={mockUpOptions[field]} list={mockUpOptions[field]}
field={field} field={field}
/> />
</Expander>
))} ))}
</div> </div>
<Button <Button onClick={(e: FormEvent) => handleGetPredict(e)}>Submit</Button>
onClick={(e: FormEvent) => handleGetPredict(e)} {response.predicted_price && (
label={'Submit'}
/>
{response && (
<span style={{ color: 'white' }}> <span style={{ color: 'white' }}>
Ответ: {response.predicted_price} Ответ: {response.predicted_price}
</span> </span>

View File

@ -4,12 +4,10 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 18px; gap: 18px;
background-color: var(--transparent-black); background-color: var(--secondary-gray);
backdrop-filter: blur(10px);
width: 100%;
justify-content: center; justify-content: center;
padding: 25px; padding: 16px;
border-radius: 8px; border-radius: 24px;
.selectorList { .selectorList {
display: flex; display: flex;

View File

@ -5,8 +5,8 @@ const Navbar = () => {
<nav className={classes.navbar}> <nav className={classes.navbar}>
<div className={classes.container}> <div className={classes.container}>
<div className={classes.logo}> <div className={classes.logo}>
<h2 className={classes.title}>Price Builder</h2> <h1 className={classes.title}>Price Builder</h1>
<span>v1.0.0</span> <span className={classes.version}>v1.0.0</span>
</div> </div>
</div> </div>
</nav> </nav>

View File

@ -1,11 +1,17 @@
@use '../../shared/assets/styles/adaptive' as adaptive; @use '../../shared/assets/styles/adaptive' as adaptive;
@use '../../shared/assets/styles/fonts' as fonts;
@use '../../shared/assets/styles/theme' as theme;
$adaptive: (
);
.navbar { .navbar {
display: flex; display: flex;
background-color: var(--transparent-black);
backdrop-filter: blur(10px);
width: 100%;
justify-content: center; justify-content: center;
background-color: var(--secondary-gray);
border-radius: 16px;
margin: 16px;
.container { .container {
padding: 15px; padding: 15px;
@ -14,14 +20,27 @@
.logo { .logo {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: start; justify-content: flex-start;
align-items: end; align-items: end;
gap: 8px; gap: 8px;
color: var(--primary-white); color: var(--primary-black);
.title { .title {
margin: 0; margin: 0;
transition: 0.3s ease;
@include fonts.urbanist-font(36px, 600);
&:hover { @include theme.hoverLink(); }
} }
} }
.version {
background-color: var(--primary-white);
color: var(--primary-black);
border-radius: 25px;
padding: 4px 16px;
@include fonts.urbanist-font(20px, 500);
@include theme.shadows();
}
} }
} }