minimal front
This commit is contained in:
parent
95c0590d67
commit
c88bf296a9
@ -1,9 +1,12 @@
|
|||||||
|
import Form from '@/widgets/form/form.widget';
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const HomePage = () => {
|
const HomePage = () => {
|
||||||
return (
|
return (
|
||||||
<div className={classes.home}>
|
<div className={classes.home}>
|
||||||
<div className={classes.container}></div>
|
<div className={classes.container}>
|
||||||
|
<Form />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,17 @@
|
|||||||
|
import React, { FormEvent } from 'react';
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const Button = () => {
|
type ButtonProps = {
|
||||||
return <></>;
|
label: string;
|
||||||
|
onClick: (e: FormEvent) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Button: React.FC<ButtonProps> = ({ label, onClick }) => {
|
||||||
|
return (
|
||||||
|
<button className={classes.button} onClick={onClick}>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Button;
|
export default Button;
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
.button {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2); // прозрачный белый фон
|
||||||
|
border: 2px solid var(--primary-white); // белая обводка
|
||||||
|
border-radius: 8px; // закруглённые углы
|
||||||
|
color: var(--primary-white); // белый текст
|
||||||
|
padding: 10px 20px; // внутренних отступов
|
||||||
|
font-size: 16px; // размер шрифта
|
||||||
|
cursor: pointer; // курсор при наведении
|
||||||
|
transition: background-color 0.3s ease; // плавный переход фона
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.4); // изменение цвета фона при наведении
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none; // убираем стандартный контур при фокусировке
|
||||||
|
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5); // добавляем тень при фокусировке
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,51 @@
|
|||||||
import { FC } from 'react';
|
import { FC, useState } from 'react';
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
type SelectorProps = {
|
type SelectorProps = {
|
||||||
handleSetValue: () => void;
|
field: string;
|
||||||
|
handleSetValue: (field: string, value: string) => void;
|
||||||
list: string[];
|
list: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const Selector: FC<SelectorProps> = ({ handleSetValue, list }) => {
|
const Selector: FC<SelectorProps> = ({ field, handleSetValue, list }) => {
|
||||||
|
const [inputValue, setInputValue] = useState('');
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setInputValue(value);
|
||||||
|
handleSetValue(field, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setInputValue(value);
|
||||||
|
handleSetValue(field, value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={classes.selector}>
|
<div className={classes.selectorContainer}>
|
||||||
{list.map((item) => (
|
<select
|
||||||
<option>{item}</option>
|
className={classes.selector}
|
||||||
|
onChange={handleChange}
|
||||||
|
value={inputValue}
|
||||||
|
>
|
||||||
|
<option value="" disabled>
|
||||||
|
Select an option
|
||||||
|
</option>
|
||||||
|
{list.map((item, index) => (
|
||||||
|
<option key={index} value={item}>
|
||||||
|
{item}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</section>
|
</select>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className={classes.input}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="Or type your own"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
.selector {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2); // прозрачный белый
|
||||||
|
border: 2px solid var(--primary-white); // белая рамка
|
||||||
|
border-radius: 8px; // закруглённые углы
|
||||||
|
color: var(--primary-white); // белый текст
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
option {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2); // цвет фона для выпадающего списка
|
||||||
|
color: var(--primary-white); // белый текст в выпадающем списке
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,17 @@
|
|||||||
export type PredictRequestType = {
|
export type PredictRequestType = {
|
||||||
|
brand: string;
|
||||||
}
|
processor: string;
|
||||||
|
ram: string;
|
||||||
|
os: string;
|
||||||
|
ssd: string;
|
||||||
|
display: number;
|
||||||
|
gpu: string;
|
||||||
|
weight: number;
|
||||||
|
battery_size: number;
|
||||||
|
release_year: number;
|
||||||
|
display_type: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type PredictResponseType = {
|
export type PredictResponseType = {
|
||||||
|
predicted_price: number;
|
||||||
}
|
};
|
||||||
|
@ -3,20 +3,68 @@ import {
|
|||||||
PredictRequestType,
|
PredictRequestType,
|
||||||
PredictResponseType,
|
PredictResponseType,
|
||||||
} from '@/shared/types/predict';
|
} from '@/shared/types/predict';
|
||||||
import { useState } from 'react';
|
import { FormEvent, useCallback, useState } from 'react';
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
import { Button } from '@/shared/components/button';
|
||||||
|
import { Selector } from '@/shared/components/selector';
|
||||||
|
|
||||||
const Form = () => {
|
const Form = () => {
|
||||||
const [request, setRequest] = useState<PredictRequestType>({});
|
const [request, setRequest] = useState<PredictRequestType>({
|
||||||
const [response, setResponse] = useState<PredictResponseType>({});
|
brand: '',
|
||||||
|
processor: '',
|
||||||
|
ram: '',
|
||||||
|
os: '',
|
||||||
|
ssd: '',
|
||||||
|
display: -1,
|
||||||
|
gpu: '',
|
||||||
|
weight: -1,
|
||||||
|
battery_size: -1,
|
||||||
|
release_year: -1,
|
||||||
|
display_type: '',
|
||||||
|
});
|
||||||
|
const [response, setResponse] = useState<PredictResponseType>({
|
||||||
|
predicted_price: -1,
|
||||||
|
});
|
||||||
|
|
||||||
const handleGetPredict = async () => {
|
const fields = Object.keys(request);
|
||||||
|
|
||||||
|
const handleInputChange = useCallback(
|
||||||
|
(updatedRequest: PredictRequestType) => {
|
||||||
|
setRequest(updatedRequest);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateField = (field: string, value: string) => {
|
||||||
|
handleInputChange({
|
||||||
|
...request,
|
||||||
|
[field]: value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGetPredict = async (event: FormEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
const newResponse = await api.predictPrice(request);
|
const newResponse = await api.predictPrice(request);
|
||||||
|
setResponse(newResponse);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form>
|
<form className={classes.form}>
|
||||||
<div className={classes.}></div>
|
<div className={classes.selectorList}>
|
||||||
|
{fields.map((field) => (
|
||||||
|
<Selector
|
||||||
|
key={field}
|
||||||
|
handleSetValue={(value) => updateField(field, value)}
|
||||||
|
list={[]}
|
||||||
|
field={field}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
onClick={(e: FormEvent) => handleGetPredict(e)}
|
||||||
|
label={'Отправить'}
|
||||||
|
/>
|
||||||
|
{response && <span>Ответ: {response.predicted_price}</span>}
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,27 +1,18 @@
|
|||||||
@use '../../shared/assets/styles/adaptive' as adaptive;
|
@use '../../shared/assets/styles/adaptive' as adaptive;
|
||||||
|
|
||||||
.navbar {
|
.form {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 18px;
|
||||||
background-color: var(--transparent-black);
|
background-color: var(--transparent-black);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
padding: 25px;
|
||||||
|
|
||||||
.container {
|
.selectorList {
|
||||||
padding: 15px;
|
|
||||||
@include adaptive.container;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
justify-content: start;
|
|
||||||
align-items: end;
|
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
color: var(--primary-white);
|
|
||||||
|
|
||||||
.title {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user