fix: add connect form
85
package-lock.json
generated
@@ -8,6 +8,9 @@
|
|||||||
"name": "ocenka-web",
|
"name": "ocenka-web",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@maskito/core": "^3.9.1",
|
||||||
|
"@maskito/phone": "^3.9.1",
|
||||||
|
"@maskito/react": "^3.9.1",
|
||||||
"next": "15.3.4",
|
"next": "15.3.4",
|
||||||
"nodemailer": "^7.0.3",
|
"nodemailer": "^7.0.3",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
@@ -15,7 +18,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
"@iconify-icon/react": "^3.0.0",
|
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
@@ -282,29 +284,6 @@
|
|||||||
"url": "https://github.com/sponsors/nzakas"
|
"url": "https://github.com/sponsors/nzakas"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@iconify-icon/react": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@iconify-icon/react/-/react-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-TOyzGUIfOFbmRQflMbf8k8bBGbeVAVCnvJ/rKz2SgBOV6VZLv7E9gzLvkPzfkZ2HZL+GbRtLNX/GJq2EI54OFQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"iconify-icon": "^3.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/cyberalien"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">=16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@iconify/types": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-darwin-arm64": {
|
"node_modules/@img/sharp-darwin-arm64": {
|
||||||
"version": "0.34.2",
|
"version": "0.34.2",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz",
|
||||||
@@ -701,6 +680,44 @@
|
|||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@maskito/core": {
|
||||||
|
"version": "3.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@maskito/core/-/core-3.9.1.tgz",
|
||||||
|
"integrity": "sha512-Sa3GFdgWZKRBLAVrrHbT0uI6fI8zMy2/yPvBuhxG5W4a+uYRCb9mpC52yZaUcVa7Gq4OvFIy03c53LntuXStmw==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/@maskito/kit": {
|
||||||
|
"version": "3.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@maskito/kit/-/kit-3.9.1.tgz",
|
||||||
|
"integrity": "sha512-r9kR4mwKz7jILUknHYpQPMBy7sXsptoOivt8S8ymf7yzTlJpfhfS+C2WiAKR24UyilhKBezC5kFR3nljKnHBCw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"@maskito/core": "^3.9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@maskito/phone": {
|
||||||
|
"version": "3.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@maskito/phone/-/phone-3.9.1.tgz",
|
||||||
|
"integrity": "sha512-a/pefAll5iwhdB/o/t/h+LJfUG94dt6JsQyhC7owxAzGicDq3O6qZ/fApsdNWfI7VvBc846Hd0IEb4ds5tNX/g==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@maskito/core": "^3.9.1",
|
||||||
|
"@maskito/kit": "^3.9.1",
|
||||||
|
"libphonenumber-js": ">=1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@maskito/react": {
|
||||||
|
"version": "3.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@maskito/react/-/react-3.9.1.tgz",
|
||||||
|
"integrity": "sha512-DF125ifk8X8cye9zsPvJScaPo9I/hhVCYcIC2UrBdS3BtVgxk+/tPeA5qQWUHi7xGKNDDniYMFXqVlZaofWw4w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@maskito/core": "^3.9.1",
|
||||||
|
"react": ">=16.8",
|
||||||
|
"react-dom": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "0.2.11",
|
"version": "0.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz",
|
||||||
@@ -3468,19 +3485,6 @@
|
|||||||
"url": "https://github.com/sponsors/typicode"
|
"url": "https://github.com/sponsors/typicode"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/iconify-icon": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-yPcnpkn8HUEUckrxxJBOer3jbGv3bqozHsLMLBRxhk3As1X76BgV2mS2a1HTNOIagR8nUs30H3qAd9GLe8Mnlg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@iconify/types": "^2.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/cyberalien"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
@@ -4120,6 +4124,13 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/libphonenumber-js": {
|
||||||
|
"version": "1.12.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.9.tgz",
|
||||||
|
"integrity": "sha512-VWwAdNeJgN7jFOD+wN4qx83DTPMVPPAUyx9/TUkBXKLiNkuWWk6anV0439tgdtwaJDrEdqkvdN22iA6J4bUCZg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
"prepare": "husky"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@maskito/core": "^3.9.1",
|
||||||
|
"@maskito/phone": "^3.9.1",
|
||||||
|
"@maskito/react": "^3.9.1",
|
||||||
"next": "15.3.4",
|
"next": "15.3.4",
|
||||||
"nodemailer": "^7.0.3",
|
"nodemailer": "^7.0.3",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
|||||||
BIN
public/images/em-rounded-logo.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
public/images/step1.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/images/step2.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/images/step3.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/images/step4.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/images/tg-rounded-logo.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
public/images/wa-rounded-logo.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
@@ -23,6 +23,7 @@ $color-lightgray: #E4E1E1;
|
|||||||
$color-darkgray: #999999;
|
$color-darkgray: #999999;
|
||||||
$color-text: #333333;
|
$color-text: #333333;
|
||||||
$color-text-light: #222222;
|
$color-text-light: #222222;
|
||||||
|
$color-green: #23A455;
|
||||||
$color-link: #333333;
|
$color-link: #333333;
|
||||||
$color-link-hover: #009283;
|
$color-link-hover: #009283;
|
||||||
$color-error: #ff0000;
|
$color-error: #ff0000;
|
||||||
|
|||||||
1
src/entities/callback-form/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './ui';
|
||||||
26
src/entities/callback-form/styles.module.scss
Normal 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;
|
||||||
|
}
|
||||||
27
src/entities/callback-form/ui.tsx
Normal 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 };
|
||||||
1
src/entities/connect/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './ui';
|
||||||
61
src/entities/connect/style.module.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/entities/connect/ui.tsx
Normal 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 };
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
export { TopMenu } from './top-menu';
|
export * from './top-menu';
|
||||||
export { BaseMenu } from './base-menu';
|
export * from './base-menu';
|
||||||
|
export * from './callback-form';
|
||||||
|
export * from './connect';
|
||||||
|
|||||||
1
src/shared/ui/button/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './ui';
|
||||||
105
src/shared/ui/button/styles.module.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/shared/ui/button/ui.tsx
Normal 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
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './input';
|
||||||
|
export * from './phone-input';
|
||||||
|
export * from './button';
|
||||||
1
src/shared/ui/input/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './ui';
|
||||||
98
src/shared/ui/input/styles.module.scss
Normal 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;
|
||||||
|
}
|
||||||
50
src/shared/ui/input/ui.tsx
Normal 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 };
|
||||||
1
src/shared/ui/phone-input/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './ui';
|
||||||
27
src/shared/ui/phone-input/ui.tsx
Normal 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 };
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import s from './styles.module.scss';
|
import s from './styles.module.scss';
|
||||||
|
import { CallbackForm, Connect } from '@/entities';
|
||||||
|
|
||||||
function AutoTech() {
|
function AutoTech() {
|
||||||
return (
|
return (
|
||||||
@@ -48,7 +49,7 @@ function AutoTech() {
|
|||||||
изменен.
|
изменен.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
WIDGET
|
<CallbackForm pageName='Автотехническая экспертиза' />
|
||||||
<h3 className={s.Header}>Документы, необходимые для экспертизы:</h3>
|
<h3 className={s.Header}>Документы, необходимые для экспертизы:</h3>
|
||||||
<p className={s.Text}>
|
<p className={s.Text}>
|
||||||
Для начала работ по автомобильной экспертизе эксперту понадобятся
|
Для начала работ по автомобильной экспертизе эксперту понадобятся
|
||||||
@@ -74,7 +75,7 @@ function AutoTech() {
|
|||||||
Для того, чтобы заказать выполнение автотехнической экспертизы, вы
|
Для того, чтобы заказать выполнение автотехнической экспертизы, вы
|
||||||
можете воспользоваться любым удобным способом.
|
можете воспользоваться любым удобным способом.
|
||||||
</p>
|
</p>
|
||||||
WIDGET
|
<Connect />
|
||||||
</div>
|
</div>
|
||||||
<div className={s.Sidebar}>sidebar</div>
|
<div className={s.Sidebar}>sidebar</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||