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';
|
||||
|
||||
const HomePage = () => {
|
||||
return (
|
||||
<div className={classes.home}>
|
||||
<div className={classes.container}></div>
|
||||
<div className={classes.container}>
|
||||
<Form />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,17 @@
|
||||
import React, { FormEvent } from 'react';
|
||||
import classes from './styles.module.scss';
|
||||
|
||||
const Button = () => {
|
||||
return <></>;
|
||||
type ButtonProps = {
|
||||
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;
|
||||
|
@ -1 +1 @@
|
||||
export { default as Button} from './button.component';
|
||||
export { default as Button } from './button.component';
|
||||
|
@ -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';
|
||||
|
||||
type SelectorProps = {
|
||||
handleSetValue: () => void;
|
||||
field: string;
|
||||
handleSetValue: (field: string, value: string) => void;
|
||||
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 (
|
||||
<section className={classes.selector}>
|
||||
{list.map((item) => (
|
||||
<option>{item}</option>
|
||||
<div className={classes.selectorContainer}>
|
||||
<select
|
||||
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 = {
|
||||
|
||||
}
|
||||
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 = {
|
||||
|
||||
}
|
||||
predicted_price: number;
|
||||
};
|
||||
|
@ -3,20 +3,68 @@ import {
|
||||
PredictRequestType,
|
||||
PredictResponseType,
|
||||
} from '@/shared/types/predict';
|
||||
import { useState } from 'react';
|
||||
import { FormEvent, useCallback, useState } from 'react';
|
||||
import classes from './styles.module.scss';
|
||||
import { Button } from '@/shared/components/button';
|
||||
import { Selector } from '@/shared/components/selector';
|
||||
|
||||
const Form = () => {
|
||||
const [request, setRequest] = useState<PredictRequestType>({});
|
||||
const [response, setResponse] = useState<PredictResponseType>({});
|
||||
const [request, setRequest] = useState<PredictRequestType>({
|
||||
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);
|
||||
setResponse(newResponse);
|
||||
};
|
||||
|
||||
return (
|
||||
<form>
|
||||
<div className={classes.}></div>
|
||||
<form className={classes.form}>
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
@ -1,27 +1,18 @@
|
||||
@use '../../shared/assets/styles/adaptive' as adaptive;
|
||||
|
||||
.navbar {
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 18px;
|
||||
background-color: var(--transparent-black);
|
||||
backdrop-filter: blur(10px);
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
padding: 25px;
|
||||
|
||||
.container {
|
||||
padding: 15px;
|
||||
@include adaptive.container;
|
||||
|
||||
.logo {
|
||||
.selectorList {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
align-items: end;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
color: var(--primary-white);
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user