Ручная вёртска по макетам

This commit is contained in:
Sergey Bolshakov 2025-10-20 20:18:46 +03:00
parent a31b68ec68
commit 0bf248ac64
31 changed files with 4173 additions and 186 deletions

View File

@ -1,7 +1,33 @@
import type { NextConfig } from "next"; import type { NextConfig } from "next";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
/* config options here */ webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: [
{
loader: "@svgr/webpack",
options: {
svgo: false,
titleProp: true,
ref: true,
},
},
],
});
return config;
},
experimental: {
turbo: {
rules: {
"*.svg": {
loaders: ["@svgr/webpack"],
as: "*.js",
},
},
},
},
}; };
export default nextConfig; export default nextConfig;

3204
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,19 +10,24 @@
}, },
"dependencies": { "dependencies": {
"@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
"lucide-react": "^0.546.0", "lucide-react": "^0.546.0",
"next": "15.5.5", "next": "15.5.5",
"react": "19.1.0", "react": "19.1.0",
"react-day-picker": "^9.11.1",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3", "@eslint/eslintrc": "^3",
"@svgr/webpack": "^8.1.0",
"@tailwindcss/postcss": "^4", "@tailwindcss/postcss": "^4",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^19", "@types/react": "^19",

BIN
public/images/advantage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 8.99999C14 11.382 12.27 11.854 10.881 12.233C9.361 12.648 8.5 12.957 8.5 14.5C8.5 14.6326 8.44732 14.7598 8.35355 14.8535C8.25979 14.9473 8.13261 15 8 15C7.86739 15 7.74021 14.9473 7.64645 14.8535C7.55268 14.7598 7.5 14.6326 7.5 14.5C7.5 12.957 6.64 12.648 5.119 12.233C3.729 11.853 2 11.382 2 8.99999C2 8.86738 2.05268 8.7402 2.14645 8.64644C2.24021 8.55267 2.36739 8.49999 2.5 8.49999C2.63261 8.49999 2.75979 8.55267 2.85355 8.64644C2.94732 8.7402 3 8.86738 3 8.99999C3 10.543 3.86 10.853 5.381 11.268C6.091 11.461 6.889 11.68 7.5 12.164V7.99999H5.5C5.36739 7.99999 5.24021 7.94731 5.14645 7.85354C5.05268 7.75978 5 7.6326 5 7.49999C5 7.36738 5.05268 7.2402 5.14645 7.14644C5.24021 7.05267 5.36739 6.99999 5.5 6.99999H7.5V5.17699C7.09717 5.05689 6.75103 4.7958 6.52487 4.44147C6.29871 4.08714 6.20765 3.66324 6.26833 3.24729C6.32902 2.83134 6.5374 2.45113 6.85537 2.17619C7.17334 1.90124 7.57965 1.74994 8 1.74994C8.42035 1.74994 8.82666 1.90124 9.14463 2.17619C9.4626 2.45113 9.67098 2.83134 9.73167 3.24729C9.79235 3.66324 9.70129 4.08714 9.47513 4.44147C9.24897 4.7958 8.90283 5.05689 8.5 5.17699V6.99999H10.5C10.6326 6.99999 10.7598 7.05267 10.8536 7.14644C10.9473 7.2402 11 7.36738 11 7.49999C11 7.6326 10.9473 7.75978 10.8536 7.85354C10.7598 7.94731 10.6326 7.99999 10.5 7.99999H8.5V12.164C9.111 11.68 9.909 11.461 10.619 11.268C12.139 10.853 13 10.543 13 8.99999C13 8.86738 13.0527 8.7402 13.1464 8.64644C13.2402 8.55267 13.3674 8.49999 13.5 8.49999C13.6326 8.49999 13.7598 8.55267 13.8536 8.64644C13.9473 8.7402 14 8.86738 14 8.99999Z" fill="#008299"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5_992)">
<path d="M19 4.66667H18.1667V3H16.5V4.66667H8.16667V3H6.5V4.66667H5.66667C4.75 4.66667 4 5.41667 4 6.33333V19.6667C4 20.5833 4.75 21.3333 5.66667 21.3333H19C19.9167 21.3333 20.6667 20.5833 20.6667 19.6667V6.33333C20.6667 5.41667 19.9167 4.66667 19 4.66667ZM19 19.6667H5.66667V8.83333H19V19.6667Z" fill="#008299"/>
</g>
<defs>
<clipPath id="clip0_5_992">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 555 B

View File

@ -0,0 +1,3 @@
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.9852 8.22711C18.0144 8.33153 17.9811 8.43435 17.9811 8.53716C17.9819 9.30506 17.9794 10.0738 17.9786 10.8417C17.9786 11.583 17.9802 13.0682 17.9777 14H11.2568V8.28655C11.4068 8.20864 11.5526 8.12349 11.6942 8.02871C12.3282 7.61504 13.0214 7.27447 13.7712 7.109C14.3352 6.9845 14.9168 6.95558 15.4816 6.8367C15.9865 6.72987 16.5972 6.57163 16.9738 6.20776C17.0205 6.16439 17.2254 5.97964 17.2004 5.91779C17.1671 5.83185 17.0646 5.85112 17.018 5.87843C16.8055 6.00294 16.4831 6.01338 16.2415 6.05836C15.5941 6.17885 14.9526 6.28487 14.2911 6.28487C13.6546 6.27925 13.0164 6.26078 12.3824 6.33869C11.9358 6.39492 11.4609 6.49693 11.0777 6.74915C10.976 6.81662 10.8635 6.92747 10.986 6.99494C11.2651 7.14996 11.2743 7.55962 11.6842 7.59416C11.4692 7.77569 11.2018 7.7781 11.0168 7.92509C10.8419 8.06486 10.6794 8.04558 10.4936 7.94758C9.9421 7.6544 9.48054 7.24555 8.99065 6.87445C8.6574 6.62384 8.29498 6.45837 7.87341 6.3917C7.1919 6.28568 6.50706 6.27443 5.82139 6.28568C5.13572 6.29612 4.45421 6.2423 3.78853 6.09129C3.38945 6.00133 2.99455 5.88807 2.58298 5.81417C2.58298 5.82301 2.69545 5.99812 2.71128 6.01338C2.7696 6.07282 2.83375 6.12503 2.89957 6.17563C4.09846 7.09534 5.74474 6.89052 7.11109 7.40299C7.57515 7.57729 8.03837 7.75641 8.48994 7.95722C8.79237 8.09217 8.79653 8.20141 8.57242 8.42792C8.45994 8.54037 8.32914 8.6207 8.18584 8.69781C7.97505 8.81267 7.71178 8.85203 7.54265 9.07212C7.92257 9.14361 8.36163 9.07051 8.75987 9.00063V13.9992H2.02394C2.02227 13.0674 2.02394 11.583 2.02394 10.8409C2.02311 10.073 2.02061 9.30426 2.02144 8.53636C2.02144 8.43354 1.98811 8.32992 2.01727 8.22631C2.01811 7.97971 2.01894 7.73231 2.01977 7.48572C2.02061 6.99735 2.02061 6.51058 2.02061 6.02302C2.00894 6.01017 2.00894 5.99651 2.02061 5.98366C2.01477 4.7049 2.00894 3.42694 2.00561 2.14899C2.00478 2.09919 1.97562 2.03252 2.05893 2.01083C2.07309 1.99878 2.08892 1.99798 2.10559 2.00521C2.23389 2.00601 2.36136 2.00601 2.48966 2.00681C2.498 2.00762 2.50549 2.00762 2.51216 2.00762C2.55132 2.00922 2.59047 2.01003 2.62796 2.01163C2.63796 2.00119 2.64796 2.00119 2.65712 2.01163C3.92433 2.01083 5.19237 2.01404 6.45957 2.00762C6.83782 2.00521 7.21606 2.02529 7.59431 2.0036C7.71928 1.99557 7.82092 2.03252 7.9159 2.1281C8.13668 2.34658 8.3633 2.56025 8.58241 2.77953C8.86735 3.06548 9.17811 3.32573 9.45304 3.61972C9.59384 3.76912 9.74631 3.90567 9.89627 4.04544C9.9121 4.0607 9.92627 4.06954 9.94043 4.07757C9.97792 4.08078 9.99875 4.08399 9.99875 4.08399V4.0864L10.0004 4.08399C10.0004 4.08399 10.0221 4.08158 10.0596 4.07757C10.0737 4.06954 10.0887 4.0599 10.1037 4.04544C10.2545 3.90567 10.407 3.76912 10.547 3.61972C10.8219 3.32573 11.1327 3.06548 11.4176 2.77953C11.6367 2.56025 11.8642 2.34658 12.0841 2.1281C12.1791 2.03252 12.2807 1.99637 12.4057 2.0036C12.7839 2.02529 13.1622 2.00521 13.5404 2.00762C14.8076 2.01485 16.0757 2.01083 17.3429 2.01163C17.352 2.00119 17.362 2.00119 17.372 2.01163C17.4112 2.01003 17.4495 2.00922 17.4878 2.00762C17.4953 2.00762 17.502 2.00762 17.5103 2.00681C17.6386 2.00601 17.7661 2.00601 17.8944 2.00521C17.9111 1.99717 17.9261 1.99798 17.9411 2.01083C18.0244 2.03252 17.9952 2.09919 17.9944 2.14899C17.9911 3.42694 17.9852 4.7049 17.9802 5.98366C17.9919 5.99651 17.9919 6.01017 17.9802 6.02302C17.9802 6.51139 17.9802 6.99815 17.9811 7.48572C17.9819 7.73231 17.9827 7.97971 17.9836 8.22631L17.9852 8.22711Z" fill="#008299"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 3C10.1435 3 8.36301 3.7375 7.05025 5.05025C5.7375 6.36301 5 8.14348 5 10C5 14 9.5 18 12 20.5C14.5 18 19 13.866 19 10C19 8.14348 18.2625 6.36301 16.9497 5.05025C15.637 3.7375 13.8565 3 12 3Z" stroke="#008299" stroke-width="2"/>
<path d="M12 12C13.1046 12 14 11.1046 14 10C14 8.89543 13.1046 8 12 8C10.8954 8 10 8.89543 10 10C10 11.1046 10.8954 12 12 12Z" fill="#008299"/>
</svg>

After

Width:  |  Height:  |  Size: 487 B

View File

@ -0,0 +1,26 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.6451 23.0928C10.6451 23.4084 11.0963 23.6976 11.8469 23.9232H11.8475C12.8171 24.2148 14.2871 24.4008 15.9323 24.4008C17.5775 24.4008 19.0475 24.2148 20.0171 23.9232H20.0177C20.7683 23.6976 21.2195 23.4084 21.2195 23.0928" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20.018 23.9232H20.0172" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.8478 23.9232H11.847" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.6451 21.0677C10.6451 21.4757 11.4005 21.8405 12.5849 22.0805C13.4963 22.2647 14.6621 22.3757 15.9323 22.3757C17.2025 22.3757 18.3683 22.2647 19.2797 22.0805C20.4641 21.8405 21.2195 21.4757 21.2195 21.0677" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.2794 20.0555H19.2786" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.5864 20.0555H12.5856" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.613 18.2886C11.0034 18.5016 10.6458 18.762 10.6458 19.0428C10.6458 19.4508 11.4018 19.8156 12.5868 20.0556C13.4976 20.2392 14.6634 20.3502 15.933 20.3502C17.2026 20.3502 18.3684 20.2392 19.2792 20.0556C20.4642 19.8156 21.2202 19.4508 21.2202 19.0428C21.2202 18.4266 19.4988 17.9106 17.1804 17.772H17.1786" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16.2073 16.0056H16.2065" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.51435 16.0056H9.51355" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.57324 17.0178C7.57324 17.634 9.29464 18.15 11.6124 18.2886C12.012 18.3126 12.4302 18.3252 12.8598 18.3252C14.643 18.3252 16.2204 18.1068 17.178 17.772H17.1792C17.7888 17.559 18.147 17.2986 18.147 17.0178" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17.2794 14.2746C17.8284 14.4804 18.1476 14.7276 18.1476 14.9928C18.1476 15.4008 17.3916 15.765 16.2066 16.0056C15.2958 16.1892 14.13 16.3002 12.8604 16.3002C11.5908 16.3002 10.425 16.1892 9.51424 16.0056C8.32924 15.765 7.57324 15.4008 7.57324 14.9928C7.57324 14.2818 9.86464 13.704 12.72 13.6854" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22.4268 12.9678C22.4268 13.6782 20.1348 14.2566 17.2794 14.2746C17.2332 14.2752 17.1858 14.2752 17.139 14.2752C15.2916 14.2752 13.6656 14.0406 12.72 13.6854C12.171 13.4796 11.8518 13.233 11.8518 12.9678" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.791 9.81116C21.3672 10.0374 22.4268 10.4592 22.4268 10.9428C22.4268 11.3508 21.6714 11.715 20.487 11.955C19.5756 12.1392 18.4098 12.2502 17.139 12.2502C15.8682 12.2502 14.703 12.1392 13.7916 11.955C12.6072 11.715 11.8518 11.3508 11.8518 10.9428C11.8518 10.5972 12.3942 10.2822 13.2804 10.0488" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21.2195 8.91724C21.2195 9.26284 20.6771 9.57784 19.7909 9.81124C18.8261 10.0662 17.4545 10.2252 15.9323 10.2252C14.9657 10.2252 14.0597 10.161 13.2803 10.0488C11.7047 9.82264 10.6451 9.40024 10.6451 8.91724" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.2431 5.87284C20.4485 6.11224 21.2195 6.48004 21.2195 6.89224C21.2195 7.61464 18.8525 8.19964 15.9323 8.19964C13.0121 8.19964 10.6451 7.61404 10.6451 6.89224C10.6451 6.23704 12.5951 5.69404 15.1391 5.59924" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21.2202 6.89221V8.91721" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.6451 6.89221V8.91721" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22.4268 10.9421V12.9671" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.8518 10.9421V13.1543" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.1476 14.9922V17.0178" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.57324 14.9922V17.0178" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21.2202 19.0428V23.0928" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.6451 19.0428V23.0928" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16.8594 5.65137H17.319" stroke="#008299" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.5 11C15.828 11.0003 16.1528 10.9358 16.4558 10.8101C16.7588 10.6845 17.034 10.5002 17.2655 10.2679C17.4971 10.0356 17.6805 9.75984 17.8051 9.45645C17.9298 9.15306 17.9933 8.82803 17.992 8.50003C18.0014 8.16631 17.9439 7.83408 17.8227 7.52299C17.7015 7.21191 17.5192 6.92828 17.2865 6.68889C17.0537 6.4495 16.7754 6.25921 16.4679 6.12926C16.1603 5.99932 15.8299 5.93237 15.496 5.93237C15.1621 5.93237 14.8317 5.99932 14.5241 6.12926C14.2166 6.25921 13.9383 6.4495 13.7055 6.68889C13.4728 6.92828 13.2905 7.21191 13.1693 7.52299C13.0481 7.83408 12.9906 8.16631 13 8.50003C13 9.88303 14.117 11 15.5 11ZM8.833 11C9.161 11.0003 9.48583 10.9358 9.78881 10.8101C10.0918 10.6845 10.367 10.5002 10.5985 10.2679C10.8301 10.0356 11.0135 9.75984 11.1381 9.45645C11.2628 9.15306 11.3263 8.82803 11.325 8.50003C11.3344 8.16631 11.2769 7.83408 11.1557 7.52299C11.0345 7.21191 10.8522 6.92828 10.6195 6.68889C10.3867 6.4495 10.1084 6.25921 9.80086 6.12926C9.49333 5.99932 9.16286 5.93237 8.829 5.93237C8.49514 5.93237 8.16467 5.99932 7.85714 6.12926C7.54961 6.25921 7.27126 6.4495 7.03855 6.68889C6.80584 6.92828 6.6235 7.21191 6.50231 7.52299C6.38112 7.83408 6.32355 8.16631 6.333 8.50003C6.333 9.88303 7.45 11 8.833 11ZM8.833 12.667C6.892 12.667 3 13.642 3 15.583V17.667H14.667V15.583C14.667 13.642 10.775 12.667 8.833 12.667ZM15.5 12.667C15.2302 12.6695 14.9606 12.6832 14.692 12.708C15.658 13.408 16.333 14.35 16.333 15.583V17.667H21.333V15.583C21.333 13.642 17.442 12.667 15.5 12.667Z" fill="#008299"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_5_1124" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
<path d="M0 0H16V16H0V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_5_1124)">
<path d="M14.9 2.59605C14.7408 2.59605 14.5882 2.65927 14.4757 2.77179C14.3632 2.88431 14.3 3.03692 14.3 3.19605V4.54605C13.8158 3.98332 13.3125 3.43733 12.791 2.90905C11.7904 1.90826 10.5171 1.22453 9.13011 0.943291C7.74315 0.662055 6.30406 0.795787 4.99268 1.32778C3.68129 1.85977 2.55576 2.76642 1.75672 3.93445C0.957685 5.10248 0.520581 6.48008 0.500027 7.89512C0.479474 9.31015 0.876383 10.6999 1.64116 11.8906C2.40593 13.0814 3.50466 14.0203 4.80004 14.5902C6.09542 15.16 7.53002 15.3355 8.92456 15.0947C10.3191 14.8538 11.6117 14.2074 12.641 13.2361C12.7567 13.1267 12.8243 12.9757 12.8288 12.8165C12.8333 12.6573 12.7744 12.5028 12.665 12.3871C12.5556 12.2713 12.4047 12.2037 12.2454 12.1992C12.0862 12.1947 11.9317 12.2537 11.816 12.3631C10.958 13.1716 9.88078 13.7095 8.71893 13.9095C7.55707 14.1095 6.36204 13.9627 5.28307 13.4876C4.2041 13.0125 3.28901 12.2301 2.65207 11.238C2.01513 10.2459 1.68458 9.08816 1.70169 7.90934C1.7188 6.73052 2.08282 5.58286 2.74828 4.60969C3.41374 3.63651 4.35115 2.88095 5.44346 2.43735C6.53576 1.99375 7.73455 1.88178 8.89011 2.11542C10.0457 2.34906 11.1068 2.91795 11.941 3.75105C12.551 4.36905 13.086 4.96505 13.625 5.59605H11.9C11.7408 5.59605 11.5882 5.65927 11.4757 5.77179C11.3632 5.88431 11.3 6.03692 11.3 6.19605C11.3 6.35518 11.3632 6.5078 11.4757 6.62032C11.5882 6.73284 11.7408 6.79605 11.9 6.79605H14.9C15.0591 6.79605 15.2117 6.73284 15.3242 6.62032C15.4368 6.5078 15.5 6.35518 15.5 6.19605V3.19605C15.5 3.03692 15.4368 2.88431 15.3242 2.77179C15.2117 2.65927 15.0591 2.59605 14.9 2.59605Z" fill="white"/>
<path d="M8.29998 7.657V4.397C8.29998 4.23787 8.23676 4.08525 8.12424 3.97273C8.01172 3.86021 7.85911 3.797 7.69998 3.797C7.54085 3.797 7.38823 3.86021 7.27571 3.97273C7.16319 4.08525 7.09998 4.23787 7.09998 4.397V7.997C7.10003 8.1005 7.12686 8.20222 7.17785 8.29229C7.22884 8.38235 7.30226 8.4577 7.39098 8.511L10.391 10.311C10.5276 10.3929 10.6911 10.4173 10.8456 10.3787C11.0002 10.34 11.133 10.2416 11.215 10.105C11.2969 9.96841 11.3213 9.80486 11.2826 9.65033C11.244 9.4958 11.1456 9.36295 11.009 9.281L8.29998 7.657Z" fill="#008299"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 8L11.083 5M14 8L11.083 11M14 8H2M2 8L4.917 11M2 8L4.917 5" stroke="#008299" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 241 B

View File

@ -2,7 +2,7 @@ import Image from "next/image";
export default function Advantages() { export default function Advantages() {
return ( return (
<section className="container mx-auto px-4 py-16"> <section className="container max-w-6xl mx-auto px-4 py-16">
{/* Заголовок секции */} {/* Заголовок секции */}
<div className="text-center mb-12"> <div className="text-center mb-12">
<h2 className="text-4xl font-bold text-gray-800 mb-4"> <h2 className="text-4xl font-bold text-gray-800 mb-4">
@ -13,123 +13,158 @@ export default function Advantages() {
</p> </p>
</div> </div>
<div className="flex flex-col lg:flex-row items-start gap-12"> <div className="flex flex-col justify-between lg:flex-row gap-12">
{/* Левая колонка с тремя секциями */} {/* Левая колонка с тремя секциями */}
<div className="lg:w-1/2 space-y-8"> <div className="lg:w-2/5 space-y-8">
{/* Секция 01 */} {/* Секция 01 */}
<div> <div>
<div className="w-12 h-8 border border-blue-200 rounded-lg flex items-center justify-center mb-4"> <div className="w-12 h-8 border border-blue-200 rounded-full flex items-center justify-center mb-4">
<span className="text-blue-500 font-semibold text-lg">01</span> <span className=" font-semibold text-lg">01</span>
</div> </div>
<h3 className="text-xl font-bold text-gray-800 mb-3 text-left"> <h3 className="text-xl font-bold text-gray-800 mb-3 text-left">
Каталог лучших яхт Балаклавы в разных ценовых сегментах Каталог лучших яхт Балаклавы в разных ценовых
сегментах
</h3> </h3>
<p className="text-gray-600 leading-relaxed text-left"> <p className="text-gray-600 leading-relaxed text-left">
Проверенные лодки с лицензией на перевозки, надежные судовладельцы, опытные капитаны. Проверенные лодки с лицензией на перевозки, надежные
В нашем каталоге вы найдете катера, парусники, катамараны с фото, подробным описанием и диапазоном цен. судовладельцы, опытные капитаны. В нашем каталоге вы
найдете катера, парусники, катамараны с фото,
подробным описанием и диапазоном цен.
</p> </p>
</div> </div>
{/* Секция 02 */} {/* Секция 02 */}
<div> <div>
<div className="w-12 h-8 border border-blue-200 rounded-lg flex items-center justify-center mb-4"> <div className="w-12 h-8 border border-blue-200 rounded-full flex items-center justify-center mb-4">
<span className="text-blue-500 font-semibold text-lg">02</span> <span className=" font-semibold text-lg">02</span>
</div> </div>
<h3 className="text-xl font-bold text-gray-800 mb-3 text-left"> <h3 className="text-xl font-bold text-gray-800 mb-3 text-left">
Удобное самостоятельное бронирование яхты в аренду Удобное самостоятельное бронирование яхты в аренду
</h3> </h3>
<p className="text-gray-600 leading-relaxed text-left"> <p className="text-gray-600 leading-relaxed text-left">
Вы можете самостоятельно выбрать яхту на ваш вкус, взять любимую еду и напитки, поставить свой плей-лист. Вы можете самостоятельно выбрать яхту на ваш вкус,
На борту есть все для комфортного размещения. Выбирайте удобную дату, время и бронируйте. взять любимую еду и напитки, поставить свой
плей-лист. На борту есть все для комфортного
размещения. Выбирайте удобную дату, время и
бронируйте.
</p> </p>
</div> </div>
{/* Секция 03 */} {/* Секция 03 */}
<div> <div>
<div className="w-12 h-8 border border-blue-200 rounded-lg flex items-center justify-center mb-4"> <div className="w-12 h-8 border border-blue-200 rounded-full flex items-center justify-center mb-4">
<span className="text-blue-500 font-semibold text-lg">03</span> <span className=" font-semibold text-lg">03</span>
</div> </div>
<h3 className="text-xl font-bold text-gray-800 mb-3 text-left"> <h3 className="text-xl font-bold text-gray-800 mb-3 text-left">
Организация морских прогулок под ключ Организация морских прогулок под ключ
</h3> </h3>
<p className="text-gray-600 leading-relaxed text-left"> <p className="text-gray-600 leading-relaxed text-left">
Вы можете связаться с нами, и наш менеджер поможет вам подобрать яхту, а также организовать праздник на борту: Вы можете связаться с нами, и наш менеджер поможет
шампанское и фрукты, кейтеринг по меню, музыканты и DJ, украшение яхты, прогулка в подарок. вам подобрать яхту, а также организовать праздник на
борту: шампанское и фрукты, кейтеринг по меню,
музыканты и DJ, украшение яхты, прогулка в подарок.
</p> </p>
</div> </div>
</div> </div>
{/* Правая колонка с изображением и оверлейными карточками */} {/* Правая колонка с изображением и оверлейными карточками */}
<div className="lg:w-1/2 relative"> <div className=" relative">
<div className="relative"> <div className="relative">
<Image <Image
src="/images/yacht.jpg" src="/images/advantage.png"
alt="Яхта в Балаклаве" alt="Яхта в Балаклаве"
width={600} width={460}
height={800} height={620}
className="rounded-2xl object-cover" className="rounded-2xl object-cover"
/> />
{/* Оверлейные карточки */} {/* Оверлейные карточки */}
<div className="absolute top-8 left-8 bg-white rounded-xl p-4 shadow-lg"> <div className="absolute top-16 left-[-100px] border bg-white rounded-full w-[300px] p-2 shadow-lg">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Image <Image
src="/images/yacht.jpg" src="/images/another-yacht.jpg"
alt="Яхта" alt="Яхта"
width={40} width={40}
height={40} height={40}
className="rounded-lg object-cover" className="rounded-full h-[40px] w-[40px] object-fill"
/> />
<div> <div>
<p className="font-medium text-gray-800">Яхта</p> <p className="font-medium text-gray-800">
Яхта
</p>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{[...Array(5)].map((_, i) => ( {[...Array(5)].map((_, i) => (
<span key={i} className="text-yellow-400"></span> <span
key={i}
className="text-yellow-400"
>
</span>
))} ))}
<span className="text-sm text-gray-600">
124
</span>
</div> </div>
<p className="text-sm text-gray-600">124</p>
</div> </div>
</div> </div>
</div> </div>
<div className="absolute top-1/2 left-8 bg-white rounded-xl p-4 shadow-lg"> <div className="absolute top-1/2 right-[-100px] border bg-white rounded-full w-[300px] p-2 shadow-lg">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Image <Image
src="/images/yacht.jpg" src="/images/another-yacht.jpg"
alt="Яхта" alt="Яхта"
width={40} width={40}
height={40} height={40}
className="rounded-lg object-cover" className="rounded-full h-[40px] w-[40px] object-fill"
/> />
<div> <div>
<p className="font-medium text-gray-800">Яхта</p> <p className="font-medium text-gray-800">
Яхта
</p>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{[...Array(5)].map((_, i) => ( {[...Array(5)].map((_, i) => (
<span key={i} className="text-yellow-400"></span> <span
key={i}
className="text-yellow-400"
>
</span>
))} ))}
<span className="text-sm text-gray-600">
124
</span>
</div> </div>
<p className="text-sm text-gray-600">88</p>
</div> </div>
</div> </div>
</div> </div>
<div className="absolute bottom-8 left-8 bg-white rounded-xl p-4 shadow-lg"> <div className="absolute bottom-8 left-8 border bg-white rounded-full w-[300px] p-2 shadow-lg">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Image <Image
src="/images/yacht.jpg" src="/images/another-yacht.jpg"
alt="Яхта" alt="Яхта"
width={40} width={40}
height={40} height={40}
className="rounded-lg object-cover" className="rounded-full h-[40px] w-[40px] object-fill"
/> />
<div> <div>
<p className="font-medium text-gray-800">Яхта</p> <p className="font-medium text-gray-800">
Яхта
</p>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{[...Array(5)].map((_, i) => ( {[...Array(5)].map((_, i) => (
<span key={i} className="text-yellow-400"></span> <span
key={i}
className="text-yellow-400"
>
</span>
))} ))}
<span className="text-sm text-gray-600">
124
</span>
</div> </div>
<p className="text-sm text-gray-600">88</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -32,7 +32,7 @@ const articles = [
export default function Articles() { export default function Articles() {
return ( return (
<section className="container mx-auto px-4 py-12"> <section className="container max-w-6xl mx-auto px-4 py-12">
<h2 className="text-3xl font-bold mb-8 text-left">Полезные статьи</h2> <h2 className="text-3xl font-bold mb-8 text-left">Полезные статьи</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{articles.map((article) => ( {articles.map((article) => (

View File

@ -1,11 +1,25 @@
"use client";
import Image from "next/image"; import Image from "next/image";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { MapPin, Calendar, Users, Coins, Droplets, ChevronDown } from "lucide-react"; import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useState } from "react";
import { DatePicker } from "@/components/ui/date-picker";
import Icon from "@/components/ui/icon";
export default function Hero() { export default function Hero() {
const [location, setLocation] = useState("");
const [guests, setGuests] = useState("");
return ( return (
<section className="relative h-[600px] rounded-[24px] mx-[16px] overflow-hidden flex items-center justify-center text-center text-white"> <section className="relative h-[600px] rounded-[24px] mx-[16px] overflow-hidden flex text-white">
<Image <Image
src="/images/hero-bg.jpg" src="/images/hero-bg.jpg"
alt="Море" alt="Море"
@ -15,58 +29,109 @@ export default function Hero() {
/> />
<div className="absolute inset-0 bg-black/40" /> <div className="absolute inset-0 bg-black/40" />
<div className="relative z-10 w-full max-w-6xl mx-auto px-4"> <div className="relative z-10 w-full max-w-6xl mx-auto px-4 flex flex-col justify-between h-full py-8 pt-24">
{/* Заголовок и подзаголовок */} {/* Заголовок и подзаголовок */}
<div className="text-left mb-8"> <div className="text-left">
<h1 className="text-5xl font-bold mb-2"> <h1 className="text-5xl font-bold mb-2">Аренда яхт</h1>
Аренда яхт <h2 className="text-5xl font-bold mb-4">в Балаклаве</h2>
</h1> <p className="text-ь text-white/90">
<h2 className="text-5xl font-bold mb-4">
в Балаклаве
</h2>
<p className="text-xl text-white/90">
Подключись к морскому бризу вместе с Travel Marine Подключись к морскому бризу вместе с Travel Marine
</p> </p>
</div> </div>
{/* Поисковая форма */} {/* Поисковая форма */}
<Card className="bg-white shadow-lg"> <Card className="bg-white shadow-lg s">
<CardContent className="p-6"> <CardContent className="p-6">
{/* Основные поля поиска */} {/* Основные поля поиска */}
<div className="flex flex-col md:flex-row gap-4 mb-4"> <div className="flex flex-col md:flex-row gap-4 mb-4">
{/* Локация */} {/* Локация */}
<div className="flex-1"> <div className="flex-1">
<Button <Select
variant="outline" value={location}
className="w-full justify-start h-12 px-4 text-left" onValueChange={setLocation}
> >
<MapPin className="w-5 h-5 text-teal-600 mr-3" /> <SelectTrigger className="w-full h-12 px-4">
<span className="text-gray-700">Балаклава</span> <div className="flex items-center">
</Button> <Icon
name="map"
className="w-5 h-5 text-teal-600 mr-3"
/>
<SelectValue placeholder="Выберите локацию" />
</div>
</SelectTrigger>
<SelectContent>
<SelectItem value="balaklava">
Балаклава
</SelectItem>
<SelectItem value="sevastopol">
Севастополь
</SelectItem>
<SelectItem value="yalta">
Ялта
</SelectItem>
<SelectItem value="sudak">
Судак
</SelectItem>
<SelectItem value="kerch">
Керчь
</SelectItem>
</SelectContent>
</Select>
</div> </div>
{/* Дата и время */} {/* Дата и время */}
<div className="flex-1"> <div className="flex-1">
<Button <DatePicker />
variant="outline"
className="w-full justify-start h-12 px-4 text-left"
>
<Calendar className="w-5 h-5 text-teal-600 mr-3" />
<span className="text-gray-700">Выберите дату и время</span>
<ChevronDown className="w-4 h-4 text-gray-400 ml-auto" />
</Button>
</div> </div>
{/* Количество гостей */} {/* Количество гостей */}
<div className="flex-1"> <div className="flex-1">
<Button <Select
variant="outline" value={guests}
className="w-full justify-start h-12 px-4 text-left" onValueChange={setGuests}
> >
<Users className="w-5 h-5 text-teal-600 mr-3" /> <SelectTrigger className="w-full h-12 px-4">
<span className="text-gray-700">Сколько гостей?</span> <div className="flex items-center">
<ChevronDown className="w-4 h-4 text-gray-400 ml-auto" /> <Icon
</Button> name="people"
className="w-5 h-5 text-teal-600 mr-3"
/>
<SelectValue placeholder="Сколько гостей?" />
</div>
</SelectTrigger>
<SelectContent>
<SelectItem value="1">
1 гость
</SelectItem>
<SelectItem value="2">
2 гостя
</SelectItem>
<SelectItem value="3">
3 гостя
</SelectItem>
<SelectItem value="4">
4 гостя
</SelectItem>
<SelectItem value="5">
5 гостей
</SelectItem>
<SelectItem value="6">
6 гостей
</SelectItem>
<SelectItem value="7">
7 гостей
</SelectItem>
<SelectItem value="8">
8 гостей
</SelectItem>
<SelectItem value="9">
9 гостей
</SelectItem>
<SelectItem value="10">
10+ гостей
</SelectItem>
</SelectContent>
</Select>
</div> </div>
{/* Кнопка поиска */} {/* Кнопка поиска */}
@ -78,18 +143,30 @@ export default function Hero() {
{/* Фильтры */} {/* Фильтры */}
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
<Button variant="outline" className="h-10"> <Button variant="outline" className="h-10">
<Coins className="w-4 h-4 text-teal-600 mr-2" /> <Icon
name="money"
className="w-4 h-4 text-teal-600 mr-2"
/>
Бюджетные Бюджетные
</Button> </Button>
<Button variant="outline" className="h-10"> <Button variant="outline" className="h-10">
<Droplets className="w-4 h-4 text-teal-600 mr-2" /> <Icon
name="money"
className="w-4 h-4 text-teal-600 mr-2"
/>
Ближайшие Ближайшие
</Button> </Button>
<Button variant="outline" className="h-10"> <Button variant="outline" className="h-10">
<Coins className="w-4 h-4 text-teal-600 mr-2" /> <Icon
name="money"
className="w-4 h-4 text-teal-600 mr-2"
/>
</Button> </Button>
<Button variant="outline" className="h-10"> <Button variant="outline" className="h-10">
<Coins className="w-4 h-4 text-teal-600 mr-2" /> <Icon
name="money"
className="w-4 h-4 text-teal-600 mr-2"
/>
</Button> </Button>
</div> </div>
</CardContent> </CardContent>

View File

@ -35,15 +35,15 @@ const reviewCategories = [
export default function Reviews() { export default function Reviews() {
return ( return (
<section className="container mx-auto px-4 py-12"> <section className="container mx-auto max-w-6xl px-4 py-12">
<h1 className="text-4xl font-bold mb-4 text-black"> <h1 className="text-4xl font-bold mb-4 text-black">
Отзывы и истории аренд яхт Отзывы и истории аренд яхт
</h1> </h1>
<div className="flex gap-6 overflow-x-auto pb-4"> <div className="flex gap-12 overflow-x-auto pb-4">
{reviewCategories.map((category) => ( {reviewCategories.map((category) => (
<div <div
key={category.id} key={category.id}
className="flex-shrink-0 text-center" className="flex-shrink-0 text-center cursor-pointer"
> >
<div className="relative w-24 h-24 mx-auto mb-3"> <div className="relative w-24 h-24 mx-auto mb-3">
<Image <Image

View File

@ -15,7 +15,7 @@ import { Button } from "@/components/ui/button";
export default function Services() { export default function Services() {
return ( return (
<section className="bg-background py-12"> <section className="bg-background py-12">
<div className="container mx-auto px-4"> <div className="container max-w-6xl mx-auto px-4">
<div className="mb-8"> <div className="mb-8">
<h1 className="text-4xl font-bold mb-4 text-black"> <h1 className="text-4xl font-bold mb-4 text-black">
Морские прогулки Морские прогулки

View File

@ -3,7 +3,7 @@ import Image from 'next/image'
export default function VideoSection() { export default function VideoSection() {
return ( return (
<section className="bg-white py-16"> <section className="bg-white py-16">
<div className="container mx-auto px-4 flex flex-col lg:flex-row items-center gap-12"> <div className="container max-w-6xl mx-auto px-4 flex flex-col lg:flex-row items-center gap-12">
{/* Левая колонка с текстом */} {/* Левая колонка с текстом */}
<div className="lg:w-1/2"> <div className="lg:w-1/2">
<h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-6 leading-tight"> <h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-6 leading-tight">

View File

@ -1,126 +1,123 @@
import { import { Card, CardContent, CardHeader } from "@/components/ui/card";
Card,
CardContent,
CardHeader,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import Image from "next/image"; import Image from "next/image";
import Icon from "@/components/ui/icon";
const yachts = [ const yachts = [
{ {
name: "Яхта", name: "Яхта",
length: "12 метров", length: "12 метров",
price: "от 12 500 Р / час", price: "от 12 500 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "Быстрая бронь", badge: "Быстрая бронь",
badgeIcon: "⚡" badgeIcon: "⚡",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "14 метров", length: "14 метров",
price: "от 26 400 Р / час", price: "от 26 400 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "22 метра", length: "22 метра",
price: "от 48 000 Р / час", price: "от 48 000 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "13.6 метров", length: "13.6 метров",
price: "от 17 400 Р / час", price: "от 17 400 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "13 метров", length: "13 метров",
price: "от 14 400 Р / час", price: "от 14 400 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "12 метров", length: "12 метров",
price: "от 12 480 Р / час", price: "от 12 480 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "14 метров", length: "14 метров",
price: "от 18 000 Р / час", price: "от 18 000 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "19 метров", length: "19 метров",
price: "от 25 920 Р / час", price: "от 25 920 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "20 метров", length: "20 метров",
price: "от 32 400 Р / час", price: "от 32 400 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "8 метров", length: "8 метров",
price: "от 9 960 Р / час", price: "от 9 960 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "13 метров", length: "13 метров",
price: "от 18 000 Р / час", price: "от 18 000 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
{ {
name: "Яхта", name: "Яхта",
length: "11.58 метров", length: "11.58 метров",
price: "от 14 400 Р / час", price: "от 14 400 Р / час",
feet: "+7 Футов", feet: "7 Футов",
img: "/images/yacht.jpg", img: "/images/yacht.jpg",
badge: "По запросу", badge: "По запросу",
badgeIcon: "🔄" badgeIcon: "🔄",
}, },
]; ];
export default function YachtGrid() { export default function YachtGrid() {
return ( return (
<div className="min-h-screen text-white"> <div className="min-h-screen text-white">
<div className="container mx-auto px-4 py-12"> <div className="container max-w-6xl mx-auto px-4 py-12">
{/* Header Section */} {/* Header Section */}
<div className="mb-12"> <div className="mb-12">
<h1 className="text-4xl font-bold mb-4 text-black"> <h1 className="text-4xl font-bold mb-4 text-black">
@ -130,14 +127,19 @@ export default function YachtGrid() {
Онлайн бронирование яхт Онлайн бронирование яхт
</h2> </h2>
<p className="text-gray-700 max-w-3xl leading-relaxed"> <p className="text-gray-700 max-w-3xl leading-relaxed">
Каталог лучших яхт Балаклавы разных ценовых сегментах. Проверенные лодки с лицензией на перевозки, опытные капитаны. Выбирайте удобную дату, время и бронируйте. Каталог лучших яхт Балаклавы разных ценовых сегментах.
Проверенные лодки с лицензией на перевозки, опытные
капитаны. Выбирайте удобную дату, время и бронируйте.
</p> </p>
</div> </div>
{/* Yacht Grid */} {/* Yacht Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
{yachts.map((yacht, idx) => ( {yachts.map((yacht, idx) => (
<Card key={idx} className="overflow-hidden bg-white text-gray-900 shadow-lg"> <Card
key={idx}
className="overflow-hidden bg-white text-gray-900 shadow-lg"
>
<CardHeader className="p-0 relative"> <CardHeader className="p-0 relative">
<div className="relative"> <div className="relative">
<Image <Image
@ -149,8 +151,15 @@ export default function YachtGrid() {
/> />
{/* Badge Overlay */} {/* Badge Overlay */}
<div className="absolute top-3 left-3"> <div className="absolute top-3 left-3">
<div className="bg-gray-800 text-white px-3 py-1 rounded-lg text-sm flex items-center gap-1"> <div className="flex items-center justify-center bg-black bg-opacity-10 text-white px-3 py-1 rounded-lg text-sm flex items-center gap-1">
<span>{yacht.badgeIcon}</span> <Icon
size={16}
name={
idx === 0
? "logo"
: "restart"
}
/>
<span>{yacht.badge}</span> <span>{yacht.badge}</span>
</div> </div>
</div> </div>
@ -158,18 +167,28 @@ export default function YachtGrid() {
</CardHeader> </CardHeader>
<CardContent className="p-4"> <CardContent className="p-4">
<div className="flex justify-between items-start mb-2"> <div className="flex justify-between items-start mb-2">
<h3 className="font-bold text-lg">{yacht.name}</h3> <h3 className="font-bold text-lg">
{yacht.name}
</h3>
<div className="text-right"> <div className="text-right">
<p className="font-bold text-lg">{yacht.price}</p> <p className="font-bold text-lg">
{yacht.price}
</p>
</div> </div>
</div> </div>
<div className="flex items-center justify-between text-gray-600"> <div className="flex items-center justify-between text-gray-600">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span></span> <Icon
size={16}
name="width"
/>
<span>{yacht.length}</span> <span>{yacht.length}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span></span> <Icon
size={16}
name="anchor"
/>
<span>{yacht.feet}</span> <span>{yacht.feet}</span>
</div> </div>
</div> </div>

View File

@ -7,7 +7,7 @@ import Footer from "@/components/layout/Footer";
const inter = Inter({ subsets: ["latin", "cyrillic"] }); // Поддержка русского const inter = Inter({ subsets: ["latin", "cyrillic"] }); // Поддержка русского
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Marine Travel - Аренда яхт в Балаклаве", title: "Travel Marine - Аренда яхт в Балаклаве",
description: "Прокат яхт и морские прогулки в Балаклаве", description: "Прокат яхт и морские прогулки в Балаклаве",
}; };

View File

@ -19,15 +19,12 @@ export default function Header() {
{ href: "/catalog", label: "Каталог" }, { href: "/catalog", label: "Каталог" },
{ href: "/yachts", label: "Яхты" }, { href: "/yachts", label: "Яхты" },
{ href: "/services", label: "Услуги" }, { href: "/services", label: "Услуги" },
{ href: "/destinations", label: "Маршруты" },
{ href: "/about", label: "О нас" },
{ href: "/contacts", label: "Контакты" },
]; ];
return ( return (
<header className="sticky top-0 z-50 bg-white/95 backdrop-blur-sm border-b border-gray-100"> <header className="sticky top-0 z-50 bg-white/95 backdrop-blur-sm border-b border-gray-100">
<div className="container mx-auto px-4 py-4"> <div className="w-full max-w-6xl mx-auto">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center px-4 sm:px-6 lg:px-8 py-4">
{/* Логотип */} {/* Логотип */}
<Link href="/" className="flex-shrink-0"> <Link href="/" className="flex-shrink-0">
<Image <Image
@ -59,7 +56,9 @@ export default function Header() {
<div className="hidden lg:flex items-center space-x-4"> <div className="hidden lg:flex items-center space-x-4">
<div className="flex items-center space-x-2 text-gray-700"> <div className="flex items-center space-x-2 text-gray-700">
<Phone className="h-4 w-4" /> <Phone className="h-4 w-4" />
<span className="font-semibold">+7 (123) 456-78-90</span> <span className="font-semibold">
+7 (978) 744-89-00
</span>
</div> </div>
<Button className="bg-primary hover:bg-primary/90 text-white"> <Button className="bg-primary hover:bg-primary/90 text-white">
Заказать звонок Заказать звонок
@ -71,7 +70,9 @@ export default function Header() {
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} onClick={() =>
setIsMobileMenuOpen(!isMobileMenuOpen)
}
className="text-gray-700" className="text-gray-700"
> >
{isMobileMenuOpen ? ( {isMobileMenuOpen ? (
@ -100,7 +101,9 @@ export default function Header() {
<div className="pt-4 border-t border-gray-100"> <div className="pt-4 border-t border-gray-100">
<div className="flex items-center space-x-2 text-gray-700 mb-4"> <div className="flex items-center space-x-2 text-gray-700 mb-4">
<Phone className="h-4 w-4" /> <Phone className="h-4 w-4" />
<span className="font-semibold">+7 (123) 456-78-90</span> <span className="font-semibold">
+7 (123) 456-78-90
</span>
</div> </div>
<Button className="w-full bg-primary hover:bg-primary/90 text-white"> <Button className="w-full bg-primary hover:bg-primary/90 text-white">
Заказать звонок Заказать звонок

View File

@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{ {
variants: { variants: {
variant: { variant: {
@ -22,8 +22,8 @@ const buttonVariants = cva(
}, },
size: { size: {
default: "h-9 px-4 py-2", default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs", sm: "h-8 rounded-full px-3 text-xs",
lg: "h-10 rounded-md px-8", lg: "h-10 rounded-full px-8",
icon: "h-9 w-9", icon: "h-9 w-9",
}, },
}, },

View File

@ -0,0 +1,213 @@
"use client"
import * as React from "react"
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from "lucide-react"
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
import { cn } from "@/lib/utils"
import { Button, buttonVariants } from "@/components/ui/button"
function Calendar({
className,
classNames,
showOutsideDays = true,
captionLayout = "label",
buttonVariant = "ghost",
formatters,
components,
...props
}: React.ComponentProps<typeof DayPicker> & {
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
}) {
const defaultClassNames = getDefaultClassNames()
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn(
"bg-background group/calendar p-3 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
className
)}
captionLayout={captionLayout}
formatters={{
formatMonthDropdown: (date) =>
date.toLocaleString("default", { month: "short" }),
...formatters,
}}
classNames={{
root: cn("w-fit", defaultClassNames.root),
months: cn(
"relative flex flex-col gap-4 md:flex-row",
defaultClassNames.months
),
month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
nav: cn(
"absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
defaultClassNames.nav
),
button_previous: cn(
buttonVariants({ variant: buttonVariant }),
"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",
defaultClassNames.button_previous
),
button_next: cn(
buttonVariants({ variant: buttonVariant }),
"h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",
defaultClassNames.button_next
),
month_caption: cn(
"flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]",
defaultClassNames.month_caption
),
dropdowns: cn(
"flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium",
defaultClassNames.dropdowns
),
dropdown_root: cn(
"has-focus:border-ring border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border",
defaultClassNames.dropdown_root
),
dropdown: cn(
"bg-popover absolute inset-0 opacity-0",
defaultClassNames.dropdown
),
caption_label: cn(
"select-none font-medium",
captionLayout === "label"
? "text-sm"
: "[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5",
defaultClassNames.caption_label
),
table: "w-full border-collapse",
weekdays: cn("flex", defaultClassNames.weekdays),
weekday: cn(
"text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal",
defaultClassNames.weekday
),
week: cn("mt-2 flex w-full", defaultClassNames.week),
week_number_header: cn(
"w-[--cell-size] select-none",
defaultClassNames.week_number_header
),
week_number: cn(
"text-muted-foreground select-none text-[0.8rem]",
defaultClassNames.week_number
),
day: cn(
"group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md",
defaultClassNames.day
),
range_start: cn(
"bg-accent rounded-l-md",
defaultClassNames.range_start
),
range_middle: cn("rounded-none", defaultClassNames.range_middle),
range_end: cn("bg-accent rounded-r-md", defaultClassNames.range_end),
today: cn(
"bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
defaultClassNames.today
),
outside: cn(
"text-muted-foreground aria-selected:text-muted-foreground",
defaultClassNames.outside
),
disabled: cn(
"text-muted-foreground opacity-50",
defaultClassNames.disabled
),
hidden: cn("invisible", defaultClassNames.hidden),
...classNames,
}}
components={{
Root: ({ className, rootRef, ...props }) => {
return (
<div
data-slot="calendar"
ref={rootRef}
className={cn(className)}
{...props}
/>
)
},
Chevron: ({ className, orientation, ...props }) => {
if (orientation === "left") {
return (
<ChevronLeftIcon className={cn("size-4", className)} {...props} />
)
}
if (orientation === "right") {
return (
<ChevronRightIcon
className={cn("size-4", className)}
{...props}
/>
)
}
return (
<ChevronDownIcon className={cn("size-4", className)} {...props} />
)
},
DayButton: CalendarDayButton,
WeekNumber: ({ children, ...props }) => {
return (
<td {...props}>
<div className="flex size-[--cell-size] items-center justify-center text-center">
{children}
</div>
</td>
)
},
...components,
}}
{...props}
/>
)
}
function CalendarDayButton({
className,
day,
modifiers,
...props
}: React.ComponentProps<typeof DayButton>) {
const defaultClassNames = getDefaultClassNames()
const ref = React.useRef<HTMLButtonElement>(null)
React.useEffect(() => {
if (modifiers.focused) ref.current?.focus()
}, [modifiers.focused])
return (
<Button
ref={ref}
variant="ghost"
size="icon"
data-day={day.date.toLocaleDateString()}
data-selected-single={
modifiers.selected &&
!modifiers.range_start &&
!modifiers.range_end &&
!modifiers.range_middle
}
data-range-start={modifiers.range_start}
data-range-end={modifiers.range_end}
data-range-middle={modifiers.range_middle}
className={cn(
"data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 flex aspect-square h-auto w-full min-w-[--cell-size] flex-col gap-1 font-normal leading-none data-[range-end=true]:rounded-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] [&>span]:text-xs [&>span]:opacity-70",
defaultClassNames.day,
className
)}
{...props}
/>
)
}
export { Calendar, CalendarDayButton }

View File

@ -0,0 +1,42 @@
"use client";
import * as React from "react";
import { format } from "date-fns";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import Icon from "./icon";
export function DatePicker() {
const [date, setDate] = React.useState<Date>();
return (
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
data-empty={!date}
className="data-[empty=true]:text-muted-foreground w-full h-12 justify-start text-left font-normal"
>
<Icon
name="calendar"
className="w-4 h-4 text-teal-600 mr-2"
/>
{date ? (
format(date, "dd.MM.yyyy")
) : (
<span>Выберите дату</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar mode="single" selected={date} onSelect={setDate} />
</PopoverContent>
</Popover>
);
}

View File

@ -0,0 +1,93 @@
import React, { forwardRef, memo } from "react";
import { IconProps } from "../../types/icon";
// Импорт SVG иконок как React компонентов
import CalendarIcon from "../../../public/images/icons/calendar.svg";
import MapIcon from "../../../public/images/icons/map.svg";
import MoneyIcon from "../../../public/images/icons/money.svg";
import PeopleIcon from "../../../public/images/icons/people.svg";
import LogoIcon from "../../../public/images/icons/logo.svg";
import RestartIcon from "../../../public/images/icons/restart.svg";
import AnchorIcon from "../../../public/images/icons/anchor.svg";
import WidthIcon from "../../../public/images/icons/width.svg";
// Объект с иконками для удобного доступа
const icons = {
calendar: CalendarIcon,
map: MapIcon,
money: MoneyIcon,
people: PeopleIcon,
logo: LogoIcon,
restart: RestartIcon,
anchor: AnchorIcon,
width: WidthIcon,
};
// Компонент Icon оптимизированный для Next.js
export const Icon = memo(
forwardRef<SVGSVGElement, IconProps>(
({ name, className = "", size = 24, color, ...props }, ref) => {
const IconComponent = icons[name];
if (!IconComponent) {
console.warn(`Icon "${name}" not found`);
return null;
}
const style = {
width: typeof size === "number" ? `${size}px` : size,
height: typeof size === "number" ? `${size}px` : size,
...(color && { fill: color }),
};
// Проверяем, что IconComponent является функцией/компонентом
// if (typeof IconComponent !== "function") {
// console.warn(`Icon "${name}" is not a valid React component`);
// return null;
// }
// Создаем элемент с правильными пропсами
return React.createElement(IconComponent, {
ref,
className,
style,
...props,
});
}
)
);
Icon.displayName = "Icon";
// Экспорт по умолчанию для совместимости
export default Icon;
/**
* Компонент Icon для отображения SVG иконок в Next.js
*
* Особенности:
* - Оптимизирован для Next.js с использованием SVGR
* - Поддержка forwardRef для доступа к DOM элементу
* - Мемоизация для улучшения производительности
* - Поддержка всех стандартных SVG пропсов
*
* Примеры использования:
* ```tsx
* // Базовое использование
* <Icon name="calendar" size={32} />
*
* // С кастомными стилями
* <Icon name="map" size="24px" color="#3B82F6" className="hover:opacity-80" />
*
* // С дополнительными SVG пропсами
* <Icon name="money" size={20} color="green" onClick={handleClick} />
*
* // С ref для прямого доступа к элементу
* const iconRef = useRef<SVGSVGElement>(null);
* <Icon ref={iconRef} name="people" size={28} />
*
* // Новые иконки
* <Icon name="logo" size={40} />
* <Icon name="restart" size={24} color="#6B7280" />
* ```
*/

View File

@ -0,0 +1,33 @@
"use client"
import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"
import { cn } from "@/lib/utils"
const Popover = PopoverPrimitive.Root
const PopoverTrigger = PopoverPrimitive.Trigger
const PopoverAnchor = PopoverPrimitive.Anchor
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }

View File

@ -0,0 +1,159 @@
"use client"
import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { Check, ChevronDown, ChevronUp } from "lucide-react"
import { cn } from "@/lib/utils"
const Select = SelectPrimitive.Root
const SelectGroup = SelectPrimitive.Group
const SelectValue = SelectPrimitive.Value
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-full border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<ChevronUp className="h-4 w-4" />
</SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
))
SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
}

12
src/types/icon.ts Normal file
View File

@ -0,0 +1,12 @@
import { SVGProps } from 'react';
export type IconName = 'calendar' | 'map' | 'money' | 'people' | 'logo' | 'restart' | 'anchor' | 'width';
export interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'name' | 'preserveAspectRatio'> {
name: IconName;
className?: string;
size?: number | string;
color?: string;
preserveAspectRatio?: boolean;
maxSize?: number | string;
}

5
src/types/svg.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare module '*.svg' {
import React from 'react';
const SVG: React.ForwardRefExoticComponent<React.SVGProps<SVGSVGElement> & React.RefAttributes<SVGSVGElement>>;
export default SVG;
}

View File

@ -22,6 +22,6 @@
"@/*": ["./src/*"] "@/*": ["./src/*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/types/**/*.d.ts"],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }