fix: add connect form

This commit is contained in:
2025-07-01 15:26:42 +03:00
parent 8bb29cc042
commit b70b2026d5
28 changed files with 551 additions and 42 deletions

View File

@@ -23,6 +23,7 @@ $color-lightgray: #E4E1E1;
$color-darkgray: #999999;
$color-text: #333333;
$color-text-light: #222222;
$color-green: #23A455;
$color-link: #333333;
$color-link-hover: #009283;
$color-error: #ff0000;

View File

@@ -0,0 +1 @@
export * from './ui';

View File

@@ -0,0 +1,26 @@
.Container {
background: $color-green;
width: 100%;
border-radius: rem(16px);
padding: rem(30px) rem(20px);
margin-bottom: 20px;
display: flex;
flex-direction: column;
}
.Title {
font-family: $font-roboto;
font-weight: 500;
font-size: 20px;
line-height: 130%;
color: $color-white;
align-self: center;
margin-bottom: 30px;
}
.Form {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 40px;
}

View File

@@ -0,0 +1,27 @@
import s from './styles.module.scss';
import { Button, Input, PhoneInput } from '@shared/ui';
type CallbackFormProps = {
pageName: string;
};
function CallbackForm({ pageName }: CallbackFormProps) {
return (
<div className={s.Container}>
<h3 className={s.Title}>Узнать точную стоимость и срок экспертизы</h3>
<form className={s.Form}>
<Input variant={'ghost'} fullWidth placeholder='Ваше имя' />
<PhoneInput
variant={'ghost'}
fullWidth
placeholder='+7 999 123-45-67'
/>
<Button variant={'white'} fullWidth>
Узнать
</Button>
</form>
</div>
);
}
export { CallbackForm };

View File

@@ -0,0 +1 @@
export * from './ui';

View File

@@ -0,0 +1,61 @@
.Container {
display: grid;
grid-template-columns: auto 200px;
gap: 100px;
}
.Icons {
display: flex;
flex-direction: row;
justify-content: space-around;
.Icon {
display: flex;
flex-direction: column;
align-items: center;
.Image {
margin-bottom: 16px;
}
.Description {
font-family: $font-roboto;
font-weight: 400;
font-size: 16px;
line-height: 130%;
color: $color-green;
text-transform: uppercase;
}
}
}
.CallOrder {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 16px;
.Title {
font-family: $font-roboto;
font-weight: 400;
font-size: 20px;
line-height: 100%;
color: $color-text;
}
.Btn {
border-width: 1px 1px 1px 1px;
border-color: $color-green;
border-radius: 15px 15px 15px 15px;
box-shadow: 2px 2px 5px 0px $color-green;
}
.Description {
font-family: $font-roboto;
font-weight: 300;
font-size: 14px;
line-height: 100%;
color: $color-text;
}
}

View File

@@ -0,0 +1,36 @@
import s from './style.module.scss';
import { Button } from '@shared/ui';
import Image from 'next/image';
import emailImg from '@public/images/em-rounded-logo.png';
import tgImg from '@public/images/tg-rounded-logo.png';
import waImg from '@public/images/wa-rounded-logo.png';
function Connect() {
return (
<div className={s.Container}>
<div className={s.Icons}>
<div className={s.Icon}>
<Image src={waImg} alt={''} className={s.Image} />
<p className={s.Description}>WHATSAPP</p>
</div>
<div className={s.Icon}>
<Image src={tgImg} alt={''} className={s.Image} />
<p className={s.Description}>TELEGRAM</p>
</div>
<div className={s.Icon}>
<Image src={emailImg} alt={''} className={s.Image} />
<p className={s.Description}>EMAIL</p>
</div>
</div>
<div className={s.CallOrder}>
<h4 className={s.Title}>Звоните по телефону</h4>
<Button variant={'white'} className={s.Btn}>
+7 (900) 241-34-34
</Button>
<p className={s.Description}>мы работаем с 08:00 до 17:00</p>
</div>
</div>
);
}
export { Connect };

View File

