start normal disign
This commit is contained in:
parent
bd9b192656
commit
244aed205b
@ -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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
17
src/shared/assets/styles/_theme.scss
Normal file
17
src/shared/assets/styles/_theme.scss
Normal 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);
|
||||||
|
}
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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 {
|
||||||
|
8
src/shared/components/devider/devider.component.tsx
Normal file
8
src/shared/components/devider/devider.component.tsx
Normal 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;
|
1
src/shared/components/devider/index.ts
Normal file
1
src/shared/components/devider/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as Devider } from './devider.component';
|
6
src/shared/components/devider/styles.module.scss
Normal file
6
src/shared/components/devider/styles.module.scss
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.devider {
|
||||||
|
background-color: var(--secondary-gray);
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
34
src/shared/components/expander/expander.component.tsx
Normal file
34
src/shared/components/expander/expander.component.tsx
Normal 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;
|
1
src/shared/components/expander/index.ts
Normal file
1
src/shared/components/expander/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as Expander } from './expander.component';
|
41
src/shared/components/expander/styles.module.scss
Normal file
41
src/shared/components/expander/styles.module.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
|
@use '../../assets/styles/fonts' as fonts;
|
||||||
|
@use '../../assets/styles/theme' as theme;
|
||||||
|
|
||||||
.selector {
|
.selector {
|
||||||
background-color: rgba(255, 255, 255, 0.2); // прозрачный белый
|
background-color: var(--primary-white); // прозрачный белый
|
||||||
border: 2px solid var(--primary-white); // белая рамка
|
border: 2px solid var(--secondary-gray); // белая рамка
|
||||||
border-radius: 8px; // закруглённые углы
|
border-radius: 8px; // закруглённые углы
|
||||||
color: var(--primary-white); // белый текст
|
color: var(--primary-black); // белый текст
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@include fonts.urbanist-font(20px, 600);
|
||||||
option {
|
@include theme.shadows();
|
||||||
background-color: rgba(255, 255, 255, 0.2); // цвет фона для выпадающего списка
|
|
||||||
color: var(--primary-white); // белый текст в выпадающем списке
|
option {
|
||||||
}
|
color: var(--primary-black); // белый текст в выпадающем списке
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover { @include theme.hoverBorder(); }
|
||||||
|
|
||||||
|
&:focus { @include theme.hoverBorder(); }
|
||||||
|
}
|
@ -13,5 +13,5 @@ export type PredictRequestType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type PredictResponseType = {
|
export type PredictResponseType = {
|
||||||
predicted_price: number;
|
predicted_price?: number;
|
||||||
};
|
};
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user