diff --git a/bun.lock b/bun.lock index ef00142..6493158 100644 --- a/bun.lock +++ b/bun.lock @@ -4,14 +4,20 @@ "": { "name": "dyagilev", "dependencies": { + "@number-flow/react": "^0.6.0", + "clsx": "^2.1.1", + "motion": "^12.38.0", "next": "16.2.4", "react": "19.2.4", "react-dom": "19.2.4", + "react-pageflip": "^2.0.3", + "zustand": "^5.0.13", }, "devDependencies": { "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "autoprefixer": "^10.5.0", "eslint": "^9", "eslint-config-next": "16.2.4", "tailwindcss": "3", @@ -178,6 +184,8 @@ "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], + "@number-flow/react": ["@number-flow/react@0.6.0", "", { "dependencies": { "esm-env": "^1.1.4", "number-flow": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-77Yfc9+zkV2UDSP8phhZzxJGuwxi/Tt1TikmipL+1r3e9GFKEYDZ1XwInj67NoSt3OnOB0KLvvcl3lfPZgBHVQ=="], + "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], @@ -292,6 +300,8 @@ "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], + "autoprefixer": ["autoprefixer@10.5.0", "", { "dependencies": { "browserslist": "^4.28.2", "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong=="], + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], "axe-core": ["axe-core@4.11.4", "", {}, "sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA=="], @@ -328,6 +338,8 @@ "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], @@ -416,6 +428,8 @@ "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], @@ -450,6 +464,10 @@ "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], + + "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], @@ -612,6 +630,12 @@ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="], + + "motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], + + "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], @@ -630,6 +654,8 @@ "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + "number-flow": ["number-flow@0.6.0", "", { "dependencies": { "esm-env": "^1.1.4" } }, "sha512-K8flNq2Wqus53vjp/btVo3qXFkagF8dIdYavreBfE7hlvFFG/b1HMGEH6nZL+mlrJ+4lbLP9OmPv3t2rmRkpSQ=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], @@ -656,6 +682,8 @@ "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + "page-flip": ["page-flip@2.0.7", "", {}, "sha512-96lQFUUz7r/LZzEUZJ3yBIMEKU9+m8HMFDzTvTdD6P7Ag/wXINjp9n0W7b4wanwnDbQETo4uNUoL3zMqpFxwGA=="], + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], @@ -702,6 +730,8 @@ "react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + "react-pageflip": ["react-pageflip@2.0.3", "", { "dependencies": { "page-flip": "latest" } }, "sha512-k81mHhRvUM52y8jyzTCh5t4O0lepkLhp+XGSUzq2C3uD+iW99Cv0jfRlqFCjZbD5N3jKkIFr7/3giucoXKDP3Q=="], + "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], @@ -844,6 +874,8 @@ "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], + "zustand": ["zustand@5.0.13", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ=="], + "@babel/core/json5": ["json5@2.2.3", "", { "bin": "lib/cli.js" }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], diff --git a/next.config.ts b/next.config.ts index e9ffa30..b1a50db 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + devIndicators: false }; export default nextConfig; diff --git a/package.json b/package.json index 610f7bb..ac5023e 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,14 @@ "lint": "eslint" }, "dependencies": { + "@number-flow/react": "^0.6.0", + "clsx": "^2.1.1", + "motion": "^12.38.0", "next": "16.2.4", "react": "19.2.4", - "react-dom": "19.2.4" + "react-dom": "19.2.4", + "react-pageflip": "^2.0.3", + "zustand": "^5.0.13" }, "devDependencies": { "@types/node": "^20", diff --git a/public/file.svg b/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/img/bg/building.png b/public/img/bg/building.png new file mode 100644 index 0000000..e403656 Binary files /dev/null and b/public/img/bg/building.png differ diff --git a/public/img/bg/sky.png b/public/img/bg/sky.png new file mode 100644 index 0000000..7b38736 Binary files /dev/null and b/public/img/bg/sky.png differ diff --git a/public/img/mocks/bookPage.png b/public/img/mocks/bookPage.png new file mode 100644 index 0000000..d1d427d Binary files /dev/null and b/public/img/mocks/bookPage.png differ diff --git a/public/img/mocks/building.png b/public/img/mocks/building.png new file mode 100644 index 0000000..16bf084 Binary files /dev/null and b/public/img/mocks/building.png differ diff --git a/public/img/premiere/1.png b/public/img/premiere/1.png new file mode 100644 index 0000000..1793bfd Binary files /dev/null and b/public/img/premiere/1.png differ diff --git a/public/img/premiere/2.png b/public/img/premiere/2.png new file mode 100644 index 0000000..ad2b045 Binary files /dev/null and b/public/img/premiere/2.png differ diff --git a/public/img/premiere/3.png b/public/img/premiere/3.png new file mode 100644 index 0000000..2918690 Binary files /dev/null and b/public/img/premiere/3.png differ diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/window.svg b/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/favicon.ico b/src/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/src/app/favicon.ico and /dev/null differ diff --git a/src/app/globals.css b/src/app/globals.css index 80dc0f8..5ef4896 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -17,5 +17,55 @@ body { background: var(--background); color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; +} + +@layer utilities { + /* Typography */ + .line-xl { + @apply lg:text-[7.778vw] md:text-[14.583vw] text-[31.111vw] leading-[100%] tracking-[-2%]; + } + .title-l { + @apply lg:text-[2.778vw] md:text-[5.208vw] text-[11.111vw] leading-[120%] tracking-[-2%]; + } + .title-m { + @apply lg:text-[1.389vw] md:text-[2.604vw] text-[5.556vw] leading-[110%] tracking-[-2%]; + } + .title-s { + @apply lg:text-[1.25vw] md:text-[2.344vw] text-[5vw] leading-[110%] tracking-[-2%]; + } + .text-m { + @apply lg:text-[1.111vw] md:text-[2.083vw] text-[4.444vw] leading-[120%] tracking-[-2%]; + } + .text-s { + @apply lg:text-[0.972vw] md:text-[1.875vw] text-[3.889vw] leading-[110%] tracking-[-2%]; + } + .text-xs { + @apply lg:text-[0.833vw] md:text-[1.563vw] text-[3.333vw] leading-[110%] tracking-[-2%]; + } + .button-l { + @apply lg:text-[0.972vw] md:text-[1.875vw] text-[3.889vw] leading-[115%] tracking-[-2%]; + } + .button-m { + @apply lg:text-[0.972vw] md:text-[1.875vw] text-[3.889vw] leading-[110%] tracking-[-2%]; + } + .button-s { + @apply lg:text-[0.833vw] md:text-[1.563vw] text-[3.333vw] leading-[110%] tracking-[-2%]; + } + .caption-m{ + @apply lg:text-[0.833vw] md:text-[1.563vw] text-[3.333vw] leading-[120%] tracking-[-2%]; + } + .caption-s{ + @apply lg:text-[0.694vw] md:text-[1.302vw] text-[2.778vw] leading-[120%] tracking-[-2%]; + } + + /* Gradients */ + .gradient-1 { + @apply bg-[linear-gradient(to_right,#3D514B,#F051A0_32%,#CF8D42_71%,#72F9B3)]; + } + .gradient-2 { + @apply bg-[linear-gradient(to_right,#CF8D42_4%,#3D514B_36%,#72F9B3_67%,#F051A0)]; + } + .gradient-3 { + @apply bg-[linear-gradient(to_right,#CF8D42_4%,#72F9B3_32%,#F051A0_58%,#3D514B)]; + } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 976eb90..381ecc9 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,20 +1,15 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Manrope } from "next/font/google"; import "./globals.css"; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", +const manrope = Manrope({ subsets: ["latin"], + weight: ["200", "400", "600"], }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Дягилев", + description: "Авторский дом Дягилев", }; export default function RootLayout({ @@ -25,9 +20,9 @@ export default function RootLayout({ return ( - {children} + {children} ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 3f36f7c..9e7da8f 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,65 +1,27 @@ -import Image from "next/image"; +"use client"; -export default function Home() { +import LoadingScreen from "@/components/LoadingScreen"; +import Hero from "@/components/pages/Hero"; +import Header from "@/components/ui/Header"; +import MenuSidebar from "@/components/ui/MenuSidebar"; +import Overview from "@/components/pages/Overview"; +import ScreenOverlay from "@/components/ui/ScreenOverlay"; +import Premiere from "@/components/pages/Premiere"; + +export default function Root() { return ( -
-
- Next.js logo -
-

- To get started, edit the page.tsx file. -

-

- Looking for a starting point or more instructions? Head over to{" "} - - Templates - {" "} - or the{" "} - - Learning - {" "} - center. -

-
-
- - Vercel logomark - Deploy Now - - - Documentation - -
-
-
+
+ + + {/* Основной UI */} +
+ + + + {/* Страницы */} + + + +
); } diff --git a/src/components/LoadingScreen.tsx b/src/components/LoadingScreen.tsx new file mode 100644 index 0000000..b576cb4 --- /dev/null +++ b/src/components/LoadingScreen.tsx @@ -0,0 +1,57 @@ +import { useEffect, useState } from "react"; +import LogoHorizontal from "./icons/LogoHorizontal"; +import Logo from "./icons/Logo"; +import NumberFlow from "@number-flow/react"; +import { AnimatePresence, motion } from "motion/react"; +import { useAppStateStore } from "@/stores/useAppStateStore"; + +export default function LoadingScreen() { + const setIsLoading = useAppStateStore((state) => state.setIsLoading); + const isLoading = useAppStateStore((state) => state.isLoading); + const [progress, setProgress] = useState(1); + + useEffect(() => { + setIsLoading(true); + const timeout = setTimeout(() => { + setIsLoading(false); + }, 1000); + + return () => { + clearTimeout(timeout); + setIsLoading(false); + }; + }, [progress, setIsLoading]); + + return ( + + {isLoading && ( + +
+ +
+ +
+ +
+ +
+ +
+
+ )} +
+ ); +} diff --git a/src/components/icons/Add.tsx b/src/components/icons/Add.tsx new file mode 100644 index 0000000..24e3f31 --- /dev/null +++ b/src/components/icons/Add.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Add = (props: React.SVGProps) => ( + + + +); +export default Add; diff --git a/src/components/icons/Arrow.tsx b/src/components/icons/Arrow.tsx new file mode 100644 index 0000000..f9b3944 --- /dev/null +++ b/src/components/icons/Arrow.tsx @@ -0,0 +1,103 @@ +import * as React from "react"; +type ArrowProps = React.SVGProps & { + direction: "left" | "right" | "up" | "down" | "more" | "less"; +}; + +const Arrow: React.FC = ({ direction, ...props }) => { + switch (direction) { + case "left": + return ( + + + + ); + case "right": + return ( + + + + ); + case "up": + return ( + + + + ); + case "down": + return ( + + + + ); + case "more": + return ( + + + + ); + case "less": + return ( + + + + ); + } +}; + +export default Arrow; diff --git a/src/components/icons/Baby.tsx b/src/components/icons/Baby.tsx new file mode 100644 index 0000000..6e9bd2c --- /dev/null +++ b/src/components/icons/Baby.tsx @@ -0,0 +1,19 @@ +import * as React from "react"; +const Baby = (props: React.SVGProps) => ( + + + + +); +export default Baby; diff --git a/src/components/icons/Basket.tsx b/src/components/icons/Basket.tsx new file mode 100644 index 0000000..fcffca5 --- /dev/null +++ b/src/components/icons/Basket.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Basket = (props: React.SVGProps) => ( + + + +); +export default Basket; diff --git a/src/components/icons/Beauty.tsx b/src/components/icons/Beauty.tsx new file mode 100644 index 0000000..aa2c483 --- /dev/null +++ b/src/components/icons/Beauty.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Beauty = (props: React.SVGProps) => ( + + + +); +export default Beauty; diff --git a/src/components/icons/Bicycle.tsx b/src/components/icons/Bicycle.tsx new file mode 100644 index 0000000..1f855d5 --- /dev/null +++ b/src/components/icons/Bicycle.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Bicycle = (props: React.SVGProps) => ( + + + +); +export default Bicycle; diff --git a/src/components/icons/Bus.tsx b/src/components/icons/Bus.tsx new file mode 100644 index 0000000..3ceb162 --- /dev/null +++ b/src/components/icons/Bus.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Bus = (props: React.SVGProps) => ( + + + +); +export default Bus; diff --git a/src/components/icons/BusStop.tsx b/src/components/icons/BusStop.tsx new file mode 100644 index 0000000..a794b02 --- /dev/null +++ b/src/components/icons/BusStop.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const BusStop = (props: React.SVGProps) => ( + + + +); +export default BusStop; diff --git a/src/components/icons/Car.tsx b/src/components/icons/Car.tsx new file mode 100644 index 0000000..4ac9790 --- /dev/null +++ b/src/components/icons/Car.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Car = (props: React.SVGProps) => ( + + + +); +export default Car; diff --git a/src/components/icons/Cart.tsx b/src/components/icons/Cart.tsx new file mode 100644 index 0000000..4ed37d3 --- /dev/null +++ b/src/components/icons/Cart.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Cart = (props: React.SVGProps) => ( + + + +); +export default Cart; diff --git a/src/components/icons/Check.tsx b/src/components/icons/Check.tsx new file mode 100644 index 0000000..22d6306 --- /dev/null +++ b/src/components/icons/Check.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Check = (props: React.SVGProps) => ( + + + +); +export default Check; diff --git a/src/components/icons/ChevronDown.tsx b/src/components/icons/ChevronDown.tsx new file mode 100644 index 0000000..2d16bfa --- /dev/null +++ b/src/components/icons/ChevronDown.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const ChevronDown = (props: React.SVGProps) => ( + + + +); +export default ChevronDown; diff --git a/src/components/icons/ChevronRight.tsx b/src/components/icons/ChevronRight.tsx new file mode 100644 index 0000000..e736c8c --- /dev/null +++ b/src/components/icons/ChevronRight.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const ChevronRight = (props: React.SVGProps) => ( + + + +); +export default ChevronRight; diff --git a/src/components/icons/ChevronUp.tsx b/src/components/icons/ChevronUp.tsx new file mode 100644 index 0000000..ed66675 --- /dev/null +++ b/src/components/icons/ChevronUp.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const ChevronUp = (props: React.SVGProps) => ( + + + +); +export default ChevronUp; diff --git a/src/components/icons/Chevronleft.tsx b/src/components/icons/Chevronleft.tsx new file mode 100644 index 0000000..e164176 --- /dev/null +++ b/src/components/icons/Chevronleft.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Chevronleft = (props: React.SVGProps) => ( + + + +); +export default Chevronleft; diff --git a/src/components/icons/Coffee.tsx b/src/components/icons/Coffee.tsx new file mode 100644 index 0000000..656cd06 --- /dev/null +++ b/src/components/icons/Coffee.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Coffee = (props: React.SVGProps) => ( + + + +); +export default Coffee; diff --git a/src/components/icons/Cookie.tsx b/src/components/icons/Cookie.tsx new file mode 100644 index 0000000..a81f8ca --- /dev/null +++ b/src/components/icons/Cookie.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Cookie = (props: React.SVGProps) => ( + + + +); +export default Cookie; diff --git a/src/components/icons/Datacentre.tsx b/src/components/icons/Datacentre.tsx new file mode 100644 index 0000000..313db29 --- /dev/null +++ b/src/components/icons/Datacentre.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Datacentre = (props: React.SVGProps) => ( + + + +); +export default Datacentre; diff --git a/src/components/icons/Dentist.tsx b/src/components/icons/Dentist.tsx new file mode 100644 index 0000000..9ba224b --- /dev/null +++ b/src/components/icons/Dentist.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Dentist = (props: React.SVGProps) => ( + + + +); +export default Dentist; diff --git a/src/components/icons/Dot.tsx b/src/components/icons/Dot.tsx new file mode 100644 index 0000000..498810e --- /dev/null +++ b/src/components/icons/Dot.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Dot = (props: React.SVGProps) => ( + + + +); +export default Dot; diff --git a/src/components/icons/Dots.tsx b/src/components/icons/Dots.tsx new file mode 100644 index 0000000..604947e --- /dev/null +++ b/src/components/icons/Dots.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Dots = (props: React.SVGProps) => ( + + + +); +export default Dots; diff --git a/src/components/icons/Education.tsx b/src/components/icons/Education.tsx new file mode 100644 index 0000000..d5eb759 --- /dev/null +++ b/src/components/icons/Education.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Education = (props: React.SVGProps) => ( + + + +); +export default Education; diff --git a/src/components/icons/Food.tsx b/src/components/icons/Food.tsx new file mode 100644 index 0000000..6e77b24 --- /dev/null +++ b/src/components/icons/Food.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Food = (props: React.SVGProps) => ( + + + +); +export default Food; diff --git a/src/components/icons/Groceries.tsx b/src/components/icons/Groceries.tsx new file mode 100644 index 0000000..7c3d460 --- /dev/null +++ b/src/components/icons/Groceries.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Groceries = (props: React.SVGProps) => ( + + + +); +export default Groceries; diff --git a/src/components/icons/Gym.tsx b/src/components/icons/Gym.tsx new file mode 100644 index 0000000..d49173d --- /dev/null +++ b/src/components/icons/Gym.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Gym = (props: React.SVGProps) => ( + + + +); +export default Gym; diff --git a/src/components/icons/Health.tsx b/src/components/icons/Health.tsx new file mode 100644 index 0000000..71a3fef --- /dev/null +++ b/src/components/icons/Health.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Health = (props: React.SVGProps) => ( + + + +); +export default Health; diff --git a/src/components/icons/HeartFilled.tsx b/src/components/icons/HeartFilled.tsx new file mode 100644 index 0000000..72e0b01 --- /dev/null +++ b/src/components/icons/HeartFilled.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const HeartFilled = (props: React.SVGProps) => ( + + + +); +export default HeartFilled; diff --git a/src/components/icons/Kindergarten.tsx b/src/components/icons/Kindergarten.tsx new file mode 100644 index 0000000..2f6ccc8 --- /dev/null +++ b/src/components/icons/Kindergarten.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Kindergarten = (props: React.SVGProps) => ( + + + +); +export default Kindergarten; diff --git a/src/components/icons/Logo.tsx b/src/components/icons/Logo.tsx new file mode 100644 index 0000000..e95b674 --- /dev/null +++ b/src/components/icons/Logo.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Logo = (props: React.SVGProps) => ( + + + +); +export default Logo; diff --git a/src/components/icons/LogoHorizontal.tsx b/src/components/icons/LogoHorizontal.tsx new file mode 100644 index 0000000..fa344e9 --- /dev/null +++ b/src/components/icons/LogoHorizontal.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const LogoHorizontal = (props: React.SVGProps) => ( + + + +); +export default LogoHorizontal; diff --git a/src/components/icons/Mask.tsx b/src/components/icons/Mask.tsx new file mode 100644 index 0000000..df336f3 --- /dev/null +++ b/src/components/icons/Mask.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Mask = (props: React.SVGProps) => ( + + + +); +export default Mask; diff --git a/src/components/icons/Menu.tsx b/src/components/icons/Menu.tsx new file mode 100644 index 0000000..691bb13 --- /dev/null +++ b/src/components/icons/Menu.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Menu = (props: React.SVGProps) => ( + + + +); +export default Menu; diff --git a/src/components/icons/MenuClosed.tsx b/src/components/icons/MenuClosed.tsx new file mode 100644 index 0000000..0386f11 --- /dev/null +++ b/src/components/icons/MenuClosed.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +const MenuClosed = (props: React.SVGProps) => ( + + + +); +export default MenuClosed; diff --git a/src/components/icons/Museum.tsx b/src/components/icons/Museum.tsx new file mode 100644 index 0000000..0e198ad --- /dev/null +++ b/src/components/icons/Museum.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Museum = (props: React.SVGProps) => ( + + + +); +export default Museum; diff --git a/src/components/icons/Park.tsx b/src/components/icons/Park.tsx new file mode 100644 index 0000000..1a7882d --- /dev/null +++ b/src/components/icons/Park.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Park = (props: React.SVGProps) => ( + + + +); +export default Park; diff --git a/src/components/icons/PingPong.tsx b/src/components/icons/PingPong.tsx new file mode 100644 index 0000000..2d18a14 --- /dev/null +++ b/src/components/icons/PingPong.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const PingPong = (props: React.SVGProps) => ( + + + +); +export default PingPong; diff --git a/src/components/icons/Play.tsx b/src/components/icons/Play.tsx new file mode 100644 index 0000000..28d9912 --- /dev/null +++ b/src/components/icons/Play.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Play = (props: React.SVGProps) => ( + + + +); +export default Play; diff --git a/src/components/icons/Pumped.tsx b/src/components/icons/Pumped.tsx new file mode 100644 index 0000000..3f9fa51 --- /dev/null +++ b/src/components/icons/Pumped.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Pumped = (props: React.SVGProps) => ( + + + +); +export default Pumped; diff --git a/src/components/icons/RC.tsx b/src/components/icons/RC.tsx new file mode 100644 index 0000000..1737543 --- /dev/null +++ b/src/components/icons/RC.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const RC = (props: React.SVGProps) => ( + + + +); +export default RC; diff --git a/src/components/icons/Rest.tsx b/src/components/icons/Rest.tsx new file mode 100644 index 0000000..d616f67 --- /dev/null +++ b/src/components/icons/Rest.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Rest = (props: React.SVGProps) => ( + + + +); +export default Rest; diff --git a/src/components/icons/Rewind.tsx b/src/components/icons/Rewind.tsx new file mode 100644 index 0000000..5151936 --- /dev/null +++ b/src/components/icons/Rewind.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Rewind = (props: React.SVGProps) => ( + + + +); +export default Rewind; diff --git a/src/components/icons/RewindForward.tsx b/src/components/icons/RewindForward.tsx new file mode 100644 index 0000000..eb132ae --- /dev/null +++ b/src/components/icons/RewindForward.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const RewindForward = (props: React.SVGProps) => ( + + + +); +export default RewindForward; diff --git a/src/components/icons/Road.tsx b/src/components/icons/Road.tsx new file mode 100644 index 0000000..cf08119 --- /dev/null +++ b/src/components/icons/Road.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Road = (props: React.SVGProps) => ( + + + +); +export default Road; diff --git a/src/components/icons/Sale.tsx b/src/components/icons/Sale.tsx new file mode 100644 index 0000000..e690050 --- /dev/null +++ b/src/components/icons/Sale.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Sale = (props: React.SVGProps) => ( + + + +); +export default Sale; diff --git a/src/components/icons/Salon.tsx b/src/components/icons/Salon.tsx new file mode 100644 index 0000000..660cfe7 --- /dev/null +++ b/src/components/icons/Salon.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Salon = (props: React.SVGProps) => ( + + + +); +export default Salon; diff --git a/src/components/icons/Save.tsx b/src/components/icons/Save.tsx new file mode 100644 index 0000000..7c9820a --- /dev/null +++ b/src/components/icons/Save.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Save = (props: React.SVGProps) => ( + + + +); +export default Save; diff --git a/src/components/icons/Science.tsx b/src/components/icons/Science.tsx new file mode 100644 index 0000000..dbcbeef --- /dev/null +++ b/src/components/icons/Science.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Science = (props: React.SVGProps) => ( + + + +); +export default Science; diff --git a/src/components/icons/Scooter.tsx b/src/components/icons/Scooter.tsx new file mode 100644 index 0000000..1ff0991 --- /dev/null +++ b/src/components/icons/Scooter.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Scooter = (props: React.SVGProps) => ( + + + +); +export default Scooter; diff --git a/src/components/icons/SeaWaves.tsx b/src/components/icons/SeaWaves.tsx new file mode 100644 index 0000000..964d54b --- /dev/null +++ b/src/components/icons/SeaWaves.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const SeaWaves = (props: React.SVGProps) => ( + + + +); +export default SeaWaves; diff --git a/src/components/icons/Search.tsx b/src/components/icons/Search.tsx new file mode 100644 index 0000000..2d74b56 --- /dev/null +++ b/src/components/icons/Search.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Search = (props: React.SVGProps) => ( + + + +); +export default Search; diff --git a/src/components/icons/Send.tsx b/src/components/icons/Send.tsx new file mode 100644 index 0000000..1bdb22f --- /dev/null +++ b/src/components/icons/Send.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Send = (props: React.SVGProps) => ( + + + +); +export default Send; diff --git a/src/components/icons/Shop.tsx b/src/components/icons/Shop.tsx new file mode 100644 index 0000000..aa69df4 --- /dev/null +++ b/src/components/icons/Shop.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Shop = (props: React.SVGProps) => ( + + + +); +export default Shop; diff --git a/src/components/icons/SportsGround.tsx b/src/components/icons/SportsGround.tsx new file mode 100644 index 0000000..763f8e6 --- /dev/null +++ b/src/components/icons/SportsGround.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const SportsGround = (props: React.SVGProps) => ( + + + +); +export default SportsGround; diff --git a/src/components/icons/Stylobate.tsx b/src/components/icons/Stylobate.tsx new file mode 100644 index 0000000..45777ca --- /dev/null +++ b/src/components/icons/Stylobate.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Stylobate = (props: React.SVGProps) => ( + + + +); +export default Stylobate; diff --git a/src/components/icons/Subway.tsx b/src/components/icons/Subway.tsx new file mode 100644 index 0000000..82d961a --- /dev/null +++ b/src/components/icons/Subway.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Subway = (props: React.SVGProps) => ( + + + +); +export default Subway; diff --git a/src/components/icons/Surroundings.tsx b/src/components/icons/Surroundings.tsx new file mode 100644 index 0000000..f7d4ff5 --- /dev/null +++ b/src/components/icons/Surroundings.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Surroundings = (props: React.SVGProps) => ( + + + +); +export default Surroundings; diff --git a/src/components/icons/Tennis.tsx b/src/components/icons/Tennis.tsx new file mode 100644 index 0000000..c7d2ace --- /dev/null +++ b/src/components/icons/Tennis.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Tennis = (props: React.SVGProps) => ( + + + +); +export default Tennis; diff --git a/src/components/icons/Theater.tsx b/src/components/icons/Theater.tsx new file mode 100644 index 0000000..6ae5be3 --- /dev/null +++ b/src/components/icons/Theater.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Theater = (props: React.SVGProps) => ( + + + +); +export default Theater; diff --git a/src/components/icons/Tour3D.tsx b/src/components/icons/Tour3D.tsx new file mode 100644 index 0000000..2d1af38 --- /dev/null +++ b/src/components/icons/Tour3D.tsx @@ -0,0 +1,21 @@ +import * as React from "react"; +const Tour3D = (props: React.SVGProps) => ( + + + + +); +export default Tour3D; diff --git a/src/components/icons/Train.tsx b/src/components/icons/Train.tsx new file mode 100644 index 0000000..af7c226 --- /dev/null +++ b/src/components/icons/Train.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Train = (props: React.SVGProps) => ( + + + +); +export default Train; diff --git a/src/components/icons/Tram.tsx b/src/components/icons/Tram.tsx new file mode 100644 index 0000000..5fe5aa4 --- /dev/null +++ b/src/components/icons/Tram.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +const Tram = (props: React.SVGProps) => ( + + + +); +export default Tram; diff --git a/src/components/icons/WalkStreet.tsx b/src/components/icons/WalkStreet.tsx new file mode 100644 index 0000000..34730c2 --- /dev/null +++ b/src/components/icons/WalkStreet.tsx @@ -0,0 +1,19 @@ +import * as React from "react"; +const WalkStreet = (props: React.SVGProps) => ( + + + + +); +export default WalkStreet; diff --git a/src/components/icons/Work.tsx b/src/components/icons/Work.tsx new file mode 100644 index 0000000..d41eabf --- /dev/null +++ b/src/components/icons/Work.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +const Work = (props: React.SVGProps) => ( + + + +); +export default Work; diff --git a/src/components/pages/Hero.tsx b/src/components/pages/Hero.tsx new file mode 100644 index 0000000..7c2c4a2 --- /dev/null +++ b/src/components/pages/Hero.tsx @@ -0,0 +1,24 @@ +/* eslint-disable @next/next/no-img-element */ +import React from "react"; + +export default function Hero() { + return ( +
+

+ Жизнь на высоте + с видом на залив +

+ + Hero +
+ ); +} diff --git a/src/components/pages/Overview.tsx b/src/components/pages/Overview.tsx new file mode 100644 index 0000000..8891623 --- /dev/null +++ b/src/components/pages/Overview.tsx @@ -0,0 +1,61 @@ +import React from "react"; +import BookSlider from "../ui/BookSlider"; + +export default function Overview() { + return ( +
+
+ +
+
+ {"(1) Концепция проекта"} +
+
+ Центр города. Берег залива. Место, где архитектура становится + искусством, а дом — вашей личной сценой. Мы продумали каждую + деталь, чтобы вы могли жить, не идя на компромиссы +
+
+
+
+
+ {"(1) Концепция проекта"} +
+
+ Центр города. Берег залива. Место, где архитектура становится + искусством, а дом — вашей личной сценой. Мы продумали каждую + деталь, чтобы вы могли жить, не идя на компромиссы +
+
+
+
+
+ {"(1) Концепция проекта"} +
+
+ Центр города. Берег залива. Место, где архитектура становится + искусством, а дом — вашей личной сценой. Мы продумали каждую + деталь, чтобы вы могли жить, не идя на компромиссы +
+
+
+
+
+ {"(1) Концепция проекта"} +
+
+ Центр города. Берег залива. Место, где архитектура становится + искусством, а дом — вашей личной сценой. Мы продумали каждую + деталь, чтобы вы могли жить, не идя на компромиссы +
+
+
+ +
+
+ ); +} diff --git a/src/components/pages/Premiere.tsx b/src/components/pages/Premiere.tsx new file mode 100644 index 0000000..ff71385 --- /dev/null +++ b/src/components/pages/Premiere.tsx @@ -0,0 +1,100 @@ +/* eslint-disable @next/next/no-img-element */ +import { useEffect, useRef } from "react"; +import { useAppStateStore } from "@/stores/useAppStateStore"; + +export default function Premiere() { + const ref = useRef(null); + const { setHeaderColorScheme } = useAppStateStore(); + + useEffect(() => { + const el = ref.current; + if (!el) return; + + const observer = new IntersectionObserver(([entry]) => { + if (entry.isIntersecting) { + setHeaderColorScheme("Dark"); + } else { + setHeaderColorScheme("Light"); + } + }); + + observer.observe(el); + return () => observer.disconnect(); + }, [setHeaderColorScheme]); + + return ( +
+
+ +

+ Дягилев — премьера, + которая вдохновляет +

+ +
+ Premiere + +
+ + 124 + + + продуманных планировки + +
+
+ +
+
+ + 8-12 + + + переменная этажность + +
+ + Premiere +
+ +
+
+ + 145 + + + парковочных мест + +
+ + Premiere + +
+ + 3-3,9м + + высота потолков +
+
+
+ ); +} diff --git a/src/components/ui/BookSlider.tsx b/src/components/ui/BookSlider.tsx new file mode 100644 index 0000000..051fabb --- /dev/null +++ b/src/components/ui/BookSlider.tsx @@ -0,0 +1,177 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { useEffect, useRef, useState } from "react"; +import Arrow from "@/components/icons/Arrow"; +import clsx from "clsx"; +import { motion, AnimatePresence } from "motion/react"; +import HTMLFlipBook from "react-pageflip"; + +const FLIPPING_TIME = 500; + +export default function BookSlider({ + children, +}: { + children: React.ReactNode; +}) { + const [isHovered, setIsHovered] = useState(false); + const [cursorPosition, setCursorPosition] = useState({ x: 0, y: 0 }); + const [cursorOnRightSide, setCursorOnRightSide] = useState(false); + const [bookWidth, setBookWidth] = useState(0); + const [bookHeight, setBookHeight] = useState(0); + const flipBookRef = useRef(null); + const sliderRef = useRef(null); + const rectRef = useRef(null); + const frameRef = useRef(null); + const isFlipping = useRef(false); + const lastMouseEvent = useRef(null); + + const handleMouseEnter = () => { + setIsHovered(true); + if (sliderRef.current) { + rectRef.current = sliderRef.current.getBoundingClientRect(); + } + }; + + const handleMouseLeave = () => { + setIsHovered(false); + + if (frameRef.current) { + cancelAnimationFrame(frameRef.current); + frameRef.current = null; + } + }; + + useEffect(() => { + if (sliderRef.current) { + setBookWidth(sliderRef.current.getBoundingClientRect().width); + setBookHeight(sliderRef.current.getBoundingClientRect().height); + } + }, []); + + useEffect(() => { + const handleMove = (e: MouseEvent) => { + lastMouseEvent.current = e; + + if (!rectRef.current) return; + + const x = e.clientX - rectRef.current.left; + const y = e.clientY - rectRef.current.top; + + const inside = + e.clientX >= rectRef.current.left && + e.clientX <= rectRef.current.right && + e.clientY >= rectRef.current.top && + e.clientY <= rectRef.current.bottom; + + if (!inside) { + setIsHovered(false); + return; + } + + setIsHovered(true); + + if (frameRef.current) return; + frameRef.current = requestAnimationFrame(() => { + setCursorPosition({ x, y }); + setCursorOnRightSide(x > rectRef.current!.width / 2); + frameRef.current = null; + }); + }; + + const handleScroll = () => { + if (!sliderRef.current || !lastMouseEvent.current) return; + rectRef.current = sliderRef.current.getBoundingClientRect(); + handleMove(lastMouseEvent.current); + }; + + window.addEventListener("mousemove", handleMove); + window.addEventListener("scroll", handleScroll, true); + + return () => { + window.removeEventListener("mousemove", handleMove); + window.removeEventListener("scroll", handleScroll, true); + }; + }, []); + + const handleClick = () => { + if (flipBookRef.current && !isFlipping.current) { + isFlipping.current = true; + if (cursorOnRightSide) (flipBookRef.current as any).pageFlip().flipNext(); + else (flipBookRef.current as any).pageFlip().flipPrev(); + setTimeout(() => { + isFlipping.current = false; + }, FLIPPING_TIME); + } + }; + + return ( +
+ + {isHovered && ( + + )} + + + {/* @ts-expect-error Почему то хочет чтобы были вообще все пропсы (даже необязательные), хотя работает только и без них */} + + {children} + +
+ ); +} + +function CursorButton({ + x, + y, + rightSide, +}: { + x: number; + y: number; + rightSide: boolean; +}) { + const [width, setWidth] = useState(0); + return ( + { + if (el) setWidth(el.getBoundingClientRect().width); + }} + style={{ + transform: `translate3d(${x - width / 2}px, ${y - width / 2}px, 0)`, + }} + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + exit={{ opacity: 0 }} + transition={{ duration: 0.3 }} + className="absolute z-10 lg:size-[6.944vw] border border-[#FFFFFF]/25 backdrop-blur-[16px] flex items-center justify-center rounded-full bg-[#262626]/25 pointer-events-none" + > +
+ +
+
+ ); +} diff --git a/src/components/ui/Buttons/Button.tsx b/src/components/ui/Buttons/Button.tsx new file mode 100644 index 0000000..4aa9aeb --- /dev/null +++ b/src/components/ui/Buttons/Button.tsx @@ -0,0 +1,56 @@ +"use client"; + +import React from "react"; +import clsx from "clsx"; + +interface ButtonProps { + children: React.ReactNode; + onClick: () => void; + type?: "Primary" | "PrimaryInverse" | "Tertiary"; + size?: "L" | "M" | "S"; + className?: string; + disabled?: boolean; +} + +export default function Button({ + children, + onClick, + className, + disabled, + type = "Primary", + size = "M", +}: ButtonProps) { + const baseStyles = clsx( + size === "L" && + "button-l lg:p-[1.111vw] md:p-[2.083vw] p-[4.444vw] lg:rounded-[1.111vw] md:rounded-[2.083vw] rounded-[4.444vw]", + size === "M" && + "button-m lg:p-[0.833vw] md:p-[1.563vw] p-[3.333vw] lg:rounded-[0.972vw] md:rounded-[1.823vw] rounded-[3.889vw]", + size === "S" && + "button-s lg:p-[0.625vw] md:p-[1.172vw] p-[2.5vw] lg:rounded-[0.833vw] md:rounded-[1.563vw] rounded-[3.333vw]" + ); + + const colorStyles = clsx( + type === "Primary" && + (disabled + ? "bg-[#262626]/6 text-[#262626]/6 backdrop-blur-[16px]" + : "bg-[#262626]/6 text-[#262626] hover:bg-[#262626]/25 active:bg-[#262626] active:text-white"), + type === "PrimaryInverse" && + (disabled + ? "bg-[#FFFFFF]/20 text-[#262626]/6 backdrop-blur-[16px]" + : "bg-[#3D514B] text-white hover:bg-[#3D514B] hover:text-[#FFFFFF]/80 active:bg-[#0D261E] active:text-white "), + type === "Tertiary" && + (disabled + ? "bg-[#FFFFFF]/20 text-[#262626]/6 backdrop-blur-[16px]" + : "bg-[#FFFFFF] text-[#262626] hover:bg-[#FFFFFF]/80 active:bg-[#FFFFFF] active:text-[#262626]/60") + ); + + return ( + + ); +} diff --git a/src/components/ui/Buttons/ButtonRound.tsx b/src/components/ui/Buttons/ButtonRound.tsx new file mode 100644 index 0000000..843e55c --- /dev/null +++ b/src/components/ui/Buttons/ButtonRound.tsx @@ -0,0 +1,48 @@ +import clsx from "clsx"; +import React from "react"; + +interface ButtonRoundProps { + type: "White" | "Dark"; + text: string; + icon: React.ReactNode; + onClick: () => void; + className?: string; + disabled?: boolean; +} + +export default function ButtonRound({ + type = "White", + text, + icon, + onClick, + className, +}: ButtonRoundProps) { + const typeStyles = clsx( + type === "White" && "bg-[#262626]/25 text-white", + type === "Dark" && "bg-[#FFFFFF]/20 text-black" + ); + return ( + + ); +} diff --git a/src/components/ui/Controls/RadioButton.tsx b/src/components/ui/Controls/RadioButton.tsx new file mode 100644 index 0000000..4fce173 --- /dev/null +++ b/src/components/ui/Controls/RadioButton.tsx @@ -0,0 +1,29 @@ +import clsx from "clsx"; + +interface RadioButtonProps { + onChange: (e: React.MouseEvent) => void; + checked: boolean; +} + +export default function RadioButton({ onChange, checked }: RadioButtonProps) { + const bgStyles = clsx( + checked + ? "lg:border-[0.347vw] md:border-[0.651vw] border-[1.389vw] border-[#3D514B] hover:border-[#0D261E] " + : "lg:border-[0.139vw] md:border-[0.26vw] border-[0.556vw] border-[#EBEBEB]" + ); + + const handleClick = (e: React.MouseEvent) => { + e.preventDefault(); + onChange(e); + }; + + return ( + + ); +} diff --git a/src/components/ui/Header.tsx b/src/components/ui/Header.tsx new file mode 100644 index 0000000..7c35de2 --- /dev/null +++ b/src/components/ui/Header.tsx @@ -0,0 +1,101 @@ +import Logo from "../icons/Logo"; +import clsx from "clsx"; +import HeartFilled from "../icons/HeartFilled"; +import { useAppStateStore } from "@/stores/useAppStateStore"; + +export default function Header() { + const headerColorScheme = useAppStateStore( + (state) => state.headerColorScheme + ); + const setMenuOpen = useAppStateStore((state) => state.setMenuOpen); + const menuOpen = useAppStateStore((state) => state.menuOpen); + + const colorSchemeStyles = clsx( + headerColorScheme === "Light" && "text-white", + headerColorScheme === "Dark" && "text-[#262626]" + ); + return ( +
+
+ + + + {"+7 (900) 000-00-00"} + +
+ + + + +
+ ); +} diff --git a/src/components/ui/MenuSidebar.tsx b/src/components/ui/MenuSidebar.tsx new file mode 100644 index 0000000..4ca0f6b --- /dev/null +++ b/src/components/ui/MenuSidebar.tsx @@ -0,0 +1,71 @@ +import { useAppStateStore } from "@/stores/useAppStateStore"; +import clsx from "clsx"; + +export default function MenuSidebar() { + const menuOpen = useAppStateStore((state) => state.menuOpen); + + const menuOpenStyles = clsx( + menuOpen && "translate-x-0", + !menuOpen && "-translate-x-full" + ); + + return ( + + ); +} diff --git a/src/components/ui/ScreenOverlay.tsx b/src/components/ui/ScreenOverlay.tsx new file mode 100644 index 0000000..b26dd58 --- /dev/null +++ b/src/components/ui/ScreenOverlay.tsx @@ -0,0 +1,17 @@ +import { useAppStateStore } from "@/stores/useAppStateStore"; +import clsx from "clsx"; + +export default function ScreenOverlay() { + const menuOpen = useAppStateStore((state) => state.menuOpen); + const setMenuOpen = useAppStateStore((state) => state.setMenuOpen); + + return ( +
setMenuOpen(false)} + className={clsx( + "fixed inset-0 bg-black/50 z-[97] transition-opacity duration-300", + menuOpen ? "opacity-100" : "opacity-0 pointer-events-none" + )} + /> + ); +} diff --git a/src/stores/useAppStateStore.tsx b/src/stores/useAppStateStore.tsx new file mode 100644 index 0000000..6cf8b2a --- /dev/null +++ b/src/stores/useAppStateStore.tsx @@ -0,0 +1,19 @@ +import { create } from "zustand"; + +interface AppStateStore { + isLoading: boolean; + setIsLoading: (isLoading: boolean) => void; + headerColorScheme: "Light" | "Dark"; + setHeaderColorScheme: (headerColorScheme: "Light" | "Dark") => void; + menuOpen: boolean; + setMenuOpen: (menuOpen: boolean) => void; +} + +export const useAppStateStore = create((set) => ({ + isLoading: true, + setIsLoading: (isLoading) => set({ isLoading }), + menuOpen: false, + setMenuOpen: (menuOpen) => set({ menuOpen }), + headerColorScheme: "Light", + setHeaderColorScheme: (headerColorScheme) => set({ headerColorScheme }), +})); diff --git a/tailwind.config.js b/tailwind.config.js index 9024638..baedf7c 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -2,6 +2,13 @@ module.exports = { content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], theme: { + screens: { + xs: "360px", + sm: "640px", + md: "768px", + lg: "1440px", + "2xl": "1536px", + }, extend: {}, }, plugins: [],