@@ -1,2 +1,4 @@
export { TopMenu } from './top-menu';
export { BaseMenu } from './base-menu';
export * from './top-menu';
export * from './base-menu';
export * from './callback-form';
export * from './connect';

View File

@@ -0,0 +1 @@
export * from './ui';

View File

@@ -0,0 +1,105 @@
.Button {
display: flex;
align-items: center;
justify-content: center;
padding: rem(8px) rem(10px);
border-radius: rem(16px);
min-height: rem(40px);
font-family: $font-roboto;
font-weight: $font-regular;
font-size: rem(16px);
line-height: 100%;
transition: all 0.15s linear;
white-space: nowrap;
width: max-content;
@include ifdesktop{
font-size: rem(20px);
border-radius: rem(16px);
padding: rem(4px) rem(24px);
min-height: rem(48px);
}
&_fullWidth {
width: 100%;
}
svg {
width: rem(18px);
height: rem(18px);
//fill: var(--text-primary);
margin-right: rem(18px);
}
&:hover {
cursor: pointer;
box-shadow: 1px 1px 1px 0px $color-darkgray;
}
&:active {
box-shadow: inset 1px 1px 2px 0px $color-darkgray;
}
&:hover svg {
fill: var(--white);
}
&_default {
background: $color-green;
color: $color-white;
}
&_green {
background: $color-green;
color: $color-white;
}
&_ghost {
background: transparent;
color: $color-white;
border: 1px solid $color-white;
&:hover {
cursor: pointer;
box-shadow: 0 0 0 0.2rem rgb(76 175 80 / 50%);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
&:active {
box-shadow: 0 0 0 0.2rem rgb(76 175 80 / 50%);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
&:hover svg {
fill: var(--white);
}
}
&_white {
background: $color-white;
color: $color-green;
border: 1px solid $color-green;
&:hover {
cursor: pointer;
box-shadow: 0 0 0 0.2rem rgb(76 175 80 / 50%);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
&:active {
box-shadow: 0 0 0 0.2rem rgb(76 175 80 / 50%);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
&:hover svg {
fill: var(--white);
}
}
&_disabled {
cursor: not-allowed;
}
}

View File

@@ -0,0 +1,53 @@
import s from './styles.module.scss';
import {
ButtonHTMLAttributes,
DetailedHTMLProps,
FunctionComponent,
ReactNode,
SVGProps,
} from 'react';
import { clsx } from 'clsx';
type ButtonProps = {
className?: string;
children?: ReactNode;
disabled?: boolean;
Icon?: FunctionComponent<SVGProps<SVGSVGElement>>;
onClick?: () => void;
variant?: 'default' | 'green' | 'ghost' | 'white';
fullWidth?: boolean;
} & DetailedHTMLProps<
ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
>;
function Button({
className,
children,
onClick,
Icon,
disabled,
variant = 'default',
fullWidth = false,
...props
}: ButtonProps) {
return (
<button
className={clsx(
className,
s.Button,
disabled && s.Button_disabled,
s['Button_' + variant],
fullWidth && s.Button_fullWidth,
)}
onClick={onClick}
disabled={disabled}
{...props}
>
{Icon && <Icon />}
{children}
</button>
);
}
export { Button };

3
src/shared/ui/index.ts Normal file
View File

@@ -0,0 +1,3 @@
export * from './input';
export * from './phone-input';
export * from './button';

View File

@@ -0,0 +1 @@
export * from './ui';

View File

@@ -0,0 +1,98 @@
.Container {
position: relative;
display: block;
}
.Input {
display: flex;
background: $color-white;
border: 1px solid $color-darkgray;
border-radius: rem(16px);
padding: rem(4px) rem(10px);
transition: border ease .5s;
font-family: $font-roboto;
font-weight: $font-regular;
font-size: rem(16px);
line-height: 100%;
color: $color-text;
width: max-content;
@include iftablet {
font-size: rem(16px);
}
@include iflaptop {
font-size: rem(18px);
padding: rem(10px) rem(16px);
}
@include ifdesktop {
font-size: rem(20px);
}
&:focus {
border-color: $color-green;
transition: border-color ease .5s;
}
&:hover {
border-color: $color-text;
transition: border-color ease .5s;
}
&:focus:hover {
border-color: $color-green;
transition: border-color ease .5s;
}
&_error {
border-color: $color-error;
}
&_fullWidth {
width: 100%;
}
&_ghost {
background: transparent;
color: $color-white;
border: 1px solid $color-white;
&:focus {
//border-color: $color-orange;
border-color: $color-white;
box-shadow: 0 0 0 0.2rem rgb(76 175 80 / 50%);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
&:hover {
border-color: $color-white;
box-shadow: 0 0 0 0.2rem rgb(76 175 80 / 50%);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
&:focus:hover {
//border-color: $color-orange;
border-color: $color-white;
box-shadow: 0 0 0 0.2rem rgb(76 175 80 / 50%);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
&::placeholder {
color: $color-white;
}
}
}
.Error {
position: absolute;
z-index: 2;
left: rem(8px);
bottom: rem(-16px);
font-family: $font-roboto;
font-weight: $font-light;
font-size: rem(12px);
line-height: 100%;
color: $color-error;
}

View File

@@ -0,0 +1,50 @@
'use client';
import s from './styles.module.scss';
import { DetailedHTMLProps, forwardRef, InputHTMLAttributes, Ref } from 'react';
import { clsx } from 'clsx';
type InputProps = {
wrapperClassName?: string;
className?: string;
fullWidth?: boolean;
variant?: 'default' | 'ghost';
error?: string | boolean;
errorTextColor?: string;
} & DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
const Input = forwardRef(function Input(
{
className,
fullWidth = false,
variant = 'default',
error = false,
errorTextColor,
...props
}: InputProps,
ref: Ref<HTMLInputElement>,
) {
return (
<div className={s.Container}>
<input
{...props}
ref={ref}
className={clsx(
s.Input,
s['Input_' + variant],
fullWidth && s.Input_fullWidth,
error && s.Input_error,
className,
)}
/>
{error && (
<span className={s.Error} style={{ color: errorTextColor }}>
{error}
</span>
)}
</div>
);
});
export { Input };

View File

@@ -0,0 +1 @@
export * from './ui';

View File

@@ -0,0 +1,27 @@
'use client';
import { useMaskito } from '@maskito/react';
import { maskitoPhoneOptionsGenerator } from '@maskito/phone';
import metadata from 'libphonenumber-js/min/metadata';
import { DetailedHTMLProps, InputHTMLAttributes } from 'react';
import { Input } from '@shared/ui';
type PhoneInput = {
className?: string;
variant?: 'default' | 'ghost';
error?: string | boolean;
errorTextColor?: string;
fullWidth?: boolean;
} & DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
function PhoneInput({ ...props }: PhoneInput) {
const options = maskitoPhoneOptionsGenerator({
countryIsoCode: 'RU',
metadata,
});
const maskedInputRef = useMaskito({ options });
return <Input {...props} ref={maskedInputRef} type='tel' />;
}
export { PhoneInput };

View File

@@ -45,4 +45,4 @@
color: $color-text;
margin-bottom: 16px;
}
}
}

View File

@@ -1,4 +1,5 @@
import s from './styles.module.scss';
import { CallbackForm, Connect } from '@/entities';
function AutoTech() {
return (
@@ -48,7 +49,7 @@ function AutoTech() {
изменен.
</li>
</ul>
WIDGET
<CallbackForm pageName='Автотехническая экспертиза' />
<h3 className={s.Header}>Документы, необходимые для экспертизы:</h3>
<p className={s.Text}>
Для начала работ по автомобильной экспертизе эксперту понадобятся
@@ -74,7 +75,7 @@ function AutoTech() {
Для того, чтобы заказать выполнение автотехнической экспертизы, вы
можете воспользоваться любым удобным способом.
</p>
WIDGET
<Connect />
</div>
<div className={s.Sidebar}>sidebar</div>
</div>