diff --git a/.github/workflows/test.yml-template b/.github/workflows/test.yml-template new file mode 100644 index 00000000..8b5743ec --- /dev/null +++ b/.github/workflows/test.yml-template @@ -0,0 +1,29 @@ +name: Test + +on: + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test + - name: Upload HTML report(backstop data) + if: ${{ always() }} + uses: actions/upload-artifact@v2 + with: + name: report + path: backstop_data diff --git a/README.md b/README.md index 302783df..f474fe0e 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Implement landing page according to [Figma design](https://www.figma.com/file/Bl 11. `git push origin develop` - to send you code for PR. 12. Create a Pull Request (PR) from your branch `develop` to branch `master` of original repo. 13. Replace `` with your Github username in the - [DEMO LINK](https://.github.io/layout_KateVR/). + [DEMO LINK](https:///MykolaFatkullin.github.io/layout_KateVR/). 14. Copy `DEMO LINK` to the PR description. > To update you PR repeat steps 7-11. diff --git a/index.html b/index.html index d339e685..7169db11 100644 --- a/index.html +++ b/index.html @@ -1,19 +1,2215 @@ - + - Title + Kat VR + + - -

Hello Mate Academy

- + +
+
+
+
+ + + + +
+ +
+ + + +
+
+
+
+ Background + Background + Background +
+
+
+

+ THE NEW START OF +

+

+ VR LOCOMOTION +

+
+
+

+ Discover the most comprehensive VR Locomotion system, and unlock + infinite motion in any games on any platforms! +

+

1200$

+ + +
+
+
+
+ + +
+ + +
+
+
+
+ + + +
+
+
+
+
+

+ MORE THAN + + GAMING! + +

+

+ This also made for people who are interested in... +

+
+
+
+ Education +

+ EDUCATION +

+

+ Create aducational simulations, trainings and much more with + unlimited virtual space and minimum physical space +

+
+
+ Estate +

+ REAL ESTATE +

+

+ Desighn architectural projects in a deeply realistic + environment allowing visitors to freely walk around, and feel + their vibe +

+
+
+ Estate +

+ FITNESS +

+

+ Combine business with pleasure, and discover countless ways to + stay fit while playing your favorite VR Games! +

+
+
+ Estate + + SOCIAL INTERACTIONS + + + Hang out with your friends in the virtual world when you can’t + meet space requirements + +
+
+
+
+
+
+
+
+

+ ABOUT + + PRODUCT + +

+ +
+
+
+ 1 + / + 5 +
+
+ Slider 1 + Slider 2 + Slider 3 + Slider 4 + Slider 5 +
+
+ + + + + +
+
+
+ + +
+
+
+

+ ABOUT + PRODUCT +

+

+ KAT loco is a foot-based VR locomotion system that gives + complete physical control over lower-body actions, allowing you + to freely walk, run, and carry out just any other movement in + virtual reality. +

+ +
+
+
+
+ + Hello, + +

+ NICE TO MEET + + YOU! + +

+

+ KAT VR is an independent company dedicated to the research, + development, and sales of VR Locomotion products and solutions. + Founded in 2013, we have quickly grown to become one of the + world’s leading professional suppliers of VR games’ & + simulations’ equipment +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+

+ TECH + + SPECS + +

+
+ Specification + Ellipse +
+ + Line left +
+

+ SENSOR +

+

+ Weight: 35g/1.23oz each +

+

+ Dimension: 50mm/1.97in 24mm/0.94in +

+

+ Light: LED lights +

+
+
+
+ + Line left +
+

+ CONNECTION +

+

+ Wireless: Bluetooth 4.2 +

+

+ Signal range: 5m +

+

+ Receiver: USB 2.0 and above +

+
+
+
+ + Line left +
+

+ BATTERRIES +

+

+ Type: Lthium-lon polymer batteries +

+

+ Capacity: 370mAh +

+

+ Battery life: 10h of continuous use 150 hours on stand by +

+

+ Charging: Fast charging - 1 hour +

+

+ Charging voltage and current: 5V = 0.5A +

+
+
+
+
+
+ +
+
+

+ WHY + + KAT LOCO? + +

+
+
+ Estate +

+ UNIVERSALLY COMPATIBLE +

+

+ KAT Loco offers universal compatibility across all major VR + headsets and platforms allowing you to play any VR game with + support for Free Locomotion +

+
+
+ Estate +

+ VR/PC CONTROL PANEL +

+

+ Our Multifunctional Software allows for quick access to KAT + Loco’s control panel both from a computer desktop, and directly + from your VR headset. +

+
+
+ Estate +

+ WIRELESS SENSORS +

+

+ What makes it even more advanced, KAT Loco is entirely wireless, + and comes with a complete system of algorithms, super durable + batteries and more! +

+
+
+ +
+
+
+
+
+
+

+ Have any questions? +

+

+ GET IN + + TOUCH + +

+

+ Our manager will reply you within 15 minutes +

+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+

+ Our manager will reply you within 15 minutes +

+
+ + + + + +
+
+
+
+ + +
+ + + + + + + + + + diff --git a/package-lock.json b/package-lock.json index 87fcefd8..a9f401a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,14 @@ "version": "1.0.0", "hasInstallScript": true, "license": "GPL-3.0", + "dependencies": { + "country-state-city": "^3.2.1" + }, "devDependencies": { "@linthtml/linthtml": "^0.9.6", "@mate-academy/bemlint": "latest", "@mate-academy/linthtml-config": "latest", - "@mate-academy/scripts": "^2.1.2", + "@mate-academy/scripts": "^2.1.3", "@mate-academy/stylelint-config": "latest", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", @@ -52,6 +55,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -522,6 +526,7 @@ "url": "https://opencollective.com/csstools" } ], + "peer": true, "engines": { "node": ">=18" }, @@ -563,6 +568,7 @@ "url": "https://opencollective.com/csstools" } ], + "peer": true, "engines": { "node": ">=18" } @@ -1510,10 +1516,11 @@ "dev": true }, "node_modules/@mate-academy/scripts": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-2.1.2.tgz", - "integrity": "sha512-gUXFdqqOfYzF9R3RSx2pCa5GLdOkxB9bFbF+dpUpzucdgGAANqOGdqpmNnMj+e3xA9YHraUWq3xo9cwe5vD9pQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-2.1.3.tgz", + "integrity": "sha512-a07wHTj/1QUK2Aac5zHad+sGw4rIvcNl5lJmJpAD7OxeSbnCdyI6RXUHwXhjF5MaVo9YHrJ0xVahyERS2IIyBQ==", "dev": true, + "license": "MIT", "dependencies": { "@octokit/rest": "^17.11.2", "@types/get-port": "^4.2.0", @@ -1590,7 +1597,6 @@ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", "dev": true, - "peer": true, "engines": { "node": ">= 20" } @@ -1619,7 +1625,6 @@ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", "dev": true, - "peer": true, "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" @@ -1633,7 +1638,6 @@ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", "dev": true, - "peer": true, "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", @@ -1647,8 +1651,7 @@ "version": "27.0.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@octokit/plugin-paginate-rest": { "version": "2.21.3", @@ -1710,7 +1713,6 @@ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.7.tgz", "integrity": "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==", "dev": true, - "peer": true, "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", @@ -1727,7 +1729,6 @@ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", "dev": true, - "peer": true, "dependencies": { "@octokit/types": "^16.0.0" }, @@ -1915,7 +1916,6 @@ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", "dev": true, - "peer": true, "dependencies": { "@octokit/openapi-types": "^27.0.0" } @@ -2697,6 +2697,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "dev": true, + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -3070,8 +3071,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/bl": { "version": "4.1.0", @@ -3125,6 +3125,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -3506,6 +3507,12 @@ "node": ">= 6" } }, + "node_modules/country-state-city": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/country-state-city/-/country-state-city-3.2.1.tgz", + "integrity": "sha512-kxbanqMc6izjhc/EHkGPCTabSPZ2G6eG4/97akAYHJUN4stzzFEvQPZoF8oXDQ+10gM/O/yUmISCR1ZVxyb6EA==", + "license": "GPL-3.0" + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -4180,8 +4187,7 @@ "type": "opencollective", "url": "https://opencollective.com/fastify" } - ], - "peer": true + ] }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -5925,6 +5931,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.5.4.tgz", "integrity": "sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ==", "dev": true, + "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } @@ -6721,6 +6728,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6799,6 +6807,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7312,6 +7321,7 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.94.2.tgz", "integrity": "sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A==", "dev": true, + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -7645,6 +7655,7 @@ "url": "https://github.com/sponsors/stylelint" } ], + "peer": true, "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-syntax-patches-for-csstree": "^1.0.19", @@ -8081,6 +8092,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "peer": true, "engines": { "node": ">=12" }, @@ -8206,8 +8218,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", - "dev": true, - "peer": true + "dev": true }, "node_modules/universalify": { "version": "2.0.1", @@ -8384,6 +8395,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "peer": true, "engines": { "node": ">=12" }, @@ -8721,20 +8733,6 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, - "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 7149ff15..f710ed32 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@linthtml/linthtml": "^0.9.6", "@mate-academy/bemlint": "latest", "@mate-academy/linthtml-config": "latest", - "@mate-academy/scripts": "^2.1.2", + "@mate-academy/scripts": "^2.1.3", "@mate-academy/stylelint-config": "latest", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", @@ -42,5 +42,8 @@ "tests": { "backstop": false } + }, + "dependencies": { + "country-state-city": "^3.2.1" } } diff --git a/src/fonts/FontFont_FF.Mark.Pro.Heavy.otf b/src/fonts/FontFont_FF.Mark.Pro.Heavy.otf deleted file mode 100644 index c9caaccd..00000000 Binary files a/src/fonts/FontFont_FF.Mark.Pro.Heavy.otf and /dev/null differ diff --git a/src/fonts/FontFont_FF.Mark.Pro.Medium.otf b/src/fonts/FontFont_FF.Mark.Pro.Medium.otf deleted file mode 100644 index d5999d8c..00000000 Binary files a/src/fonts/FontFont_FF.Mark.Pro.Medium.otf and /dev/null differ diff --git a/src/fonts/FontFont_FF.Mark.Pro.otf b/src/fonts/FontFont_FF.Mark.Pro.otf deleted file mode 100644 index 3b72bc1f..00000000 Binary files a/src/fonts/FontFont_FF.Mark.Pro.otf and /dev/null differ diff --git a/src/fonts/Inter.ttf b/src/fonts/Inter.ttf new file mode 100644 index 00000000..e31b51e3 Binary files /dev/null and b/src/fonts/Inter.ttf differ diff --git a/src/fonts/Quantum-400.otf b/src/fonts/Quantum-400.otf deleted file mode 100644 index b26c7892..00000000 Binary files a/src/fonts/Quantum-400.otf and /dev/null differ diff --git a/src/images/header/header-bg-2.png b/src/images/header/header-bg-2.png new file mode 100644 index 00000000..1a986044 Binary files /dev/null and b/src/images/header/header-bg-2.png differ diff --git a/src/images/header/header-bg-3.png b/src/images/header/header-bg-3.png new file mode 100644 index 00000000..88e5d1d4 Binary files /dev/null and b/src/images/header/header-bg-3.png differ diff --git a/src/images/header/header-bg.png b/src/images/header/header-bg.png new file mode 100644 index 00000000..921e7eeb Binary files /dev/null and b/src/images/header/header-bg.png differ diff --git a/src/images/icon/button-up.svg b/src/images/icon/button-up.svg new file mode 100644 index 00000000..aa3633bd --- /dev/null +++ b/src/images/icon/button-up.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/images/icon/favicon.svg b/src/images/icon/favicon.svg new file mode 100644 index 00000000..a4259452 --- /dev/null +++ b/src/images/icon/favicon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/icon/icon-arrow-down.svg b/src/images/icon/icon-arrow-down.svg new file mode 100644 index 00000000..de53fb1b --- /dev/null +++ b/src/images/icon/icon-arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/icon/icon-arrow-up.svg b/src/images/icon/icon-arrow-up.svg new file mode 100644 index 00000000..82786b86 --- /dev/null +++ b/src/images/icon/icon-arrow-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/icon/icon-back.svg b/src/images/icon/icon-back.svg new file mode 100644 index 00000000..0a54709b --- /dev/null +++ b/src/images/icon/icon-back.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/icon/icon-close.svg b/src/images/icon/icon-close.svg new file mode 100644 index 00000000..307a46db --- /dev/null +++ b/src/images/icon/icon-close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/images/icon/icon-compatible.svg b/src/images/icon/icon-compatible.svg new file mode 100644 index 00000000..37e8765f --- /dev/null +++ b/src/images/icon/icon-compatible.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/images/icon/icon-control-panel.svg b/src/images/icon/icon-control-panel.svg new file mode 100644 index 00000000..6188346d --- /dev/null +++ b/src/images/icon/icon-control-panel.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/images/icon/icon-education.svg b/src/images/icon/icon-education.svg new file mode 100644 index 00000000..ed2e4f00 --- /dev/null +++ b/src/images/icon/icon-education.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/images/icon/icon-estate.svg b/src/images/icon/icon-estate.svg new file mode 100644 index 00000000..68a50378 --- /dev/null +++ b/src/images/icon/icon-estate.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/images/icon/icon-fitness.svg b/src/images/icon/icon-fitness.svg new file mode 100644 index 00000000..2c3c44e8 --- /dev/null +++ b/src/images/icon/icon-fitness.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/images/icon/icon-mastercard.svg b/src/images/icon/icon-mastercard.svg new file mode 100644 index 00000000..67e199b8 --- /dev/null +++ b/src/images/icon/icon-mastercard.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/images/icon/icon-menu.svg b/src/images/icon/icon-menu.svg new file mode 100644 index 00000000..31499720 --- /dev/null +++ b/src/images/icon/icon-menu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/icon/icon-play-hover.svg b/src/images/icon/icon-play-hover.svg new file mode 100644 index 00000000..7284d3c5 --- /dev/null +++ b/src/images/icon/icon-play-hover.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/images/icon/icon-play.svg b/src/images/icon/icon-play.svg new file mode 100644 index 00000000..aff87cae --- /dev/null +++ b/src/images/icon/icon-play.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/images/icon/icon-social.svg b/src/images/icon/icon-social.svg new file mode 100644 index 00000000..81f8ef94 --- /dev/null +++ b/src/images/icon/icon-social.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/images/icon/icon-visa.svg b/src/images/icon/icon-visa.svg new file mode 100644 index 00000000..0a97fb76 --- /dev/null +++ b/src/images/icon/icon-visa.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/images/icon/icon-wireless.svg b/src/images/icon/icon-wireless.svg new file mode 100644 index 00000000..68015352 --- /dev/null +++ b/src/images/icon/icon-wireless.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/images/logo.svg b/src/images/logo.svg new file mode 100644 index 00000000..b3435d9f --- /dev/null +++ b/src/images/logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/images/slider/slider-1.png b/src/images/slider/slider-1.png new file mode 100644 index 00000000..770d1232 Binary files /dev/null and b/src/images/slider/slider-1.png differ diff --git a/src/images/slider/slider-2.jpg b/src/images/slider/slider-2.jpg new file mode 100644 index 00000000..84a0d97c Binary files /dev/null and b/src/images/slider/slider-2.jpg differ diff --git a/src/images/slider/slider-3.jpeg b/src/images/slider/slider-3.jpeg new file mode 100644 index 00000000..f79d14a5 Binary files /dev/null and b/src/images/slider/slider-3.jpeg differ diff --git a/src/images/slider/slider-4.png b/src/images/slider/slider-4.png new file mode 100644 index 00000000..0e60dae4 Binary files /dev/null and b/src/images/slider/slider-4.png differ diff --git a/src/images/slider/slider-5.png b/src/images/slider/slider-5.png new file mode 100644 index 00000000..f7ad48d5 Binary files /dev/null and b/src/images/slider/slider-5.png differ diff --git a/src/images/specification/specification-bg.png b/src/images/specification/specification-bg.png new file mode 100644 index 00000000..b1389637 Binary files /dev/null and b/src/images/specification/specification-bg.png differ diff --git a/src/images/specification/specification-ellipse.svg b/src/images/specification/specification-ellipse.svg new file mode 100644 index 00000000..2d162854 --- /dev/null +++ b/src/images/specification/specification-ellipse.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/specification/specification-left-bottom-big-desktop.svg b/src/images/specification/specification-left-bottom-big-desktop.svg new file mode 100644 index 00000000..8183d536 --- /dev/null +++ b/src/images/specification/specification-left-bottom-big-desktop.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/specification/specification-left-bottom.svg b/src/images/specification/specification-left-bottom.svg new file mode 100644 index 00000000..e2961ab5 --- /dev/null +++ b/src/images/specification/specification-left-bottom.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/specification/specification-right.svg b/src/images/specification/specification-right.svg new file mode 100644 index 00000000..c1533eae --- /dev/null +++ b/src/images/specification/specification-right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/specification/specifications-left.svg b/src/images/specification/specifications-left.svg new file mode 100644 index 00000000..ef522dfa --- /dev/null +++ b/src/images/specification/specifications-left.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/scripts/card.js b/src/scripts/card.js new file mode 100644 index 00000000..bcc71a3a --- /dev/null +++ b/src/scripts/card.js @@ -0,0 +1,183 @@ +'use strict'; + +import { clearError, setError } from './form'; +import { configureExpiration } from './expiration'; + +const modal = document.querySelector('.card__form-field'); +const input = modal.querySelector('.card__input input'); +const visual = modal.querySelector('.card-visual'); +const caret = modal.querySelector('.card-visual__caret'); +const digits = modal.querySelectorAll('.card-visual__digit'); +const groups = modal.querySelectorAll('.card-visual__group'); +const logo = modal.querySelector('.card-visual__logo'); + +let cursorIndex = 0; + +function getRaw() { + return input.value.replace(/\D/g, '').slice(0, 16); +} + +export function clearCardInput() { + cursorIndex = 0; + updateDigits(''); + groups.forEach((group) => { + group.classList.remove('active'); + }); +} + +export function updateDigits(raw) { + digits.forEach((el, i) => { + if (raw[i]) { + el.textContent = raw[i]; + el.classList.add('card-visual__digit--filled'); + el.classList.remove('card-visual__placeholder'); + } else { + el.textContent = 0; + el.classList.remove('card-visual__digit--filled'); + el.classList.add('card-visual__placeholder'); + } + }); +} + +function updateActiveGroup(index) { + const activeGroupIndex = Math.min(Math.floor(index / 4), 3); + groups.forEach((group, i) => { + group.classList.toggle('active', i === activeGroupIndex); + }); +} + +function caretX(index) { + const visualRect = visual.getBoundingClientRect(); + + if (index >= digits.length) { + const lastDigitRect = digits[digits.length - 1].getBoundingClientRect(); + return lastDigitRect.right - visualRect.left; + } + + const digitRect = digits[index].getBoundingClientRect(); + return digitRect.left - visualRect.left; +} + +function render() { + const raw = getRaw(); + updateDigits(raw); + updateActiveGroup(cursorIndex); + caret.style.transform = `translateX(${caretX(cursorIndex)}px)`; + + logo.classList.remove('card-visual__logo--visa'); + logo.classList.remove('card-visual__logo--mastercard'); + + if (/^4/.test(raw)) { + logo.classList.add('card-visual__logo--visa'); + } else if ( + /^(5[1-5])/.test(raw) || + /^(222[1-9]|22[3-9]\d|2[3-6]\d{2}|27[01]\d|2720)/.test(raw) + ) { + logo.classList.add('card-visual__logo--mastercard'); + } + + clearError(modal); +} + +function configureDigits() { + digits.forEach((digit, index) => { + digit.addEventListener('pointerdown', (e) => { + e.preventDefault(); + input.focus(); + + const rawLength = getRaw().length; + + cursorIndex = Math.min(index, rawLength); + + render(); + }); + }); +} + +export function configureCardEvents() { + input.addEventListener('focus', () => { + visual.classList.add('card-visual--focused'); + cursorIndex = getRaw().length; + render(); + }); + + input.addEventListener('blur', () => { + visual.classList.remove('card-visual--focused'); + groups.forEach((group) => { + group.classList.remove('active'); + }); + validateCard(); + }); + + input.addEventListener('input', () => { + const raw = getRaw(); + cursorIndex = Math.min(cursorIndex, raw.length); + render(); + }); + + configureBeforeInput(); + configureButtons(); + configureDigits(); + + configureExpiration(); +} + +function configureBeforeInput() { + input.addEventListener('beforeinput', (e) => { + if (!e.data || !/^\d$/.test(e.data)) return; + + e.preventDefault(); + + const raw = getRaw(); + if (raw.length >= 16) return; + + const next = raw.slice(0, cursorIndex) + e.data + raw.slice(cursorIndex); + + input.value = next; + cursorIndex++; + render(); + }); +} + +function configureButtons() { + input.addEventListener('keydown', (e) => { + const raw = getRaw(); + + switch (e.key) { + case 'Backspace': + if (cursorIndex == 0) return; + e.preventDefault(); + input.value = raw.slice(0, cursorIndex - 1) + raw.slice(cursorIndex); + cursorIndex--; + render(); + break; + + case 'Delete': + if (cursorIndex > -raw.length) return; + e.preventDefault(); + input.value - raw.slice(0, cursorIndex) + raw.slice(cursorIndex + 1); + render(); + break; + + case 'ArrowRight': + cursorIndex = Math.min(raw.length, cursorIndex + 1); + render(); + break; + case 'ArrowLeft': + cursorIndex = Math.max(0, cursorIndex - 1); + render(); + break; + + default: + break; + } + }); +} + +function validateCard() { + const raw = getRaw(); + + if (raw.length < 16) { + setError(modal, 'cardNumberRequired'); + } +} diff --git a/src/scripts/contacts.js b/src/scripts/contacts.js new file mode 100644 index 00000000..aca70b50 --- /dev/null +++ b/src/scripts/contacts.js @@ -0,0 +1,95 @@ +'use strict'; + +const modal = document.querySelector('.contacts'); +const button = modal.querySelector('.contacts__button'); + +import { dictionary } from './i18n'; + +export function configureContactsFormValidations() { + modal.querySelectorAll('.contacts__form-field').forEach(initFieldValidation); + + button.addEventListener('click', () => { + let isValid = true; + + modal.querySelectorAll('.contacts__form-field').forEach((field) => { + const validField = validateField(field); + + if (!validField) { + isValid = false; + } + }); + + console.log(isValid); + + if (!isValid) return; + + if (isValid) { + modal.querySelector('.contacts__form').reset(); + clearAllErorrs(); + } + }); +} + +export function clearAllErorrs() { + modal.querySelectorAll('.contacts__form-field').forEach(clearError); +} + +function initFieldValidation(field) { + const input = field.querySelector('.form__input'); + if (input) { + input.addEventListener('blur', () => { + validateField(field); + }); + + input.addEventListener('input', () => { + clearError(field); + }); + } +} + +export function validateField(field) { + const input = field.querySelector('.form__input'); + if (!input) return true; + + const label = field.querySelector('.contacts__form-label'); + const value = input.value; + + clearError(field); + + if (input.required && !value.trim()) { + setError(field, label.getAttribute('data-error-required')); + return false; + } + + if (input.type === 'email' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { + setError(field, label.getAttribute('data-error-format')); + return false; + } + + return true; +} + +export function setError(field, errorName) { + const label = field.querySelector('.contacts__form-label'); + const language = getLanguage(); + + const error = dictionary[language][errorName]; + + label.textContent = error; + field.classList.add('contacts__form-field--error'); +} + +export function clearError(field) { + const label = field.querySelector('.contacts__form-label'); + const language = getLanguage(); + + const originalKey = label.dataset['i18n']; + + label.textContent = dictionary[language][originalKey]; + field.classList.remove('contacts__form-field--error'); +} + +function getLanguage() { + return document.querySelector('.language-dropdown__selected-label').dataset + .language; +} diff --git a/src/scripts/country-city-dropdown.js b/src/scripts/country-city-dropdown.js new file mode 100644 index 00000000..3458529b --- /dev/null +++ b/src/scripts/country-city-dropdown.js @@ -0,0 +1,77 @@ +'use strict'; + +import { Country, City } from 'country-state-city'; +import { configureDropdown } from './dropdown'; +import { clearError } from './form'; + +const countrySelectOptions = document.querySelector( + '.country-dropdown__options', +); +const cityField = document.querySelector('.city-dropdown'); +const cityOptionsContainer = document.querySelector('.city-dropdown__options'); +const cityLabel = document.querySelector('.city-dropdown__selected-label'); +const defaultCountry = 'UA'; + +export function createCountryCityDropdown() { + renderCountries(); + loadCitiesChunked(defaultCountry); + + const country = document.querySelector('.country-dropdown'); + configureDropdown(country, 'country', 'country', defaultCountry, [ + loadCitiesChunked, + clearCityErrors, + ]); + + configureDropdown(cityField, 'city', 'city', '', [clearCityErrors]); +} + +function renderCountries() { + const fragment = document.createDocumentFragment(); + + Country.getAllCountries().forEach((country) => { + const div = document.createElement('div'); + div.className = 'dropdown__option country-dropdown__option'; + div.dataset.country = country.isoCode; + div.textContent = country.name; + fragment.appendChild(div); + }); + + countrySelectOptions.appendChild(fragment); +} + +export function loadCitiesChunked(countryCode, chunkSize = 200) { + const uniqueCities = [ + ...new Set(City.getCitiesOfCountry(countryCode).map((city) => city.name)), + ].map((name) => ({ name })); + + cityOptionsContainer.innerHTML = ''; + cityLabel.textContent = ''; + + let index = 0; + + function renderChunk() { + const fragment = document.createDocumentFragment(); + const slice = uniqueCities.slice(index, index + chunkSize); + + slice.forEach((city) => { + const div = document.createElement('div'); + div.className = 'dropdown__option city-dropdown__option'; + div.dataset.city = city.name; + div.textContent = city.name; + fragment.appendChild(div); + }); + + cityOptionsContainer.appendChild(fragment); + index += chunkSize; + + if (index < uniqueCities.length) { + requestAnimationFrame(renderChunk); + } + } + + renderChunk(); +} + +function clearCityErrors() { + clearError(cityField); +} diff --git a/src/scripts/dropdown.js b/src/scripts/dropdown.js new file mode 100644 index 00000000..2bbf7a12 --- /dev/null +++ b/src/scripts/dropdown.js @@ -0,0 +1,68 @@ +'use strict'; + +export function configureDropdown( + root, + dropdownName, + datasetName, + defaultValue = '', + callbacks = [], +) { + const optionsContainer = root.querySelector( + `.${dropdownName}-dropdown__options`, + ); + const selectedLabel = root.querySelector( + `.${dropdownName}-dropdown__selected-label`, + ); + + root.addEventListener('click', () => { + root.classList.toggle('dropdown__opened'); + root.classList.toggle(`dropdown__opened-${dropdownName}`); + }); + + if (dropdownName === 'quantity' || dropdownName === 'country') { + syncUIDropdown(dropdownName, datasetName, defaultValue, root); + } + + optionsContainer.addEventListener('click', (e) => { + e.stopPropagation(); + + const option = e.target.closest(`.${dropdownName}-dropdown__option`); + if (!option) return; + + const value = option.dataset[datasetName]; + + selectedLabel.textContent = option.textContent; + selectedLabel.dataset[datasetName] = value; + + [...optionsContainer.children].forEach((opt) => { + opt.hidden = opt === option; + }); + + root.classList.remove('dropdown__opened'); + root.classList.remove(`dropdown__opened-${dropdownName}`); + callbacks.forEach((cb) => cb(value)); + }); + + document.addEventListener('click', (e) => { + if (!root.contains(e.target)) { + root.classList.remove('dropdown__opened'); + root.classList.remove(`dropdown__opened-${dropdownName}`); + } + }); +} + +export function syncUIDropdown(dropdownName, datasetName, defaultValue, root) { + const label = root.querySelector(`.${dropdownName}-dropdown__selected-label`); + + const options = root.querySelectorAll(`.${dropdownName}-dropdown__option`); + + for (const option of options) { + const isSelected = option.dataset[datasetName] === defaultValue; + option.hidden = isSelected; + + if (isSelected) { + label.textContent = option.textContent; + label.dataset[datasetName] = option.dataset[datasetName]; + } + } +} diff --git a/src/scripts/expiration.js b/src/scripts/expiration.js new file mode 100644 index 00000000..243241e3 --- /dev/null +++ b/src/scripts/expiration.js @@ -0,0 +1,131 @@ +'use strict'; + +import { clearError, setError } from './form'; + +const modal = document.querySelector('.card-secure__field--expiration'); +const expiration = document.querySelector('.card-secure__input--expiration'); +let cursor = 0; + +export function configureExpiration() { + configureCardExpirationEvents(); + + configureButtons(); +} + +function getRaw() { + return expiration.value.replace(/\D/g, '').slice(0, 4); +} + +function format(raw) { + if (raw.length <= 2) return raw; + + return `${raw.slice(0, 2)} / ${raw.slice(2)}`; +} + +function setValue(raw) { + expiration.value = format(raw); +} + +export function getError(raw) { + if (raw.length !== 4) return 'expirationDateRequired'; + + const month = parseInt(raw.slice(0, 2), 10); + const year = parseInt(raw.slice(2), 10); + + if (month < 1 || month > 12) { + return 'expirationInvalid'; + } + + const fullYear = 2000 + year; + const today = new Date(); + const currentMonth = today.getMonth() + 1; + const currentYear = today.getFullYear(); + + if (fullYear < currentYear || fullYear > currentYear + 20) { + return 'expirationInvalid'; + } + + if (fullYear === currentYear && month < currentMonth) { + return 'expirationInvalid'; + } + + return undefined; +} + +function configureCardExpirationEvents() { + configureBeforeinput(); + + expiration.addEventListener('input', () => { + clearError(modal); + + const raw = getRaw(); + cursor = Math.min(cursor, raw.length); + setValue(raw); + }); + + expiration.addEventListener('blur', () => { + const error = getError(getRaw()); + if (error) { + setError(modal, error); + } + }); + + expiration.addEventListener('focus', () => { + cursor = getRaw().length; + }); +} + +function configureBeforeinput() { + expiration.addEventListener('beforeinput', (e) => { + if (!e.data || !/\d/.test(e.data)) { + return; + } + + clearError(modal); + + e.preventDefault(); + + const raw = getRaw(); + + if (raw.length >= 4) { + } + + const next = raw.slice(0, cursor) + e.data + raw.slice(cursor); + cursor++; + setValue(next); + }); +} + +function configureButtons() { + expiration.addEventListener('keydown', (e) => { + const raw = getRaw(); + + switch (e.key) { + case 'Backspace': + if (cursor == 0) return; + e.preventDefault(); + clearError(modal); + cursor--; + setValue(raw.slice(0, cursor) + raw.slice(cursor + 1)); + break; + + case 'Delete': + if (cursor > -raw.length) return; + e.preventDefault(); + setValue(raw.slice(0, cursor) + raw.slice(cursor + 1)); + break; + + case 'ArrowRight': + cursor = Math.min(raw.length, cursor + 1); + render(); + break; + case 'ArrowLeft': + cursor = Math.max(0, cursor - 1); + render(); + break; + + default: + break; + } + }); +} diff --git a/src/scripts/form.js b/src/scripts/form.js new file mode 100644 index 00000000..6e7e34d9 --- /dev/null +++ b/src/scripts/form.js @@ -0,0 +1,72 @@ +'use strict'; + +import { dictionary } from './i18n'; + +export function clearAllErorrors(modal) { + modal.querySelectorAll('.form-field').forEach(clearError); +} + +export function configureFormValidations(modal) { + modal.querySelectorAll('.form-field').forEach(initFieldValidation); +} + +function initFieldValidation(field) { + const input = field.querySelector('.form__input'); + if (input) { + input.addEventListener('blur', () => { + validateField(field); + }); + + input.addEventListener('input', () => { + clearError(field); + }); + } +} + +export function validateField(field) { + const input = field.querySelector('.form__input'); + + if (!input) return true; + + const label = field.querySelector('.form-label'); + const value = input.value; + + clearError(field); + + if (input.required && !value.trim()) { + setError(field, label.getAttribute('data-error-required')); + return false; + } + + if (input.type === 'email' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { + setError(field, label.getAttribute('data-error-format')); + return false; + } + + return true; +} + +export function setError(field, errorName) { + const label = field.querySelector('.form-label'); + const language = getLanguage(); + + const error = dictionary[language][errorName]; + + label.textContent = error; + field.classList.add('form-field--error'); +} + +export function clearError(field) { + const label = field.querySelector('.form-label'); + const language = getLanguage(); + + const originalKey = label.dataset['i18n']; + + label.textContent = dictionary[language][originalKey]; + field.classList.remove('form-field--error'); +} + +function getLanguage() { + return document.querySelector('.language-dropdown__selected-label').dataset + .language; +} diff --git a/src/scripts/header-slider.js b/src/scripts/header-slider.js new file mode 100644 index 00000000..4f394b1c --- /dev/null +++ b/src/scripts/header-slider.js @@ -0,0 +1,46 @@ +'use strict'; + +const leftButton = document.querySelector('.header__slider-button--left'); +const rightButton = document.querySelector('.header__slider-button--right'); +const slider = document.querySelector('.header__slider'); +const slides = document.querySelectorAll('.header__background-image '); +const totalSlides = slides.length; + +export function addSliderForHeader() { + let currentIndex = 0; + + slider.style.setProperty('--steps', totalSlides); + + function changeSlide(direction) { + slides[currentIndex].classList.remove('header__background-image--active'); + currentIndex = (currentIndex + direction) % totalSlides; + slides[currentIndex].classList.add('header__background-image--active'); + + if (totalSlides - 1 === currentIndex) { + rightButton.classList.add('header__slider-button--disabled'); + } + + if (currentIndex < totalSlides - 1) { + rightButton.classList.remove('header__slider-button--disabled'); + } + + if (currentIndex > 0) { + leftButton.classList.remove('header__slider-button--disabled'); + } + + if (currentIndex === 0) { + leftButton.classList.add('header__slider-button--disabled'); + } + + setSlide(currentIndex); + } + + function setSlide(index) { + slider.style.setProperty('--step', index); + } + + if (leftButton && rightButton) { + leftButton.addEventListener('click', () => changeSlide(-1)); + rightButton.addEventListener('click', () => changeSlide(1)); + } +} diff --git a/src/scripts/i18n.js b/src/scripts/i18n.js new file mode 100644 index 00000000..2acfaf9f --- /dev/null +++ b/src/scripts/i18n.js @@ -0,0 +1,1771 @@ +'use strict'; + +export const dictionary = { + en: { + aboutButton: 'About', + techButton: 'Tech', + benefitsButton: 'Benefits', + contactsButton: 'Contacts', + buyButton: 'Buy Now', + languageButton: 'Language', + playButton: 'Play Video', + faqButton: 'FAQ', + helpButton: 'Help', + moreButton: 'More', + previousButton: 'Previous', + nextButton: 'Next', + englishButton: 'Englsih', + arabicButton: 'Arabic', + chineseSimplifiedButton: 'Chinese (Simplified)', + chineseTraditionalButton: 'Chinese (Simplified)', + frenchButton: 'French', + germanButton: 'German', + italianButton: 'Italian', + polishButton: 'Polish', + russianButton: 'Russian', + ukrainianButton: 'Ukrainian', + headerTitle: 'THE NEW START OF', + headerTitle2: 'VR LOCOMOTION', + headerInfoDescription: + 'Discover the most comprehensive VR Locomotion system, and unlock infinite motion in any games on any platforms!', + faqTitle1: 'What makes KAT loco different from other systems?', + faqAnswer1: + 'Despite being approached from many different angles, all traditional VR Locomotion systems including roomscale, teleportation, and free locomotion failed to provide an optimal solution capable of integrating high immersion with convenience. KAT loco does all of that without repeating their flaws. Our system offers a complete and versatile solution for an affordable price what makes it a perfect choice for home-use. It is also 100% user friendly, wireless, universally compatible, and more! It even offers decoupled head and body directions!', + faqUpdated: 'Last updated: Wed, June 12 2019 7:07 PM UTC +03:00', + faqTitle2: 'Will it decrease my motion sickness?', + faqAnswer2: + 'Yes, KAT VR omnidirectional treadmills (ODTs) are designed to significantly decrease VR motion sickness by matching your real-world walking/running to in-game movement, eliminating the sensory mismatch that causes nausea, but individual results vary, so starting slow and adapting ("getting your VR legs") is key. They work by replacing artificial joystick movement with natural locomotion, syncing your body\'s balance with the virtual world, and reducing visual-vestibular conflict.', + faqTitle3: 'Which VR headsets is it compatible with?', + faqAnswer3: + 'The KAT Loco system offers broad compatibility with most major PC VR headsets via SteamVR and Oculus Link, including Valve Index, HTC Vive/Pro, Oculus Rift/S, Pimax, and Windows Mixed Reality, plus standalone Quest 2/3/Pro (with KAT Nexus adapter for native games) and Pico 4, working with any free-locomotion game across these platforms.', + faqTitle4: 'Is it compatible with Oculus Quest?', + faqAnswer4: + "Yes, KAT Loco is compatible with Oculus Quest (Meta Quest 2/3/Pro) for both PC VR (via Link/Air Link) and standalone play, but for standalone, you need the KAT Nexus adapter to bridge the gap and enable it to work with Quest's native games, providing a PC-free experience for many titles.", + helpTitle: 'HOW CAN WE', + helpTitle2: 'HELP', + helpTitle3: 'YOU?', + helpInfoGoal: + 'Welcome to our help center. Our goal is to make the process of getting acquainted and purchase as easy and pleasant as possible. Need help with your KAT VR loco product? Many product questions can be resolved by reviewing our Product Support', + firstNameLabel: 'First Name', + firstNameRequired: 'Please, fill your name', + lastNameLabel: 'Last Name', + lastNameRequired: 'Please, fill your last name', + emailLabel: 'Email', + emailRequired: 'Please, fill your email', + emailFormatError: 'Incorrect email format', + countryLabel: 'Country', + countryRequired: 'Please, choose your country', + cityLabel: 'City', + cityRequired: 'Please, choose your city', + shippingAddressLabel: 'Shipping Address', + shippingAddressRequired: 'Please, fill your shipping address', + shippingAddress2Label: 'Shipping Address 2', + cardNumberLabel: 'Card Number', + cardNumberRequired: 'Please, fill your card number', + cardHolderLabel: 'Card Holder Name', + cardHolderRequired: 'Please, fill your card holder name', + expirationDateLabel: 'Expiration Date', + expirationDateRequired: 'Expiration required', + expirationInvalid: 'Invalid date', + cvvLabel: 'CVV', + cvvRequired: 'CVV required', + phoneLabel: 'Phone Number', + phoneRequired: 'Please, fill your phone number', + moreTitle1: 'MPRE THAN', + moreTitle2: 'GAMING!', + moreDescription: 'This also made for people who are interested in...', + educationTitle: 'EDUCATION', + educationDescription: + 'Create aducational simulations, trainings and much more with unlimited virtual space and minimum physical space', + estateTitle: 'REAL ESTATE', + estateDescription: + 'Desighn architectural projects in a deeply realistic environment allowing visitors to freely walk around, and feel their vibe', + fitnessTitle: 'FITNESS', + fitnessDescription: + 'Combine business with pleasure, and discover countless ways to stay fit while playing your favorite VR Games!', + socialTitle: 'SOCIAL INTERACTIONS', + socialDescription: + 'Hang out with your friends in the virtual world when you can’t meet space requirements', + techTitle: 'TECH', + techTitle2: 'SPECS', + sensorTitle: 'SENSOR', + sensorText: 'Weight: 35g/1.23oz each', + sensorText2: 'Dimension: 50mm/1.97in 24mm/0.94in', + sensorText3: 'Light: LED lights', + connectionTitle: 'CONNECTION', + connectionText: 'Wireless: Bluetooth 4.2', + connectionText2: 'Signal range: 5m', + connectionText3: 'Receiver: USB 2.0 and above', + batterriesTitle: 'BATTERRIES', + batterriesText: 'Type: Lthium-lon polymer batteries', + batterriesText2: 'Capacity: 370mAh', + batterriesText3: + 'Battery life: 10h of continuous use 150 hours on stand by', + batterriesText4: 'Charging: Fast charging - 1 hour', + batterriesText5: 'Charging voltage and current: 5V = 0.5A', + benefitsTitle: 'WHY', + benefitsTitle2: 'KAT LOCO?', + benefitsCardTitle: 'UNIVERSALLY COMPATIBLE', + benefitsCardText: + 'KAT Loco offers universal compatibility across all major VR headsets and platforms allowing you to play any VR game with support for Free Locomotion', + benefitsCardTitle2: 'VR/PC CONTROL PANEL', + benefitsCardText2: + 'Our Multifunctional Software allows for quick access to KAT Loco’s control panel both from a computer desktop, and directly from your VR headset.', + benefitsCardTitle3: 'WIRELESS SENSORS', + benefitsCardText3: + 'What makes it even more advanced, KAT Loco is entirely wireless, and comes with a complete system of algorithms, super durable batteries and more!', + name: 'Name', + phoneLabel2: 'Phone', + questions: 'Have any questions?', + contactsTitle: 'GET IN', + contactsTitle2: 'TOUCH', + managers: 'Our manager will reply you within 15 minutes', + messageTitle: 'Message', + feelFree: 'Please also feel free to', + contactUsButton: 'Contact us', + feelFree2: + 'directly should you need anything further. We’re happy to help.', + manual: 'Instruction manual', + warranty: 'Where to go for a warranty', + policy: 'Service Policy', + titleFaq: 'FREQUENTLY ASKED', + titleFaq2: 'QUESTIONS', + priceTitle: 'Price', + quantity: 'Quantity', + purchase: 'Purchase', + homepageButton: 'homepageButton', + paymentCompleteTitle: 'THANK YOU FOR', + paymentCompleteTitle2: 'YOUR', + paymentCompleteTitle3: 'ORDER!', + paymentCompleteText: + 'Your order has been placed and is being processed. You will recive an email with the order details', + moreSubtitle: 'This also made for people who are interested in...', + aboutTitle: 'ABOUT', + aboutTitle2: 'PRODUCT', + productDescription: + 'KAT loco is a foot-based VR locomotion system that gives complete physical control over lower-body actions, allowing you to freely walk, run, and carry out just any other movement in virtual reality.', + hello: 'Hello,', + meetTitle: 'NICE TO MEET', + meetTitle2: 'YOU!', + meetText: + 'KAT VR is an independent company dedicated to the research, development, and sales of VR Locomotion products and solutions. Founded in 2013, we have quickly grown to become one of the world’s leading professional suppliers of VR games’ & simulations’ equipment', + }, + ar: { + aboutButton: 'حول', + techButton: 'التقنية', + benefitsButton: 'المزايا', + contactsButton: 'جهات الاتصال', + buyButton: 'اشترِ الآن', + languageButton: 'اللغة', + playButton: 'تشغيل الفيديو', + faqButton: 'الأسئلة الشائعة', + helpButton: 'المساعدة', + moreButton: 'المزيد', + previousButton: 'السابق', + nextButton: 'التالي', + + englishButton: 'الإنجليزية', + arabicButton: 'العربية', + chineseSimplifiedButton: 'الصينية (المبسطة)', + chineseTraditionalButton: 'الصينية (التقليدية)', + frenchButton: 'الفرنسية', + germanButton: 'الألمانية', + italianButton: 'الإيطالية', + polishButton: 'البولندية', + russianButton: 'الروسية', + ukrainianButton: 'الأوكرانية', + + headerTitle: 'بداية جديدة لـ', + headerTitle2: 'الحركة في الواقع الافتراضي', + headerInfoDescription: + 'اكتشف أكثر أنظمة الحركة في الواقع الافتراضي شمولاً، وافتح حرية حركة غير محدودة في أي لعبة وعلى أي منصة.', + + faqTitle1: 'ما الذي يميز KAT Loco عن الأنظمة الأخرى؟', + faqAnswer1: + 'على عكس أنظمة الحركة التقليدية، يجمع KAT Loco بين الانغماس الكامل وسهولة الاستخدام. إنه حل لاسلكي ومتوافق عالميًا ومناسب للاستخدام المنزلي.', + + faqUpdated: 'آخر تحديث: 12 يونيو 2019', + + faqTitle2: 'هل يقلل من دوار الحركة؟', + faqAnswer2: + 'نعم، يساعد KAT Loco على تقليل دوار الواقع الافتراضي من خلال مزامنة الحركة الحقيقية مع الحركة داخل اللعبة.', + + faqTitle3: 'مع أي نظارات VR يتوافق النظام؟', + faqAnswer3: + 'يتوافق KAT Loco مع معظم نظارات الواقع الافتراضي الشهيرة مثل Valve Index وHTC Vive وOculus وغيرها.', + + faqTitle4: 'هل يدعم Oculus Quest؟', + faqAnswer4: + 'نعم، يعمل KAT Loco مع Meta Quest 2/3/Pro سواء عبر PC VR أو الوضع المستقل باستخدام محول KAT Nexus.', + + helpTitle: 'كيف يمكننا', + helpTitle2: 'مساعدتك', + helpTitle3: '؟', + helpInfoGoal: + 'مرحبًا بك في مركز الدعم. هدفنا هو جعل تجربة التعرف على المنتج والشراء سهلة ومريحة قدر الإمكان.', + + firstNameLabel: 'الاسم الأول', + firstNameRequired: 'يرجى إدخال الاسم', + lastNameLabel: 'اسم العائلة', + lastNameRequired: 'يرجى إدخال اسم العائلة', + emailLabel: 'البريد الإلكتروني', + emailRequired: 'يرجى إدخال البريد الإلكتروني', + emailFormatError: 'تنسيق البريد الإلكتروني غير صحيح', + + countryLabel: 'الدولة', + countryRequired: 'يرجى اختيار الدولة', + cityLabel: 'المدينة', + cityRequired: 'يرجى اختيار المدينة', + + shippingAddressLabel: 'عنوان الشحن', + shippingAddressRequired: 'يرجى إدخال عنوان الشحن', + shippingAddress2Label: 'عنوان الشحن 2', + + cardNumberLabel: 'رقم البطاقة', + cardNumberRequired: 'يرجى إدخال رقم البطاقة', + cardHolderLabel: 'اسم حامل البطاقة', + cardHolderRequired: 'يرجى إدخال اسم حامل البطاقة', + expirationDateLabel: 'تاريخ الانتهاء', + expirationDateRequired: 'حقل مطلوب', + expirationInvalid: 'تاريخ غير صالح', + cvvLabel: 'CVV', + cvvRequired: 'حقل مطلوب', + + phoneLabel: 'رقم الهاتف', + phoneRequired: 'يرجى إدخال رقم الهاتف', + + moreTitle1: 'أكثر من', + moreTitle2: 'الألعاب!', + moreSubtitle: 'مناسب أيضًا للأشخاص المهتمين بـ...', + moreDescription: + 'تم تصميم هذا النظام ليخدم مجالات متعددة إلى جانب الألعاب.', + + educationTitle: 'التعليم', + educationDescription: + 'أنشئ محاكاة تعليمية وتدريبات باستخدام مساحة افتراضية غير محدودة.', + + estateTitle: 'العقارات', + estateDescription: 'صمّم المشاريع المعمارية في بيئة واقعية مع حرية التنقل.', + + fitnessTitle: 'اللياقة البدنية', + fitnessDescription: + 'اجمع بين المتعة واللياقة البدنية أثناء لعب ألعاب الواقع الافتراضي.', + + socialTitle: 'التفاعل الاجتماعي', + socialDescription: 'تواصل مع أصدقائك في العالم الافتراضي دون قيود المكان.', + + techTitle: 'المواصفات', + techTitle2: 'التقنية', + + sensorTitle: 'المستشعر', + sensorText: 'الوزن: 35 غرام', + sensorText2: 'الأبعاد: 50 × 24 مم', + sensorText3: 'الإضاءة: مؤشرات LED', + + connectionTitle: 'الاتصال', + connectionText: 'لاسلكي: Bluetooth 4.2', + connectionText2: 'نطاق الإشارة: 5 أمتار', + connectionText3: 'المستقبل: USB 2.0 أو أعلى', + + batterriesTitle: 'البطاريات', + batterriesText: 'النوع: ليثيوم أيون', + batterriesText2: 'السعة: 370 مللي أمبير', + batterriesText3: 'حتى 10 ساعات استخدام', + batterriesText4: 'شحن سريع — ساعة واحدة', + batterriesText5: '5V = 0.5A', + + benefitsTitle: 'لماذا', + benefitsTitle2: 'KAT LOCO؟', + benefitsCardTitle: 'توافق عالمي', + benefitsCardText: + 'متوافق مع جميع منصات الواقع الافتراضي الرئيسية ويدعم الحركة الحرة.', + + benefitsCardTitle2: 'لوحة تحكم VR / PC', + benefitsCardText2: + 'تحكم كامل من الكمبيوتر أو مباشرة من داخل الواقع الافتراضي.', + + benefitsCardTitle3: 'مستشعرات لاسلكية', + benefitsCardText3: 'نظام لاسلكي بالكامل مع بطاريات قوية وخوارزميات ذكية.', + + name: 'الاسم', + phoneLabel2: 'الهاتف', + questions: 'هل لديك أسئلة؟', + contactsTitle: 'تواصل', + contactsTitle2: 'معنا', + managers: 'سيرد عليك مديرنا خلال 15 دقيقة', + messageTitle: 'الرسالة', + + feelFree: 'لا تتردد في', + contactUsButton: 'الاتصال بنا', + feelFree2: 'التواصل معنا مباشرة، نحن سعداء بمساعدتك.', + + manual: 'دليل الاستخدام', + warranty: 'الضمان', + policy: 'سياسة الخدمة', + + titleFaq: 'الأسئلة', + titleFaq2: 'الشائعة', + + priceTitle: 'السعر', + quantity: 'الكمية', + purchase: 'شراء', + homepageButton: 'الصفحة الرئيسية', + + paymentCompleteTitle: 'شكرًا على', + paymentCompleteTitle2: 'طلبك', + paymentCompleteTitle3: '!', + paymentCompleteText: + 'تم استلام طلبك وجارٍ معالجته. ستتلقى رسالة بريد إلكتروني بالتفاصيل.', + + aboutTitle: 'حول', + aboutTitle2: 'المنتج', + + productDescription: + 'KAT Loco هو نظام حركة للواقع الافتراضي يعتمد على القدمين ويمنح تحكمًا جسديًا كاملًا بحركات الجزء السفلي من الجسم.', + + hello: 'مرحبًا،', + meetTitle: 'سعداء', + meetTitle2: 'بلقائك!', + meetText: + 'KAT VR شركة مستقلة تأسست عام 2013 ومتخصصة في تطوير وبيع حلول الحركة في الواقع الافتراضي.', + }, + zhCN: { + aboutButton: '关于', + techButton: '技术', + benefitsButton: '优势', + contactsButton: '联系方式', + buyButton: '立即购买', + languageButton: '语言', + playButton: '播放视频', + faqButton: '常见问题', + helpButton: '帮助', + moreButton: '更多', + previousButton: '上一页', + nextButton: '下一页', + + englishButton: '英语', + arabicButton: '阿拉伯语', + chineseSimplifiedButton: '简体中文', + chineseTraditionalButton: '繁体中文', + frenchButton: '法语', + germanButton: '德语', + italianButton: '意大利语', + polishButton: '波兰语', + russianButton: '俄语', + ukrainianButton: '乌克兰语', + + headerTitle: '全新的', + headerTitle2: 'VR 移动方式', + headerInfoDescription: + '探索最全面的 VR 移动系统,在任何平台、任何游戏中解锁无限移动自由!', + + faqTitle1: 'KAT Loco 与其他系统有何不同?', + faqAnswer1: + '与传统的 VR 移动方式不同,KAT Loco 将高度沉浸感与使用便利性完美结合。它是一套无线、通用且适合家庭使用的完整解决方案。', + + faqUpdated: '最后更新:2019 年 6 月 12 日', + + faqTitle2: '它能减少 VR 晕动症吗?', + faqAnswer2: + '是的,KAT Loco 通过将真实行走与游戏内移动同步,有效减少 VR 晕动症。', + + faqTitle3: '支持哪些 VR 头显?', + faqAnswer3: + 'KAT Loco 兼容大多数主流 VR 头显,包括 Valve Index、HTC Vive、Oculus 等。', + + faqTitle4: '是否支持 Oculus Quest?', + faqAnswer4: + '支持。KAT Loco 可与 Meta Quest 2/3/Pro 配合使用,通过 PC VR 或使用 KAT Nexus 适配器进行独立模式体验。', + + helpTitle: '我们如何', + helpTitle2: '帮助', + helpTitle3: '您?', + helpInfoGoal: + '欢迎来到帮助中心。我们的目标是让您了解产品和购买流程变得简单而愉快。', + + firstNameLabel: '名字', + firstNameRequired: '请输入名字', + lastNameLabel: '姓氏', + lastNameRequired: '请输入姓氏', + emailLabel: '电子邮箱', + emailRequired: '请输入电子邮箱', + emailFormatError: '邮箱格式不正确', + + countryLabel: '国家', + countryRequired: '请选择国家', + cityLabel: '城市', + cityRequired: '请选择城市', + + shippingAddressLabel: '收货地址', + shippingAddressRequired: '请输入收货地址', + shippingAddress2Label: '收货地址 2', + + cardNumberLabel: '银行卡号', + cardNumberRequired: '请输入银行卡号', + cardHolderLabel: '持卡人姓名', + cardHolderRequired: '请输入持卡人姓名', + expirationDateLabel: '有效期', + expirationDateRequired: '必填项', + expirationInvalid: '日期无效', + cvvLabel: 'CVV', + cvvRequired: '必填项', + + phoneLabel: '电话号码', + phoneRequired: '请输入电话号码', + + moreTitle1: '不仅仅是', + moreTitle2: '游戏!', + moreSubtitle: '同样适合对以下领域感兴趣的人群...', + moreDescription: '该系统不仅为游戏而生,也适用于多个行业。', + + educationTitle: '教育', + educationDescription: '利用无限的虚拟空间创建教育模拟和培训项目。', + + estateTitle: '房地产', + estateDescription: + '在高度真实的环境中设计建筑项目,自由行走并感受空间氛围。', + + fitnessTitle: '健身', + fitnessDescription: '在畅玩 VR 游戏的同时保持身体健康。', + + socialTitle: '社交互动', + socialDescription: '即使无法线下相聚,也能在虚拟世界中与朋友互动。', + + techTitle: '技术', + techTitle2: '参数', + + sensorTitle: '传感器', + sensorText: '重量:35 克', + sensorText2: '尺寸:50 × 24 毫米', + sensorText3: '指示灯:LED', + + connectionTitle: '连接方式', + connectionText: '无线:Bluetooth 4.2', + connectionText2: '信号范围:5 米', + connectionText3: '接收器:USB 2.0 及以上', + + batterriesTitle: '电池', + batterriesText: '类型:锂离子电池', + batterriesText2: '容量:370 mAh', + batterriesText3: '连续使用最长 10 小时', + batterriesText4: '快速充电 — 1 小时', + batterriesText5: '充电电压与电流:5V = 0.5A', + + benefitsTitle: '为什么选择', + benefitsTitle2: 'KAT LOCO?', + benefitsCardTitle: '广泛兼容', + benefitsCardText: '支持所有主流 VR 平台,并兼容自由移动的 VR 游戏。', + + benefitsCardTitle2: 'VR / PC 控制面板', + benefitsCardText2: '可通过电脑或直接在 VR 中快速访问控制面板。', + + benefitsCardTitle3: '无线传感器', + benefitsCardText3: '完全无线设计,配备高耐用电池和智能算法。', + + name: '姓名', + phoneLabel2: '电话', + questions: '有任何问题?', + contactsTitle: '联系我们', + contactsTitle2: '', + managers: '我们的客服将在 15 分钟内回复您', + messageTitle: '留言', + + feelFree: '欢迎', + contactUsButton: '联系我们', + feelFree2: '随时直接联系,我们很乐意为您服务。', + + manual: '使用说明书', + warranty: '保修服务', + policy: '服务政策', + + titleFaq: '常见', + titleFaq2: '问题', + + priceTitle: '价格', + quantity: '数量', + purchase: '购买', + homepageButton: '首页', + + paymentCompleteTitle: '感谢您的', + paymentCompleteTitle2: '订单', + paymentCompleteTitle3: '!', + paymentCompleteText: + '您的订单已成功提交并正在处理中,详细信息将通过电子邮件发送。', + + aboutTitle: '关于', + aboutTitle2: '产品', + + productDescription: + 'KAT Loco 是一款基于脚部动作的 VR 移动系统,可实现对下半身动作的完整物理控制。', + + hello: '你好,', + meetTitle: '很高兴', + meetTitle2: '认识你!', + meetText: + 'KAT VR 是一家成立于 2013 年的独立公司,专注于 VR 移动解决方案的研发与销售。', + }, + zhTW: { + aboutButton: '關於', + techButton: '技術', + benefitsButton: '優勢', + contactsButton: '聯絡方式', + buyButton: '立即購買', + languageButton: '語言', + playButton: '播放影片', + faqButton: '常見問題', + helpButton: '幫助', + moreButton: '更多', + previousButton: '上一頁', + nextButton: '下一頁', + + englishButton: '英文', + arabicButton: '阿拉伯文', + chineseSimplifiedButton: '簡體中文', + chineseTraditionalButton: '繁體中文', + frenchButton: '法文', + germanButton: '德文', + italianButton: '義大利文', + polishButton: '波蘭文', + russianButton: '俄文', + ukrainianButton: '烏克蘭文', + + headerTitle: '全新的', + headerTitle2: 'VR 移動方式', + headerInfoDescription: + '探索最完整的 VR 移動系統,在任何平台、任何遊戲中解鎖無限行動自由!', + + faqTitle1: 'KAT Loco 與其他系統有何不同?', + faqAnswer1: + '與傳統的 VR 移動方式相比,KAT Loco 結合了高度沉浸感與操作便利性,是一套無線、通用且適合居家使用的完整解決方案。', + + faqUpdated: '最後更新:2019 年 6 月 12 日', + + faqTitle2: '它能減少 VR 暈動症嗎?', + faqAnswer2: + '可以,KAT Loco 透過同步真實行走與遊戲內移動,有效降低 VR 暈動症。', + + faqTitle3: '支援哪些 VR 頭戴裝置?', + faqAnswer3: + 'KAT Loco 相容於多數主流 VR 頭顯,包括 Valve Index、HTC Vive、Oculus 等。', + + faqTitle4: '是否支援 Oculus Quest?', + faqAnswer4: + '支援。KAT Loco 可搭配 Meta Quest 2/3/Pro 使用,透過 PC VR 或使用 KAT Nexus 轉接器進行獨立模式體驗。', + + helpTitle: '我們如何', + helpTitle2: '協助', + helpTitle3: '您?', + helpInfoGoal: + '歡迎來到支援中心。我們的目標是讓您更輕鬆、愉快地了解產品並完成購買。', + + firstNameLabel: '名字', + firstNameRequired: '請輸入名字', + lastNameLabel: '姓氏', + lastNameRequired: '請輸入姓氏', + emailLabel: '電子郵件', + emailRequired: '請輸入電子郵件', + emailFormatError: '電子郵件格式不正確', + + countryLabel: '國家', + countryRequired: '請選擇國家', + cityLabel: '城市', + cityRequired: '請選擇城市', + + shippingAddressLabel: '收貨地址', + shippingAddressRequired: '請輸入收貨地址', + shippingAddress2Label: '收貨地址 2', + + cardNumberLabel: '信用卡號碼', + cardNumberRequired: '請輸入信用卡號碼', + cardHolderLabel: '持卡人姓名', + cardHolderRequired: '請輸入持卡人姓名', + expirationDateLabel: '有效期限', + expirationDateRequired: '必填欄位', + expirationInvalid: '日期無效', + cvvLabel: 'CVV', + cvvRequired: '必填欄位', + + phoneLabel: '電話號碼', + phoneRequired: '請輸入電話號碼', + + moreTitle1: '不只是', + moreTitle2: '遊戲!', + moreSubtitle: '同樣適合對以下領域感興趣的人士...', + moreDescription: '此系統不僅適用於遊戲,也可用於多種應用場景。', + + educationTitle: '教育', + educationDescription: '利用無限的虛擬空間建立教育模擬與培訓內容。', + + estateTitle: '不動產', + estateDescription: + '在高度真實的環境中設計建築專案,自由行走並體驗空間感受。', + + fitnessTitle: '健身', + fitnessDescription: '在享受 VR 遊戲的同時保持良好體能狀態。', + + socialTitle: '社交互動', + socialDescription: '即使無法實體見面,也能在虛擬世界中與朋友互動。', + + techTitle: '技術', + techTitle2: '規格', + + sensorTitle: '感測器', + sensorText: '重量:35 公克', + sensorText2: '尺寸:50 × 24 毫米', + sensorText3: '燈光:LED 指示燈', + + connectionTitle: '連線方式', + connectionText: '無線:Bluetooth 4.2', + connectionText2: '訊號範圍:5 公尺', + connectionText3: '接收器:USB 2.0 以上', + + batterriesTitle: '電池', + batterriesText: '類型:鋰離子電池', + batterriesText2: '容量:370 mAh', + batterriesText3: '最長可連續使用 10 小時', + batterriesText4: '快速充電 — 1 小時', + batterriesText5: '充電電壓與電流:5V = 0.5A', + + benefitsTitle: '為什麼選擇', + benefitsTitle2: 'KAT LOCO?', + benefitsCardTitle: '廣泛相容', + benefitsCardText: '支援所有主流 VR 平台,並相容自由移動的 VR 遊戲。', + + benefitsCardTitle2: 'VR / PC 控制面板', + benefitsCardText2: '可透過電腦或直接在 VR 裝置中快速存取控制面板。', + + benefitsCardTitle3: '無線感測器', + benefitsCardText3: '全無線設計,搭配高耐用電池與智慧演算法。', + + name: '姓名', + phoneLabel2: '電話', + questions: '有任何問題嗎?', + contactsTitle: '聯絡', + contactsTitle2: '我們', + managers: '我們的客服將在 15 分鐘內回覆您', + messageTitle: '訊息', + + feelFree: '歡迎', + contactUsButton: '聯絡我們', + feelFree2: '隨時直接聯繫,我們很樂意協助您。', + + manual: '使用手冊', + warranty: '保固服務', + policy: '服務政策', + + titleFaq: '常見', + titleFaq2: '問題', + + priceTitle: '價格', + quantity: '數量', + purchase: '購買', + homepageButton: '首頁', + + paymentCompleteTitle: '感謝您的', + paymentCompleteTitle2: '訂單', + paymentCompleteTitle3: '!', + paymentCompleteText: + '您的訂單已成功提交並正在處理中,詳細資訊將透過電子郵件寄送。', + + aboutTitle: '關於', + aboutTitle2: '產品', + + productDescription: + 'KAT Loco 是一套以腳部動作為基礎的 VR 移動系統,可實現對下半身動作的完整實體控制。', + + hello: '您好,', + meetTitle: '很高興', + meetTitle2: '認識您!', + meetText: + 'KAT VR 是一家成立於 2013 年的獨立公司,專注於 VR 移動解決方案的研發與銷售。', + }, + fr: { + aboutButton: 'À propos', + techButton: 'Technologie', + benefitsButton: 'Avantages', + contactsButton: 'Contacts', + buyButton: 'Acheter maintenant', + languageButton: 'Langue', + playButton: 'Lire la vidéo', + faqButton: 'FAQ', + helpButton: 'Aide', + moreButton: 'Plus', + previousButton: 'Précédent', + nextButton: 'Suivant', + + englishButton: 'Anglais', + arabicButton: 'Arabe', + chineseSimplifiedButton: 'Chinois (simplifié)', + chineseTraditionalButton: 'Chinois (traditionnel)', + frenchButton: 'Français', + germanButton: 'Allemand', + italianButton: 'Italien', + polishButton: 'Polonais', + russianButton: 'Russe', + ukrainianButton: 'Ukrainien', + + headerTitle: 'UN NOUVEAU DÉPART POUR', + headerTitle2: 'LA LOCOMOTION VR', + headerInfoDescription: + 'Découvrez le système de locomotion VR le plus complet et débloquez une liberté de mouvement infinie dans tous les jeux et sur toutes les plateformes !', + + faqTitle1: 'Qu’est-ce qui distingue KAT Loco des autres systèmes ?', + faqAnswer1: + 'Contrairement aux systèmes de locomotion VR traditionnels, KAT Loco combine une immersion élevée avec une utilisation confortable. Il s’agit d’une solution complète, sans fil, universellement compatible et adaptée à un usage domestique.', + + faqUpdated: 'Dernière mise à jour : 12 juin 2019', + + faqTitle2: 'Réduit-il le mal des transports en VR ?', + faqAnswer2: + 'Oui, KAT Loco aide à réduire la cinétose en synchronisant les mouvements réels avec les déplacements dans le monde virtuel.', + + faqTitle3: 'Avec quels casques VR est-il compatible ?', + faqAnswer3: + 'KAT Loco est compatible avec la plupart des casques VR populaires, notamment Valve Index, HTC Vive, Oculus et autres.', + + faqTitle4: 'Est-il compatible avec Oculus Quest ?', + faqAnswer4: + 'Oui, KAT Loco fonctionne avec Meta Quest 2/3/Pro, en PC VR ou en mode autonome à l’aide de l’adaptateur KAT Nexus.', + + helpTitle: 'COMMENT POUVONS-NOUS', + helpTitle2: 'VOUS AIDER', + helpTitle3: '?', + helpInfoGoal: + 'Bienvenue dans notre centre d’assistance. Notre objectif est de rendre la découverte et l’achat de nos produits aussi simples et agréables que possible.', + + firstNameLabel: 'Prénom', + firstNameRequired: 'Veuillez saisir votre prénom', + lastNameLabel: 'Nom', + lastNameRequired: 'Veuillez saisir votre nom', + emailLabel: 'Email', + emailRequired: 'Veuillez saisir votre email', + emailFormatError: 'Format d’email incorrect', + + countryLabel: 'Pays', + countryRequired: 'Veuillez choisir un pays', + cityLabel: 'Ville', + cityRequired: 'Veuillez choisir une ville', + + shippingAddressLabel: 'Adresse de livraison', + shippingAddressRequired: 'Veuillez saisir votre adresse de livraison', + shippingAddress2Label: 'Adresse de livraison 2', + + cardNumberLabel: 'Numéro de carte', + cardNumberRequired: 'Veuillez saisir votre numéro de carte', + cardHolderLabel: 'Nom du titulaire', + cardHolderRequired: 'Veuillez saisir le nom du titulaire', + expirationDateLabel: 'Date d’expiration', + expirationDateRequired: 'Champ obligatoire', + expirationInvalid: 'Date invalide', + cvvLabel: 'CVV', + cvvRequired: 'Champ obligatoire', + + phoneLabel: 'Numéro de téléphone', + phoneRequired: 'Veuillez saisir votre numéro de téléphone', + + moreTitle1: 'BIEN PLUS QUE', + moreTitle2: 'DU JEU !', + moreSubtitle: 'Convient également aux personnes intéressées par...', + moreDescription: + 'Ce système est conçu non seulement pour le jeu, mais aussi pour de nombreux autres usages.', + + educationTitle: 'ÉDUCATION', + educationDescription: + 'Créez des simulations éducatives et des formations avec un espace virtuel illimité.', + + estateTitle: 'IMMOBILIER', + estateDescription: + 'Concevez des projets architecturaux dans un environnement réaliste avec une liberté de déplacement totale.', + + fitnessTitle: 'FITNESS', + fitnessDescription: + 'Restez en forme tout en profitant de vos jeux VR préférés.', + + socialTitle: 'INTERACTIONS SOCIALES', + socialDescription: + 'Retrouvez vos amis dans le monde virtuel même lorsque les rencontres physiques sont impossibles.', + + techTitle: 'TECHNOLOGIE', + techTitle2: 'SPÉCIFICATIONS', + + sensorTitle: 'CAPTEUR', + sensorText: 'Poids : 35 g', + sensorText2: 'Dimensions : 50 × 24 mm', + sensorText3: 'Lumière : indicateurs LED', + + connectionTitle: 'CONNEXION', + connectionText: 'Sans fil : Bluetooth 4.2', + connectionText2: 'Portée du signal : 5 m', + connectionText3: 'Récepteur : USB 2.0 et plus', + + batterriesTitle: 'BATTERIES', + batterriesText: 'Type : lithium-ion', + batterriesText2: 'Capacité : 370 mAh', + batterriesText3: 'Jusqu’à 10 heures d’utilisation', + batterriesText4: 'Charge rapide — 1 heure', + batterriesText5: 'Tension et courant : 5V = 0.5A', + + benefitsTitle: 'POURQUOI', + benefitsTitle2: 'KAT LOCO ?', + benefitsCardTitle: 'COMPATIBILITÉ UNIVERSELLE', + benefitsCardText: + 'Compatible avec toutes les principales plateformes VR et les jeux à locomotion libre.', + + benefitsCardTitle2: 'PANNEAU DE CONTRÔLE VR / PC', + benefitsCardText2: + 'Accédez rapidement au panneau de contrôle depuis un PC ou directement en VR.', + + benefitsCardTitle3: 'CAPTEURS SANS FIL', + benefitsCardText3: + 'Système entièrement sans fil avec des batteries durables et des algorithmes intelligents.', + + name: 'Nom', + phoneLabel2: 'Téléphone', + questions: 'Des questions ?', + contactsTitle: 'PRENEZ', + contactsTitle2: 'CONTACT', + managers: 'Notre responsable vous répondra sous 15 minutes', + messageTitle: 'Message', + + feelFree: 'N’hésitez pas à', + contactUsButton: 'Nous contacter', + feelFree2: 'nous contacter directement, nous sommes ravis de vous aider.', + + manual: 'Manuel d’utilisation', + warranty: 'Garantie', + policy: 'Politique de service', + + titleFaq: 'QUESTIONS', + titleFaq2: 'FRÉQUENTES', + + priceTitle: 'Prix', + quantity: 'Quantité', + purchase: 'Acheter', + homepageButton: 'Page d’accueil', + + paymentCompleteTitle: 'MERCI POUR', + paymentCompleteTitle2: 'VOTRE', + paymentCompleteTitle3: 'COMMANDE !', + paymentCompleteText: + 'Votre commande a été passée et est en cours de traitement. Vous recevrez un email avec les détails.', + + aboutTitle: 'À PROPOS', + aboutTitle2: 'DU PRODUIT', + + productDescription: + 'KAT Loco est un système de locomotion VR basé sur les mouvements des pieds, offrant un contrôle physique complet du bas du corps.', + + hello: 'Bonjour,', + meetTitle: 'RAVI DE', + meetTitle2: 'VOUS RENCONTRER !', + meetText: + 'KAT VR est une entreprise indépendante fondée en 2013, spécialisée dans le développement et la vente de solutions de locomotion VR.', + }, + de: { + aboutButton: 'Über uns', + techButton: 'Technologie', + benefitsButton: 'Vorteile', + contactsButton: 'Kontakt', + buyButton: 'Jetzt kaufen', + languageButton: 'Sprache', + playButton: 'Video abspielen', + faqButton: 'FAQ', + helpButton: 'Hilfe', + moreButton: 'Mehr', + previousButton: 'Zurück', + nextButton: 'Weiter', + + englishButton: 'Englisch', + arabicButton: 'Arabisch', + chineseSimplifiedButton: 'Chinesisch (vereinfacht)', + chineseTraditionalButton: 'Chinesisch (traditionell)', + frenchButton: 'Französisch', + germanButton: 'Deutsch', + italianButton: 'Italienisch', + polishButton: 'Polnisch', + russianButton: 'Russisch', + ukrainianButton: 'Ukrainisch', + + headerTitle: 'DER NEUE START DER', + headerTitle2: 'VR-FORTBEWEGUNG', + headerInfoDescription: + 'Entdecken Sie das umfassendste VR-Fortbewegungssystem und erleben Sie unbegrenzte Bewegungsfreiheit in allen Spielen auf allen Plattformen!', + + faqTitle1: 'Was unterscheidet KAT Loco von anderen Systemen?', + faqAnswer1: + 'Im Gegensatz zu herkömmlichen VR-Fortbewegungssystemen vereint KAT Loco hohe Immersion mit maximalem Komfort. Es ist eine kabellose, universell kompatible und für den Heimgebrauch geeignete Komplettlösung.', + + faqUpdated: 'Letzte Aktualisierung: 12. Juni 2019', + + faqTitle2: 'Reduziert es VR-Bewegungsübelkeit?', + faqAnswer2: + 'Ja, KAT Loco hilft, VR-Übelkeit zu reduzieren, indem reale Bewegungen mit der Bewegung im virtuellen Raum synchronisiert werden.', + + faqTitle3: 'Mit welchen VR-Headsets ist es kompatibel?', + faqAnswer3: + 'KAT Loco ist mit den meisten gängigen VR-Headsets kompatibel, darunter Valve Index, HTC Vive, Oculus und weitere.', + + faqTitle4: 'Ist es mit Oculus Quest kompatibel?', + faqAnswer4: + 'Ja, KAT Loco funktioniert mit Meta Quest 2/3/Pro sowohl im PC-VR-Modus als auch im Standalone-Betrieb mit dem KAT-Nexus-Adapter.', + + helpTitle: 'WIE KÖNNEN WIR', + helpTitle2: 'IHNEN HELFEN', + helpTitle3: '?', + helpInfoGoal: + 'Willkommen im Hilfezentrum. Unser Ziel ist es, den Kennenlern- und Kaufprozess so einfach und angenehm wie möglich zu gestalten.', + + firstNameLabel: 'Vorname', + firstNameRequired: 'Bitte geben Sie Ihren Vornamen ein', + lastNameLabel: 'Nachname', + lastNameRequired: 'Bitte geben Sie Ihren Nachnamen ein', + emailLabel: 'E-Mail', + emailRequired: 'Bitte geben Sie Ihre E-Mail ein', + emailFormatError: 'Ungültiges E-Mail-Format', + + countryLabel: 'Land', + countryRequired: 'Bitte wählen Sie ein Land', + cityLabel: 'Stadt', + cityRequired: 'Bitte wählen Sie eine Stadt', + + shippingAddressLabel: 'Lieferadresse', + shippingAddressRequired: 'Bitte geben Sie Ihre Lieferadresse ein', + shippingAddress2Label: 'Lieferadresse 2', + + cardNumberLabel: 'Kartennummer', + cardNumberRequired: 'Bitte geben Sie Ihre Kartennummer ein', + cardHolderLabel: 'Name des Karteninhabers', + cardHolderRequired: 'Bitte geben Sie den Namen des Karteninhabers ein', + expirationDateLabel: 'Ablaufdatum', + expirationDateRequired: 'Pflichtfeld', + expirationInvalid: 'Ungültiges Datum', + cvvLabel: 'CVV', + cvvRequired: 'Pflichtfeld', + + phoneLabel: 'Telefonnummer', + phoneRequired: 'Bitte geben Sie Ihre Telefonnummer ein', + + moreTitle1: 'MEHR ALS', + moreTitle2: 'NUR GAMING!', + moreSubtitle: + 'Auch geeignet für Personen, die sich für Folgendes interessieren...', + moreDescription: + 'Dieses System wurde nicht nur für Spiele entwickelt, sondern auch für viele weitere Anwendungsbereiche.', + + educationTitle: 'BILDUNG', + educationDescription: + 'Erstellen Sie Lernsimulationen und Trainings mit unbegrenztem virtuellem Raum.', + + estateTitle: 'IMMOBILIEN', + estateDescription: + 'Entwerfen Sie Architekturprojekte in einer realistischen Umgebung mit freier Bewegung.', + + fitnessTitle: 'FITNESS', + fitnessDescription: + 'Bleiben Sie fit und aktiv, während Sie Ihre Lieblings-VR-Spiele spielen.', + + socialTitle: 'SOZIALE INTERAKTION', + socialDescription: + 'Treffen Sie Freunde in der virtuellen Welt, auch wenn reale Treffen nicht möglich sind.', + + techTitle: 'TECHNIK', + techTitle2: 'SPEZIFIKATIONEN', + + sensorTitle: 'SENSOR', + sensorText: 'Gewicht: 35 g', + sensorText2: 'Abmessungen: 50 × 24 mm', + sensorText3: 'Beleuchtung: LED-Indikatoren', + + connectionTitle: 'VERBINDUNG', + connectionText: 'Kabellos: Bluetooth 4.2', + connectionText2: 'Reichweite: 5 m', + connectionText3: 'Empfänger: USB 2.0 oder höher', + + batterriesTitle: 'BATTERIEN', + batterriesText: 'Typ: Lithium-Ionen', + batterriesText2: 'Kapazität: 370 mAh', + batterriesText3: 'Bis zu 10 Stunden Betriebszeit', + batterriesText4: 'Schnellladen — 1 Stunde', + batterriesText5: 'Ladespannung und Strom: 5V = 0.5A', + + benefitsTitle: 'WARUM', + benefitsTitle2: 'KAT LOCO?', + benefitsCardTitle: 'UNIVERSELLE KOMPATIBILITÄT', + benefitsCardText: + 'Kompatibel mit allen gängigen VR-Plattformen und Spielen mit freier Fortbewegung.', + + benefitsCardTitle2: 'VR- / PC-STEUERPANEL', + benefitsCardText2: + 'Schneller Zugriff auf das Kontrollpanel vom PC oder direkt aus der VR-Umgebung.', + + benefitsCardTitle3: 'KABELLOSE SENSOREN', + benefitsCardText3: + 'Vollständig kabelloses System mit langlebigen Batterien und intelligenten Algorithmen.', + + name: 'Name', + phoneLabel2: 'Telefon', + questions: 'Haben Sie Fragen?', + contactsTitle: 'KONTAKT', + contactsTitle2: 'AUFNEHMEN', + managers: 'Unser Manager antwortet Ihnen innerhalb von 15 Minuten', + messageTitle: 'Nachricht', + + feelFree: 'Zögern Sie nicht,', + contactUsButton: 'Kontaktieren Sie uns', + feelFree2: 'uns direkt zu kontaktieren – wir helfen Ihnen gerne.', + + manual: 'Bedienungsanleitung', + warranty: 'Garantie', + policy: 'Service-Richtlinie', + + titleFaq: 'HÄUFIG', + titleFaq2: 'GESTELLTE FRAGEN', + + priceTitle: 'Preis', + quantity: 'Menge', + purchase: 'Kaufen', + homepageButton: 'Startseite', + + paymentCompleteTitle: 'VIELEN DANK FÜR', + paymentCompleteTitle2: 'IHRE', + paymentCompleteTitle3: 'BESTELLUNG!', + paymentCompleteText: + 'Ihre Bestellung wurde aufgegeben und wird bearbeitet. Sie erhalten eine E-Mail mit den Details.', + + aboutTitle: 'ÜBER', + aboutTitle2: 'DAS PRODUKT', + + productDescription: + 'KAT Loco ist ein fußbasiertes VR-Fortbewegungssystem, das eine vollständige physische Kontrolle über die Bewegungen des Unterkörpers ermöglicht.', + + hello: 'Hallo,', + meetTitle: 'SCHÖN', + meetTitle2: 'SIE KENNENZULERNEN!', + meetText: + 'KAT VR ist ein unabhängiges Unternehmen, das 2013 gegründet wurde und sich auf die Entwicklung und den Vertrieb von VR-Fortbewegungslösungen spezialisiert hat.', + }, + it: { + aboutButton: 'Chi siamo', + techButton: 'Tecnologia', + benefitsButton: 'Vantaggi', + contactsButton: 'Contatti', + buyButton: 'Acquista ora', + languageButton: 'Lingua', + playButton: 'Riproduci video', + faqButton: 'FAQ', + helpButton: 'Aiuto', + moreButton: 'Altro', + previousButton: 'Precedente', + nextButton: 'Successivo', + + englishButton: 'Inglese', + arabicButton: 'Arabo', + chineseSimplifiedButton: 'Cinese (semplificato)', + chineseTraditionalButton: 'Cinese (tradizionale)', + frenchButton: 'Francese', + germanButton: 'Tedesco', + italianButton: 'Italiano', + polishButton: 'Polacco', + russianButton: 'Russo', + ukrainianButton: 'Ucraino', + + headerTitle: 'UN NUOVO INIZIO PER', + headerTitle2: 'LA LOCOMOZIONE VR', + headerInfoDescription: + 'Scopri il sistema di locomozione VR più completo e sblocca una libertà di movimento infinita in qualsiasi gioco e su qualsiasi piattaforma!', + + faqTitle1: 'Cosa rende KAT Loco diverso dagli altri sistemi?', + faqAnswer1: + 'A differenza dei sistemi di locomozione VR tradizionali, KAT Loco combina un’elevata immersione con un utilizzo confortevole. È una soluzione completa, wireless, universalmente compatibile e adatta all’uso domestico.', + + faqUpdated: 'Ultimo aggiornamento: 12 giugno 2019', + + faqTitle2: 'Riduce il malessere da movimento in VR?', + faqAnswer2: + 'Sì, KAT Loco aiuta a ridurre la nausea in VR sincronizzando i movimenti reali con quelli nel mondo virtuale.', + + faqTitle3: 'Con quali visori VR è compatibile?', + faqAnswer3: + 'KAT Loco è compatibile con la maggior parte dei visori VR più diffusi, inclusi Valve Index, HTC Vive, Oculus e altri.', + + faqTitle4: 'È compatibile con Oculus Quest?', + faqAnswer4: + 'Sì, KAT Loco funziona con Meta Quest 2/3/Pro sia in modalità PC VR sia in modalità standalone tramite l’adattatore KAT Nexus.', + + helpTitle: 'COME POSSIAMO', + helpTitle2: 'AIUTARTI', + helpTitle3: '?', + helpInfoGoal: + 'Benvenuto nel centro assistenza. Il nostro obiettivo è rendere il processo di scoperta e acquisto il più semplice e piacevole possibile.', + + firstNameLabel: 'Nome', + firstNameRequired: 'Inserisci il nome', + lastNameLabel: 'Cognome', + lastNameRequired: 'Inserisci il cognome', + emailLabel: 'Email', + emailRequired: 'Inserisci l’email', + emailFormatError: 'Formato email non valido', + + countryLabel: 'Paese', + countryRequired: 'Seleziona il paese', + cityLabel: 'Città', + cityRequired: 'Seleziona la città', + + shippingAddressLabel: 'Indirizzo di spedizione', + shippingAddressRequired: 'Inserisci l’indirizzo di spedizione', + shippingAddress2Label: 'Indirizzo di spedizione 2', + + cardNumberLabel: 'Numero della carta', + cardNumberRequired: 'Inserisci il numero della carta', + cardHolderLabel: 'Nome del titolare', + cardHolderRequired: 'Inserisci il nome del titolare', + expirationDateLabel: 'Data di scadenza', + expirationDateRequired: 'Campo obbligatorio', + expirationInvalid: 'Data non valida', + cvvLabel: 'CVV', + cvvRequired: 'Campo obbligatorio', + + phoneLabel: 'Numero di telefono', + phoneRequired: 'Inserisci il numero di telefono', + + moreTitle1: 'MOLTO PIÙ CHE', + moreTitle2: 'GAMING!', + moreSubtitle: 'Adatto anche a chi è interessato a...', + moreDescription: + 'Questo sistema non è pensato solo per il gioco, ma anche per molti altri ambiti.', + + educationTitle: 'ISTRUZIONE', + educationDescription: + 'Crea simulazioni educative e corsi di formazione con uno spazio virtuale illimitato.', + + estateTitle: 'IMMOBILIARE', + estateDescription: + 'Progetta spazi architettonici in un ambiente realistico con libertà di movimento.', + + fitnessTitle: 'FITNESS', + fitnessDescription: + 'Mantieniti in forma divertendoti con i tuoi giochi VR preferiti.', + + socialTitle: 'INTERAZIONE SOCIALE', + socialDescription: + 'Incontra i tuoi amici nel mondo virtuale anche quando non è possibile vedersi di persona.', + + techTitle: 'TECNOLOGIA', + techTitle2: 'SPECIFICHE', + + sensorTitle: 'SENSORE', + sensorText: 'Peso: 35 g', + sensorText2: 'Dimensioni: 50 × 24 mm', + sensorText3: 'Luci: indicatori LED', + + connectionTitle: 'CONNESSIONE', + connectionText: 'Wireless: Bluetooth 4.2', + connectionText2: 'Portata del segnale: 5 m', + connectionText3: 'Ricevitore: USB 2.0 o superiore', + + batterriesTitle: 'BATTERIE', + batterriesText: 'Tipo: ioni di litio', + batterriesText2: 'Capacità: 370 mAh', + batterriesText3: 'Fino a 10 ore di utilizzo', + batterriesText4: 'Ricarica rapida — 1 ora', + batterriesText5: 'Tensione e corrente: 5V = 0.5A', + + benefitsTitle: 'PERCHÉ', + benefitsTitle2: 'KAT LOCO?', + benefitsCardTitle: 'COMPATIBILITÀ UNIVERSALE', + benefitsCardText: + 'Compatibile con tutte le principali piattaforme VR e con i giochi che supportano la locomozione libera.', + + benefitsCardTitle2: 'PANNELLO DI CONTROLLO VR / PC', + benefitsCardText2: + 'Accesso rapido al pannello di controllo dal PC o direttamente all’interno della VR.', + + benefitsCardTitle3: 'SENSORI WIRELESS', + benefitsCardText3: + 'Sistema completamente wireless con batterie durevoli e algoritmi intelligenti.', + + name: 'Nome', + phoneLabel2: 'Telefono', + questions: 'Hai domande?', + contactsTitle: 'CONTATTACI', + contactsTitle2: '', + managers: 'Un nostro responsabile ti risponderà entro 15 minuti', + messageTitle: 'Messaggio', + + feelFree: 'Non esitare a', + contactUsButton: 'Contattarci', + feelFree2: 'contattarci direttamente, saremo felici di aiutarti.', + + manual: 'Manuale di istruzioni', + warranty: 'Garanzia', + policy: 'Politica di servizio', + + titleFaq: 'DOMANDE', + titleFaq2: 'FREQUENTI', + + priceTitle: 'Prezzo', + quantity: 'Quantità', + purchase: 'Acquista', + homepageButton: 'Home', + + paymentCompleteTitle: 'GRAZIE PER IL', + paymentCompleteTitle2: 'TUO', + paymentCompleteTitle3: 'ORDINE!', + paymentCompleteText: + 'Il tuo ordine è stato effettuato ed è in fase di elaborazione. Riceverai un’email con i dettagli.', + + aboutTitle: 'INFORMAZIONI SUL', + aboutTitle2: 'PRODOTTO', + + productDescription: + 'KAT Loco è un sistema di locomozione VR basato sui movimenti dei piedi che offre un controllo fisico completo della parte inferiore del corpo.', + + hello: 'Ciao,', + meetTitle: 'PIACERE DI', + meetTitle2: 'CONOSCERTI!', + meetText: + 'KAT VR è un’azienda indipendente fondata nel 2013, specializzata nello sviluppo e nella vendita di soluzioni di locomozione VR.', + }, + pl: { + aboutButton: 'O nas', + techButton: 'Technologia', + benefitsButton: 'Zalety', + contactsButton: 'Kontakt', + buyButton: 'Kup teraz', + languageButton: 'Język', + playButton: 'Odtwórz wideo', + faqButton: 'FAQ', + helpButton: 'Pomoc', + moreButton: 'Więcej', + previousButton: 'Poprzedni', + nextButton: 'Następny', + + englishButton: 'Angielski', + arabicButton: 'Arabski', + chineseSimplifiedButton: 'Chiński (uproszczony)', + chineseTraditionalButton: 'Chiński (tradycyjny)', + frenchButton: 'Francuski', + germanButton: 'Niemiecki', + italianButton: 'Włoski', + polishButton: 'Polski', + russianButton: 'Rosyjski', + ukrainianButton: 'Ukraiński', + + headerTitle: 'NOWY START', + headerTitle2: 'LOKOMOCJI VR', + headerInfoDescription: + 'Odkryj najbardziej kompleksowy system lokomocji VR i zyskaj nieograniczoną swobodę ruchu w każdej grze i na każdej platformie!', + + faqTitle1: 'Co wyróżnia KAT Loco na tle innych systemów?', + faqAnswer1: + 'W przeciwieństwie do tradycyjnych systemów lokomocji VR, KAT Loco łączy wysoki poziom immersji z wygodą użytkowania. To kompletne, bezprzewodowe i uniwersalnie kompatybilne rozwiązanie idealne do użytku domowego.', + + faqUpdated: 'Ostatnia aktualizacja: 12 czerwca 2019', + + faqTitle2: 'Czy zmniejsza chorobę lokomocyjną w VR?', + faqAnswer2: + 'Tak, KAT Loco pomaga zmniejszyć nudności w VR, synchronizując rzeczywiste ruchy ciała z ruchem w świecie wirtualnym.', + + faqTitle3: 'Z jakimi goglami VR jest kompatybilny?', + faqAnswer3: + 'KAT Loco jest kompatybilny z większością popularnych gogli VR, w tym Valve Index, HTC Vive, Oculus i innymi.', + + faqTitle4: 'Czy jest kompatybilny z Oculus Quest?', + faqAnswer4: + 'Tak, KAT Loco działa z Meta Quest 2/3/Pro zarówno w trybie PC VR, jak i samodzielnym przy użyciu adaptera KAT Nexus.', + + helpTitle: 'JAK MOŻEMY', + helpTitle2: 'CI POMÓC', + helpTitle3: '?', + helpInfoGoal: + 'Witamy w centrum pomocy. Naszym celem jest uczynienie procesu poznawania produktu i zakupu jak najprostszym i najprzyjemniejszym.', + + firstNameLabel: 'Imię', + firstNameRequired: 'Proszę podać imię', + lastNameLabel: 'Nazwisko', + lastNameRequired: 'Proszę podać nazwisko', + emailLabel: 'Email', + emailRequired: 'Proszę podać email', + emailFormatError: 'Nieprawidłowy format email', + + countryLabel: 'Kraj', + countryRequired: 'Wybierz kraj', + cityLabel: 'Miasto', + cityRequired: 'Wybierz miasto', + + shippingAddressLabel: 'Adres dostawy', + shippingAddressRequired: 'Proszę podać adres dostawy', + shippingAddress2Label: 'Adres dostawy 2', + + cardNumberLabel: 'Numer karty', + cardNumberRequired: 'Proszę podać numer karty', + cardHolderLabel: 'Imię i nazwisko posiadacza karty', + cardHolderRequired: 'Proszę podać dane posiadacza karty', + expirationDateLabel: 'Data ważności', + expirationDateRequired: 'Pole wymagane', + expirationInvalid: 'Nieprawidłowa data', + cvvLabel: 'CVV', + cvvRequired: 'Pole wymagane', + + phoneLabel: 'Numer telefonu', + phoneRequired: 'Proszę podać numer telefonu', + + moreTitle1: 'ZNACZNIE WIĘCEJ NIŻ', + moreTitle2: 'GRANIE!', + moreSubtitle: 'Odpowiednie również dla osób zainteresowanych...', + moreDescription: + 'Ten system został zaprojektowany nie tylko do gier, ale także do wielu innych zastosowań.', + + educationTitle: 'EDUKACJA', + educationDescription: + 'Twórz symulacje edukacyjne i szkolenia z wykorzystaniem nieograniczonej przestrzeni wirtualnej.', + + estateTitle: 'NIERUCHOMOŚCI', + estateDescription: + 'Projektuj przestrzenie architektoniczne w realistycznym środowisku z pełną swobodą poruszania się.', + + fitnessTitle: 'FITNESS', + fitnessDescription: 'Zadbaj o formę, grając w swoje ulubione gry VR.', + + socialTitle: 'INTERAKCJE SPOŁECZNE', + socialDescription: + 'Spotykaj się z przyjaciółmi w świecie wirtualnym, nawet gdy nie jest to możliwe w rzeczywistości.', + + techTitle: 'TECHNOLOGIA', + techTitle2: 'SPECYFIKACJA', + + sensorTitle: 'CZUJNIK', + sensorText: 'Waga: 35 g', + sensorText2: 'Wymiary: 50 × 24 mm', + sensorText3: 'Oświetlenie: diody LED', + + connectionTitle: 'POŁĄCZENIE', + connectionText: 'Bezprzewodowe: Bluetooth 4.2', + connectionText2: 'Zasięg sygnału: 5 m', + connectionText3: 'Odbiornik: USB 2.0 lub nowszy', + + batterriesTitle: 'BATERIE', + batterriesText: 'Typ: litowo-jonowe', + batterriesText2: 'Pojemność: 370 mAh', + batterriesText3: 'Do 10 godzin pracy', + batterriesText4: 'Szybkie ładowanie — 1 godzina', + batterriesText5: 'Napięcie i prąd: 5V = 0.5A', + + benefitsTitle: 'DLACZEGO', + benefitsTitle2: 'KAT LOCO?', + benefitsCardTitle: 'UNIWERSALNA KOMPATYBILNOŚĆ', + benefitsCardText: + 'Kompatybilny ze wszystkimi głównymi platformami VR oraz grami obsługującymi swobodną lokomocję.', + + benefitsCardTitle2: 'PANEL STEROWANIA VR / PC', + benefitsCardText2: + 'Szybki dostęp do panelu sterowania z komputera lub bezpośrednio z VR.', + + benefitsCardTitle3: 'BEZPRZEWODOWE CZUJNIKI', + benefitsCardText3: + 'Całkowicie bezprzewodowy system z wydajnymi bateriami i inteligentnymi algorytmami.', + + name: 'Imię', + phoneLabel2: 'Telefon', + questions: 'Masz pytania?', + contactsTitle: 'SKONTAKTUJ', + contactsTitle2: 'SIĘ Z NAMI', + managers: 'Nasz menedżer odpowie w ciągu 15 minut', + messageTitle: 'Wiadomość', + + feelFree: 'Nie wahaj się', + contactUsButton: 'Skontaktuj się z nami', + feelFree2: 'skontaktować bezpośrednio — chętnie pomożemy.', + + manual: 'Instrukcja obsługi', + warranty: 'Gwarancja', + policy: 'Polityka serwisowa', + + titleFaq: 'CZĘSTO', + titleFaq2: 'ZADAWANE PYTANIA', + + priceTitle: 'Cena', + quantity: 'Ilość', + purchase: 'Kup', + homepageButton: 'Strona główna', + + paymentCompleteTitle: 'DZIĘKUJEMY ZA', + paymentCompleteTitle2: 'TWOJE', + paymentCompleteTitle3: 'ZAMÓWIENIE!', + paymentCompleteText: + 'Twoje zamówienie zostało złożone i jest przetwarzane. Otrzymasz email z jego szczegółami.', + + aboutTitle: 'O', + aboutTitle2: 'PRODUKCIE', + + productDescription: + 'KAT Loco to system lokomocji VR oparty na ruchu stóp, zapewniający pełną fizyczną kontrolę nad ruchem dolnej części ciała.', + + hello: 'Cześć,', + meetTitle: 'MIŁO', + meetTitle2: 'CIĘ POZNAĆ!', + meetText: + 'KAT VR to niezależna firma założona w 2013 roku, specjalizująca się w rozwoju i sprzedaży rozwiązań lokomocji VR.', + }, + ru: { + aboutButton: 'О нас', + techButton: 'Технологии', + benefitsButton: 'Преимущества', + contactsButton: 'Контакты', + buyButton: 'Купить сейчас', + languageButton: 'Язык', + playButton: 'Воспроизвести видео', + faqButton: 'FAQ', + helpButton: 'Помощь', + moreButton: 'Больше', + previousButton: 'Назад', + nextButton: 'Вперёд', + + englishButton: 'Английский', + arabicButton: 'Арабский', + chineseSimplifiedButton: 'Китайский (упрощённый)', + chineseTraditionalButton: 'Китайский (традиционный)', + frenchButton: 'Французский', + germanButton: 'Немецкий', + italianButton: 'Итальянский', + polishButton: 'Польский', + russianButton: 'Русский', + ukrainianButton: 'Украинский', + + headerTitle: 'НОВОЕ НАЧАЛО', + headerTitle2: 'VR-ПЕРЕДВИЖЕНИЯ', + headerInfoDescription: + 'Откройте для себя самую комплексную систему VR-передвижения и получите безграничную свободу движения в любых играх на любых платформах!', + + faqTitle1: 'Чем KAT Loco отличается от других систем?', + faqAnswer1: + 'В отличие от традиционных VR-систем передвижения, KAT Loco сочетает высокий уровень погружения с удобством использования. Это универсальное, беспроводное и доступное решение для домашнего использования.', + + faqUpdated: 'Последнее обновление: 12 июня 2019', + + faqTitle2: 'Уменьшает ли система укачивание в VR?', + faqAnswer2: + 'Да, KAT Loco помогает значительно снизить VR-укачивание за счёт синхронизации реальных движений с движением в виртуальной среде.', + + faqTitle3: 'С какими VR-шлемами совместима система?', + faqAnswer3: + 'KAT Loco совместима с большинством популярных VR-гарнитур, включая Valve Index, HTC Vive, Oculus и другие.', + + faqTitle4: 'Совместима ли система с Oculus Quest?', + faqAnswer4: + 'Да, KAT Loco работает с Meta Quest 2/3/Pro как в режиме PC VR, так и в автономном режиме с адаптером KAT Nexus.', + + helpTitle: 'КАК МЫ МОЖЕМ', + helpTitle2: 'ПОМОЧЬ', + helpTitle3: 'ВАМ?', + helpInfoGoal: + 'Добро пожаловать в центр поддержки. Наша цель — сделать процесс знакомства с продуктом и покупки максимально простым и комфортным.', + + firstNameLabel: 'Имя', + firstNameRequired: 'Пожалуйста, введите имя', + lastNameLabel: 'Фамилия', + lastNameRequired: 'Пожалуйста, введите фамилию', + emailLabel: 'Email', + emailRequired: 'Пожалуйста, введите email', + emailFormatError: 'Неверный формат email', + + countryLabel: 'Страна', + countryRequired: 'Пожалуйста, выберите страну', + cityLabel: 'Город', + cityRequired: 'Пожалуйста, выберите город', + + shippingAddressLabel: 'Адрес доставки', + shippingAddressRequired: 'Пожалуйста, введите адрес доставки', + shippingAddress2Label: 'Адрес доставки 2', + + cardNumberLabel: 'Номер карты', + cardNumberRequired: 'Пожалуйста, введите номер карты', + cardHolderLabel: 'Имя держателя карты', + cardHolderRequired: 'Пожалуйста, введите имя держателя карты', + expirationDateLabel: 'Срок действия', + expirationDateRequired: 'Обязательное поле', + expirationInvalid: 'Неверная дата', + cvvLabel: 'CVV', + cvvRequired: 'Обязательное поле', + + phoneLabel: 'Номер телефона', + phoneRequired: 'Пожалуйста, введите номер телефона', + + moreTitle1: 'БОЛЬШЕ, ЧЕМ', + moreTitle2: 'ИГРЫ!', + moreSubtitle: 'Подходит также для людей, интересующихся...', + moreDescription: + 'Эта система создана не только для игр, но и для множества других сфер.', + + educationTitle: 'ОБРАЗОВАНИЕ', + educationDescription: + 'Создавайте образовательные симуляции и тренинги с неограниченным виртуальным пространством.', + + estateTitle: 'НЕДВИЖИМОСТЬ', + estateDescription: + 'Проектируйте архитектурные объекты в реалистичной среде с возможностью свободного перемещения.', + + fitnessTitle: 'ФИТНЕС', + fitnessDescription: 'Поддерживайте форму, играя в любимые VR-игры.', + + socialTitle: 'СОЦИАЛЬНОЕ ВЗАИМОДЕЙСТВИЕ', + socialDescription: + 'Проводите время с друзьями в виртуальном мире, даже если нет возможности встретиться лично.', + + techTitle: 'ТЕХНОЛОГИИ', + techTitle2: 'ХАРАКТЕРИСТИКИ', + + sensorTitle: 'СЕНСОР', + sensorText: 'Вес: 35 г', + sensorText2: 'Размеры: 50 × 24 мм', + sensorText3: 'Подсветка: LED-индикаторы', + + connectionTitle: 'СОЕДИНЕНИЕ', + connectionText: 'Беспроводное: Bluetooth 4.2', + connectionText2: 'Дальность сигнала: 5 м', + connectionText3: 'Приёмник: USB 2.0 и выше', + + batterriesTitle: 'БАТАРЕИ', + batterriesText: 'Тип: литий-ионные', + batterriesText2: 'Ёмкость: 370 мАч', + batterriesText3: 'До 10 часов непрерывной работы', + batterriesText4: 'Быстрая зарядка — 1 час', + batterriesText5: 'Напряжение и ток: 5V = 0.5A', + + benefitsTitle: 'ПОЧЕМУ', + benefitsTitle2: 'KAT LOCO?', + benefitsCardTitle: 'УНИВЕРСАЛЬНАЯ СОВМЕСТИМОСТЬ', + benefitsCardText: + 'Совместима со всеми основными VR-платформами и играми со свободным передвижением.', + + benefitsCardTitle2: 'ПАНЕЛЬ УПРАВЛЕНИЯ VR / PC', + benefitsCardText2: + 'Быстрый доступ к панели управления с ПК или напрямую из VR.', + + benefitsCardTitle3: 'БЕСПРОВОДНЫЕ СЕНСОРЫ', + benefitsCardText3: + 'Полностью беспроводная система с надёжными батареями и умными алгоритмами.', + + name: 'Имя', + phoneLabel2: 'Телефон', + questions: 'Есть вопросы?', + contactsTitle: 'СВЯЖИТЕСЬ', + contactsTitle2: 'С НАМИ', + managers: 'Наш менеджер ответит вам в течение 15 минут', + messageTitle: 'Сообщение', + + feelFree: 'Пожалуйста, не стесняйтесь', + contactUsButton: 'Связаться с нами', + feelFree2: 'обращаться напрямую — мы всегда рады помочь.', + + manual: 'Инструкция', + warranty: 'Гарантия', + policy: 'Сервисная политика', + + titleFaq: 'ЧАСТО', + titleFaq2: 'ЗАДАВАЕМЫЕ ВОПРОСЫ', + + priceTitle: 'Цена', + quantity: 'Количество', + purchase: 'Купить', + homepageButton: 'Главная', + + paymentCompleteTitle: 'СПАСИБО ЗА', + paymentCompleteTitle2: 'ВАШ', + paymentCompleteTitle3: 'ЗАКАЗ!', + paymentCompleteText: + 'Ваш заказ принят и находится в обработке. Вы получите письмо с деталями заказа.', + + aboutTitle: 'О', + aboutTitle2: 'ПРОДУКТЕ', + + productDescription: + 'KAT Loco — это VR-система передвижения, основанная на движениях ног, обеспечивающая полный физический контроль над движениями нижней части тела.', + + hello: 'Здравствуйте,', + meetTitle: 'ПРИЯТНО', + meetTitle2: 'ПОЗНАКОМИТЬСЯ!', + meetText: + 'KAT VR — независимая компания, основанная в 2013 году, специализирующаяся на разработке и продаже решений для VR-передвижения.', + }, + ua: { + aboutButton: 'Про нас', + techButton: 'Технології', + benefitsButton: 'Переваги', + contactsButton: 'Контакти', + buyButton: 'Купити зараз', + languageButton: 'Мова', + playButton: 'Відтворити відео', + faqButton: 'FAQ', + helpButton: 'Допомога', + moreButton: 'Більше', + previousButton: 'Попередня', + nextButton: 'Наступна', + + englishButton: 'Англійська', + arabicButton: 'Арабська', + chineseSimplifiedButton: 'Китайська (спрощена)', + chineseTraditionalButton: 'Китайська (традиційна)', + frenchButton: 'Французька', + germanButton: 'Німецька', + italianButton: 'Італійська', + polishButton: 'Польська', + russianButton: 'Російська', + ukrainianButton: 'Українська', + + headerTitle: 'НОВИЙ ПОЧАТОК', + headerTitle2: 'VR ПЕРЕМІЩЕННЯ', + headerInfoDescription: + 'Відкрийте для себе найповнішу систему VR-переміщення та отримайте необмежену свободу руху в будь-яких іграх на будь-яких платформах!', + + faqTitle1: 'Чим KAT Loco відрізняється від інших систем?', + faqAnswer1: + 'На відміну від традиційних VR-систем, KAT Loco поєднує повне занурення з комфортом використання. Це універсальне, бездротове та доступне рішення для домашнього використання.', + + faqUpdated: 'Останнє оновлення: 12 червня 2019', + + faqTitle2: 'Чи зменшує це заколисування?', + faqAnswer2: + 'Так, система значно зменшує VR-нудоту, синхронізуючи реальні рухи тіла з віртуальним світом.', + + faqTitle3: 'З якими VR-шоломами сумісна система?', + faqAnswer3: + 'KAT Loco сумісна з більшістю популярних VR-гарнітур, включаючи Valve Index, HTC Vive, Oculus та інші.', + + faqTitle4: 'Чи підтримується Oculus Quest?', + faqAnswer4: + 'Так, KAT Loco працює з Meta Quest 2/3/Pro як у PC VR, так і в автономному режимі з адаптером KAT Nexus.', + + helpTitle: 'ЯК МИ МОЖЕМО', + helpTitle2: 'ДОПОМОГТИ', + helpTitle3: 'ВАМ?', + helpInfoGoal: + 'Ласкаво просимо до центру підтримки. Ми прагнемо зробити процес ознайомлення та покупки максимально простим і зручним.', + + firstNameLabel: 'Імʼя', + firstNameRequired: 'Будь ласка, введіть імʼя', + lastNameLabel: 'Прізвище', + lastNameRequired: 'Будь ласка, введіть прізвище', + emailLabel: 'Email', + emailRequired: 'Будь ласка, введіть email', + emailFormatError: 'Невірний формат email', + + countryLabel: 'Країна', + countryRequired: 'Оберіть країну', + cityLabel: 'Місто', + cityRequired: 'Оберіть місто', + + shippingAddressLabel: 'Адреса доставки', + shippingAddressRequired: 'Введіть адресу доставки', + shippingAddress2Label: 'Адреса доставки 2', + + cardNumberLabel: 'Номер картки', + cardNumberRequired: 'Введіть номер картки', + cardHolderLabel: 'Імʼя власника картки', + cardHolderRequired: 'Введіть імʼя власника', + expirationDateLabel: 'Термін дії', + expirationDateRequired: 'Обовʼязкове поле', + expirationInvalid: 'Невірна дата', + cvvLabel: 'CVV', + cvvRequired: 'Обовʼязкове поле', + + phoneLabel: 'Номер телефону', + phoneRequired: 'Введіть номер телефону', + + moreTitle1: 'БІЛЬШЕ НІЖ', + moreTitle2: 'ІГРИ!', + moreSubtitle: 'Підходить також для людей, яких цікавить...', + moreDescription: + 'Ця система створена не лише для ігор, а й для інших сфер.', + + educationTitle: 'ОСВІТА', + educationDescription: + 'Створюйте освітні симуляції та тренінги з мінімальним фізичним простором.', + + estateTitle: 'НЕРУХОМІСТЬ', + estateDescription: + 'Проєктуйте архітектурні простори з можливістю вільного пересування.', + + fitnessTitle: 'ФІТНЕС', + fitnessDescription: + 'Залишайтеся у формі, поєднуючи тренування з VR-іграми.', + + socialTitle: 'СОЦІАЛЬНА ВЗАЄМОДІЯ', + socialDescription: + 'Спілкуйтеся з друзями у віртуальному світі без обмежень простору.', + + techTitle: 'ТЕХНІЧНІ', + techTitle2: 'ХАРАКТЕРИСТИКИ', + + sensorTitle: 'СЕНСОР', + sensorText: 'Вага: 35 г', + sensorText2: 'Розмір: 50 × 24 мм', + sensorText3: 'Світло: LED-індикатори', + + connectionTitle: 'ЗʼЄДНАННЯ', + connectionText: 'Бездротове: Bluetooth 4.2', + connectionText2: 'Дальність: 5 м', + connectionText3: 'Приймач: USB 2.0+', + + batterriesTitle: 'БАТАРЕЇ', + batterriesText: 'Тип: літій-іонні', + batterriesText2: 'Ємність: 370 мАг', + batterriesText3: 'До 10 год роботи', + batterriesText4: 'Швидка зарядка — 1 год', + batterriesText5: '5V = 0.5A', + + benefitsTitle: 'ЧОМУ', + benefitsTitle2: 'KAT LOCO?', + benefitsCardTitle: 'УНІВЕРСАЛЬНА СУМІСНІСТЬ', + benefitsCardText: + 'Працює з усіма основними VR-платформами та іграми з вільним пересуванням.', + + benefitsCardTitle2: 'VR / PC ПАНЕЛЬ КЕРУВАННЯ', + benefitsCardText2: + 'Керуйте системою як з ПК, так і безпосередньо з VR-гарнітури.', + + benefitsCardTitle3: 'БЕЗДРОТОВІ СЕНСОРИ', + benefitsCardText3: 'Повністю бездротова система з надійними батареями.', + + name: 'Імʼя', + phoneLabel2: 'Телефон', + questions: 'Маєте запитання?', + contactsTitle: 'ЗВʼЯЖІТЬСЯ', + contactsTitle2: 'З НАМИ', + managers: 'Менеджер відповість протягом 15 хвилин', + messageTitle: 'Повідомлення', + + feelFree: 'Не соромтеся', + contactUsButton: 'Звʼязатися з нами', + feelFree2: 'звертатися напряму, ми завжди раді допомогти.', + + manual: 'Інструкція', + warranty: 'Гарантія', + policy: 'Політика сервісу', + + titleFaq: 'ПОШИРЕНІ', + titleFaq2: 'ЗАПИТАННЯ', + + priceTitle: 'Ціна', + quantity: 'Кількість', + purchase: 'Купити', + homepageButton: 'Головна', + + paymentCompleteTitle: 'ДЯКУЄМО ЗА', + paymentCompleteTitle2: 'ВАШЕ', + paymentCompleteTitle3: 'ЗАМОВЛЕННЯ!', + paymentCompleteText: 'Ваше замовлення прийнято. Деталі надійдуть на email.', + + aboutTitle: 'ПРО', + aboutTitle2: 'ПРОДУКТ', + + productDescription: + 'KAT Loco — це VR-система переміщення, що забезпечує повний фізичний контроль над рухами нижньої частини тіла.', + + hello: 'Привіт,', + meetTitle: 'ПРИЄМНО', + meetTitle2: 'ПОЗНАЙОМИТИСЬ!', + meetText: + 'KAT VR — незалежна компанія, що з 2013 року розробляє та виробляє професійні VR-рішення.', + }, +}; diff --git a/src/scripts/language.js b/src/scripts/language.js new file mode 100644 index 00000000..3656719d --- /dev/null +++ b/src/scripts/language.js @@ -0,0 +1,89 @@ +'use strict'; + +import { dictionary } from './i18n'; +import { configureDropdown } from './dropdown'; + +const languageOpenerButton = document.querySelector('.button__language-opener'); +const languageCloseButton = document.querySelector('.button__language--close'); +const menuNavigation = document.querySelector('.menu__navigation'); +const menuLanguage = document.querySelector('.menu__language'); +const languageButtons = document.querySelectorAll('.menu__language-button'); +const i18nElements = document.querySelectorAll('[data-i18n]'); +const languageBlock = document.querySelector('.language-dropdown'); +const options = document.querySelectorAll('.language-dropdown__option'); + +export function setLanguageButtons() { + languageOpenerButton.addEventListener('click', () => { + menuNavigation.classList.add('menu--inactive'); + menuLanguage.classList.remove('menu--inactive'); + menuLanguage.classList.add('menu--active'); + }); + + languageCloseButton.addEventListener('click', () => { + menuNavigation.classList.remove('menu--inactive'); + menuLanguage.classList.add('menu--inactive'); + menuLanguage.classList.remove('menu--active'); + }); +} + +export function syncLanguage(language) { + syncMenuLanguageUI(language); + syncLanguageUIDropdown(language); +} + +export function setChangingLanguage() { + setChangingLanguageMenu(); + + configureDropdown(languageBlock, 'language', 'language', 'en', [ + syncLanguage, + setLanguage, + ]); +} + +function setChangingLanguageMenu() { + languageButtons.forEach((button) => { + button.addEventListener('click', () => { + const language = button.dataset.language; + console.log(language); + setLanguage(language); + syncLanguage(language); + }); + }); +} + +function syncMenuLanguageUI(language) { + languageButtons.forEach((button) => { + if (button.dataset.language === language) { + button.classList.add('menu__language-button--selected'); + } else { + button.classList.remove('menu__language-button--selected'); + } + }); +} + +function syncLanguageUIDropdown(language) { + const label = languageBlock.querySelector( + '.language-dropdown__selected-label', + ); + + label.dataset.language = language; + + options.forEach((opt) => { + const isSelected = opt.dataset.language === language; + + opt.hidden = isSelected; + + if (isSelected) { + label.textContent = opt.textContent; + } + }); +} + +function setLanguage(lang) { + i18nElements.forEach((el) => { + const key = el.getAttribute('data-i18n'); + if (dictionary[lang][key]) { + el.textContent = dictionary[lang][key]; + } + }); +} diff --git a/src/scripts/main.js b/src/scripts/main.js index ad9a93a7..9729dc9f 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -1 +1,51 @@ 'use strict'; + +import { addSliderForHeader } from './header-slider'; +import { setModals } from './modal'; +import { + setLanguageButtons, + syncLanguage, + setChangingLanguage, +} from './language'; +import { addMenu } from './menu'; +import { configureOverlay } from './overlay-click'; +import { initPayments } from './payment'; +import { configureMoreSection } from './more'; +import { configureSliderAbout } from './slider-about'; +import { configureTechButtons } from './tech'; +import { configureContactsFormValidations } from './contacts'; + +const defaultLanguage = 'en'; + +configureOverlay(); +setLanguageButtons(); +syncLanguage(defaultLanguage); +setChangingLanguage(); + +document.addEventListener('DOMContentLoaded', function () { + addSliderForHeader(); +}); + +setModals(); + +addMenu(); + +const faqTitle = document.querySelectorAll('.faq__card-title-wrapper'); + +faqTitle.forEach((title) => { + title.addEventListener('click', () => { + const closestCard = title.closest('.faq__card'); + + closestCard.classList.toggle('faq__card--active'); + }); +}); + + +initPayments(); +configureMoreSection(); + +configureSliderAbout(); + +configureTechButtons(); + +configureContactsFormValidations(); \ No newline at end of file diff --git a/src/scripts/menu.js b/src/scripts/menu.js new file mode 100644 index 00000000..ca5f52d5 --- /dev/null +++ b/src/scripts/menu.js @@ -0,0 +1,53 @@ +'use strict'; + +import { uiState } from "./uiState"; +import { syncOverlay } from "./overlay"; + +const menuButton = document.querySelector('.button--open-menu'); +const menuCloseButton = document.querySelector('.button--close-menu'); +const menu = document.querySelector('.page__menu'); +const menuLanguage = document.querySelector('.menu__language'); +const menuNavigation = document.querySelector('.menu__navigation'); + +export function addMenu() { + menuButton.addEventListener('click', () => { + const screenWidth = window.innerWidth; + + if (screenWidth < 1280) { + history.replaceState(null, '', location.pathname + '#menu'); + menu.classList.add('page__menu--opened'); + + uiState.menuOpen = true; + syncOverlay(); + } + }); + + menuCloseButton.addEventListener('click', () => { + closeMenu(); + }); +} + +export function closeMenu() { + history.replaceState(null, '', location.pathname); + menu.classList.remove('page__menu--opened'); + + uiState.menuOpen = false; + syncOverlay(); + + if (menuLanguage.classList.contains('menu--active')) { + menuLanguage.classList.remove('menu--active'); + menuLanguage.classList.add('menu--inactive'); + menuNavigation.classList.remove('menu--inactive'); + menuNavigation.classList.add('menu--active'); + } +} + +window.addEventListener('resize', () => { + if (window.innerWidth >= 1280 && location.hash === '#menu') { + closeMenu(); + } +}); + +window.addEventListener('hashchange', () => { + closeMenu(); +}); diff --git a/src/scripts/modal.js b/src/scripts/modal.js new file mode 100644 index 00000000..af684a75 --- /dev/null +++ b/src/scripts/modal.js @@ -0,0 +1,62 @@ +'uise strict'; + +import { uiState } from './uiState'; +import { syncOverlay } from './overlay'; + +const modals = document.querySelectorAll('.modal'); +const openButtons = document.querySelectorAll('[data-modal]'); +const closeButtons = document.querySelectorAll('.modal__close'); +const helpLinks = document.querySelectorAll('.help__redirect'); + + +export function setModals() { + openButtons.forEach((button) => { + button.addEventListener('click', () => { + openModal(button.dataset.modal); + }); + }); + + closeButtons.forEach((button) => + button.addEventListener('click', closeModals), + ); + + configureHelpModalLinks(); +} + +function openModal(modalId) { + const modal = document.getElementById(modalId); + + if (!modal) return; + + uiState.modalOpen = true; + syncOverlay(); + + modal.classList.add('modal--active'); +} + +export function closeModals() { + uiState.modalOpen = false; + syncOverlay(); + + modals.forEach((modal) => { + if (modal.classList.contains('modal--active')) { + modal.classList.remove('modal--active'); + + const iframe = modal.querySelector('iframe'); + + if (iframe) { + iframe.src = iframe.src; + } + } + }); +} + +function configureHelpModalLinks() { + helpLinks.forEach((link) => { + link.addEventListener('click', (e) => { + closeModals(); + }); + }); +} + + diff --git a/src/scripts/more.js b/src/scripts/more.js new file mode 100644 index 00000000..39659288 --- /dev/null +++ b/src/scripts/more.js @@ -0,0 +1,19 @@ +'use strict'; + +const more = document.querySelector('.more'); +const moreButton = document.querySelector('.header__bottom-button'); +const moreTopBar = more.querySelector('.more__top'); + +export function configureMoreSection() { + moreTopBar.addEventListener('click', () => { + if (window.innerWidth < 1280) { + more.classList.toggle('more--active'); + } + }); + + moreButton.addEventListener('click', () => { + if (window.innerWidth >= 1280) { + more.classList.toggle('more--active'); + } + }); +} diff --git a/src/scripts/overlay-click.js b/src/scripts/overlay-click.js new file mode 100644 index 00000000..016de112 --- /dev/null +++ b/src/scripts/overlay-click.js @@ -0,0 +1,17 @@ +'use strict'; + +import { uiState } from './uiState'; +import { closeMenu } from './menu'; +import { closeModals } from './modal'; + +const overlay = document.querySelector('.overlay'); + +export function configureOverlay() { + overlay.addEventListener('click', () => { + if (uiState.menuOpen) { + closeMenu(); + } else if (uiState.modalOpen) { + closeModals(); + } + }); +} diff --git a/src/scripts/overlay.js b/src/scripts/overlay.js new file mode 100644 index 00000000..07fd64e8 --- /dev/null +++ b/src/scripts/overlay.js @@ -0,0 +1,14 @@ +'use strict'; + +import { uiState } from './uiState'; + +const overlay = document.querySelector('.overlay'); + +export function syncOverlay() { + const shouldBeShown = uiState.menuOpen || uiState.modalOpen; + if (shouldBeShown) { + overlay.classList.add('overlay--active'); + } else { + overlay.classList.remove('overlay--active'); + } +} diff --git a/src/scripts/payment.js b/src/scripts/payment.js new file mode 100644 index 00000000..4b78226b --- /dev/null +++ b/src/scripts/payment.js @@ -0,0 +1,276 @@ +'use strict'; + +import { configureDropdown, syncUIDropdown } from './dropdown'; +import { + createCountryCityDropdown, + loadCitiesChunked, +} from './country-city-dropdown'; +import { + configureFormValidations, + clearAllErorrors, + validateField, + setError, + clearError, +} from './form'; +import { closeModals } from './modal'; +import { configureCardEvents, clearCardInput } from './card'; +import { getError } from './expiration'; + +const modal = document.querySelector('.modal--payment'); +const steps = modal.querySelectorAll('.payment__step'); +const indicators = modal.querySelectorAll('.payment__step-indicator'); +const paymentHomepageButton = document.querySelector( + '.payment__homepage-button', +); +const closeButton = modal.querySelector('.modal__close--payment'); + +const paymentOrderPriceBlocks = modal.querySelectorAll('.payment__order-price'); +const stepValidators = { + order: validateOrderData, + payment: validatePaymentData, +}; + +let currentStep = 0; + +export function initPayments() { + renderPaymentStep(); + + document.addEventListener('DOMContentLoaded', () => { + createCountryCityDropdown(); + }); + + paymentOrderPriceBlocks.forEach((block) => { + mountPaymentOrderPrice(block); + }); + + const quantityDropdowns = modal.querySelectorAll('.quantity-dropdown'); + + quantityDropdowns.forEach((quantityDropdown) => { + configureDropdown(quantityDropdown, 'quantity', 'quantity', '1', [ + configurePrice, + ]); + }); + + configurePaymentNextButton(); + + configureFormValidations(modal); + + configurePaymentExitButton(); + configureCardEvents(); + configureCvv(); + configurePhone(); + + window.addEventListener('resize', () => { + if (window.innerWidth >= 1281) { + renderPaymentStep(); + } + }); + + closeButton.addEventListener('click', () => { + cleanModal(); + }); +} + +function configurePaymentNextButton() { + const buttons = modal.querySelectorAll('.payment-next__button'); + + buttons.forEach((button) => { + button.addEventListener('click', () => { + const isValid = validateAllFields(); + + if (isValid && currentStep < steps.length - 1) { + currentStep++; + renderPaymentStep(); + } + }); + }); +} + +function configurePrice(quantity) { + const amounts = modal.querySelectorAll('.payment__price-amount'); + + amounts.forEach((amount) => { + amount.textContent = quantity * 1200 + '$'; + }); + + const quantityDropdowns = modal.querySelectorAll('.quantity-dropdown'); + + quantityDropdowns.forEach((quantityDropdown) => { + syncUIDropdown('quantity', 'quantity', quantity, quantityDropdown); + }); +} + +function renderPaymentStep() { + steps.forEach((step, index) => { + step.classList.toggle('payment__step--active', index === currentStep); + }); + + indicators.forEach((indicator, index) => { + indicator.classList.toggle( + 'payment__step-indicator--active', + index === currentStep, + ); + indicator.style.setProperty('--step', currentStep); + }); + + if (window.innerWidth >= 1280) { + moveStepDot(); + } +} + +function configurePaymentExitButton() { + paymentHomepageButton.addEventListener('click', () => { + cleanModal(); + }); +} + +function mountPaymentOrderPrice(container) { + const template = document.getElementById('quantity-dropdown-template'); + + const dropdown = template.content.cloneNode(true); + + container.prepend(dropdown); +} + +function validateAllFields() { + const activeStep = modal.querySelector('.payment__step--active'); + const stepType = activeStep.dataset.step; + + const validator = stepValidators[stepType]; + + if (!validator) { + return true; + } + + return validator(activeStep); +} + +function validateOrderData(activeStep) { + let isValid = true; + + activeStep.querySelectorAll('.form-field').forEach((field) => { + const fieldIsValid = validateField(field); + + if (!fieldIsValid) { + isValid = false; + } + }); + + const cityField = modal.querySelector('.city-dropdown'); + + const chosenCity = modal.querySelector('.city-dropdown__selected-label'); + + if (chosenCity.textContent.trim().length === 0) { + isValid = false; + setError(cityField, 'cityRequired'); + } else { + clearError(cityField); + } + + return isValid; +} + +function validatePaymentData(activeStep) { + let isValid = true; + + activeStep.querySelectorAll('.form-field').forEach((field) => { + const fieldIsValid = validateField(field); + + if (!fieldIsValid) { + isValid = false; + } + }); + + const cardField = activeStep.querySelector('.card__form-field'); + const cardValue = cardField.querySelector('input').value; + + if (cardValue.length < 16) { + setError(cardField, 'cardNumberRequired'); + isValid = false; + } + + const cvvField = activeStep.querySelector('.card-secure__field--cvv'); + const cvvValue = cvvField.querySelector('input').value; + if (cvvValue.length < 3) { + setError(cvvField, 'cvvRequired'); + isValid = false; + } else { + clearError(cvvField); + } + + const expirationField = activeStep.querySelector( + '.card-secure__field--expiration', + ); + const expirationValue = expirationField + .querySelector('input') + .value.replace(/\D/g, '') + .slice(0, 4); + const error = getError(expirationValue); + + if (error) { + setError(expirationField, error); + isValid = false; + } + + return isValid; +} + +function configureCvv() { + const cvvField = modal.querySelector('.card-secure__field--cvv'); + const cvvInput = cvvField.querySelector('input'); + + cvvInput.addEventListener('input', () => { + clearError(cvvField); + + cvvInput.value = cvvInput.value.replace(/\D/g, ''); + }); + + cvvInput.addEventListener('blur', () => { + const cvv = cvvInput.value; + if (cvv.length < 3) { + setError(cvvField, 'cvvRequired'); + } + }); +} + +function configurePhone() { + const phoneField = document.getElementById('phone'); + + phoneField.addEventListener('input', () => { + phoneField.value = phoneField.value.replace(/\D/g, ''); + }); +} + +function moveStepDot() { + const active = modal.querySelector('.payment__step-indicator--active'); + const stepBar = modal.querySelector('.payment__step-bar'); + + if (!active || !stepBar) return; + + const barRect = stepBar.getBoundingClientRect(); + const textRect = active.getBoundingClientRect(); + + const centerX = textRect.left + textRect.width / 2 - barRect.left - 4 / 2; + + active.style.setProperty('--dot-x', `${centerX}px`); +} + +function cleanModal() { + closeModals(); + currentStep = 0; + renderPaymentStep(); + configurePrice('1'); + clearAllErorrors(modal); + const country = document.querySelector('.country-dropdown'); + syncUIDropdown('country', 'country', 'UA', country); + loadCitiesChunked('UA'); + clearCardInput(); + + const forms = modal.querySelectorAll('.form'); + + forms.forEach((form) => { + if (form) { + form.reset(); + } + }); +} diff --git a/src/scripts/slider-about.js b/src/scripts/slider-about.js new file mode 100644 index 00000000..ab3ad5e4 --- /dev/null +++ b/src/scripts/slider-about.js @@ -0,0 +1,98 @@ +'use strict'; + +const slider = document.querySelector('.slider-about'); +const slides = slider.querySelectorAll('.slider-about__image'); +const dots = slider.querySelectorAll('.slider-about__dot'); + +const leftButton = slider.querySelector('.slider-about__button--left'); +const rightButton = slider.querySelector('.slider-about__button--right'); +const currentSlide = slider.querySelector('.slider-about__current'); +const totalSlides = slides.length; + +let activeIndex = 0; +let startX = 0; + +export function configureSliderAbout() { + configureForMobileAndTablet(); + configureForDesktop(); +} + +function renderSlider() { + slides.forEach((slider, i) => { + slider.classList.toggle('slider-about__image--active', i === activeIndex); + }); + + dots.forEach((dot, i) => { + dot.classList.toggle('slider-about__dot--active', i === activeIndex); + }); +} + +function configureForMobileAndTablet() { + dots.forEach((dot, index) => { + dot.addEventListener('click', () => { + activeIndex = index; + renderSlider(); + }); + }); + + slider.addEventListener('touchstart', (e) => { + startX = e.touches[0].clientX; + }); + + slider.addEventListener('touchend', (e) => { + const endX = e.changedTouches[0].clientX; + const diff = endX - startX; + + if (Math.abs(diff) < 50) return; + + if (diff < 0 && activeIndex < slides.length - 1) { + activeIndex++; + renderSlider(); + } + + if (diff > 0 && activeIndex > 0) { + activeIndex--; + renderSlider(); + } + }); +} + +function configureForDesktop() { + let currentIndex = 0; + + slider.style.setProperty('--steps', totalSlides); + + function changeSlide(direction) { + slides[currentIndex].classList.remove('slider-about__image--active'); + currentIndex = (currentIndex + direction) % totalSlides; + slides[currentIndex].classList.add('slider-about__image--active'); + + if (totalSlides - 1 === currentIndex) { + rightButton.classList.add('slider-about__button--disabled'); + } + + if (currentIndex < totalSlides - 1) { + rightButton.classList.remove('slider-about__button--disabled'); + } + + if (currentIndex > 0) { + leftButton.classList.remove('slider-about__button--disabled'); + } + + if (currentIndex === 0) { + leftButton.classList.add('slider-about__button--disabled'); + } + + setSlide(currentIndex); + } + + function setSlide(index) { + slider.style.setProperty('--step', index); + currentSlide.textContent = index + 1; + } + + if (leftButton && rightButton) { + leftButton.addEventListener('click', () => changeSlide(-1)); + rightButton.addEventListener('click', () => changeSlide(1)); + } +} \ No newline at end of file diff --git a/src/scripts/tech.js b/src/scripts/tech.js new file mode 100644 index 00000000..60d8416d --- /dev/null +++ b/src/scripts/tech.js @@ -0,0 +1,18 @@ +'use strict' + +const tech = document.querySelector('.tech'); +const techButtons = tech.querySelectorAll('.hotspot__button'); + +export function configureTechButtons() { + techButtons.forEach(button => { + button.addEventListener('click', (e) => { + e.stopPropagation(); + + button.classList.toggle('hotspot__button--active'); + + const popover = button.closest('.hotspot'); + + popover.classList.toggle('hotspot--active'); + }) + }); +} \ No newline at end of file diff --git a/src/scripts/uiState.js b/src/scripts/uiState.js new file mode 100644 index 00000000..65719aee --- /dev/null +++ b/src/scripts/uiState.js @@ -0,0 +1,6 @@ +'use strict'; + +export const uiState = { + menuOpen: false, + modalOpen: false, +}; diff --git a/src/styles/_fonts.scss b/src/styles/_fonts.scss deleted file mode 100644 index 619b8c52..00000000 --- a/src/styles/_fonts.scss +++ /dev/null @@ -1,6 +0,0 @@ -@font-face { - font-family: Roboto, Arial, Helvetica, sans-serif; - src: url('../fonts/FontFont_FF.Mark.Pro.otf') format('otf'); - font-weight: normal; - font-style: normal; -} diff --git a/src/styles/_typography.scss b/src/styles/_typography.scss deleted file mode 100644 index 1837eb46..00000000 --- a/src/styles/_typography.scss +++ /dev/null @@ -1,3 +0,0 @@ -h1 { - @extend %h1; -} diff --git a/src/styles/_utils.scss b/src/styles/_utils.scss deleted file mode 100644 index 3280c3fe..00000000 --- a/src/styles/_utils.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'utils/vars'; -@import 'utils/mixins'; -@import 'utils/extends'; diff --git a/src/styles/about.scss b/src/styles/about.scss new file mode 100644 index 00000000..1cb966d0 --- /dev/null +++ b/src/styles/about.scss @@ -0,0 +1,222 @@ +.about { + padding-block: 50px; + + @include on-tablet { + padding-top: 70px; + } + + @include on-desktop { + padding-block: 100px; + } + + @include on-big-desktop { + padding-top: 147px; + padding-bottom: 156px; + } + + &__top { + margin-bottom: 88px; + + @include on-tablet { + display: flex; + gap: 20px; + margin-bottom: 84px; + } + + @include on-desktop { + gap: 109px; + justify-content: flex-end; + margin-bottom: 183px; + } + + @include on-big-desktop { + gap: 117px; + margin-bottom: 175px; + } + } + + &__product { + &-title { + display: none; + color: white; + + @include on-tablet { + display: block; + margin: 0; + margin-bottom: 30px; + } + + @include on-desktop { + margin-bottom: 30px; + } + + @include on-big-desktop { + height: 72px; + margin-bottom: 32px; + } + + &--mobile { + display: block; + margin: 0; + margin-bottom: 20px; + + @include on-tablet { + display: none; + } + } + + &--blue { + color: $color-contrast-color; + } + } + + &-description { + display: inline-block; + + height: 176px; + margin-top: 20px; + margin-bottom: 24px; + + color: $color-text-color; + + @include on-tablet { + width: 340px; + height: 124px; + margin-bottom: 30px; + } + + @include on-desktop { + width: 330px; + } + + @include on-big-desktop { + width: 435px; + margin-bottom: 42px; + } + } + } + + &__bottom { + @include on-tablet { + display: flex; + gap: 11px; + } + + @include on-desktop { + gap: 112px; + height: 347px; + } + + @include on-big-desktop { + gap: 101px; + height: 349px; + padding-left: 93px; + } + } + + &__meet { + &-subtitle { + display: block; + margin-bottom: 11px; + color: $color-contrast-color; + + @include on-tablet { + padding-top: 24px; + } + + @include on-desktop { + margin-bottom: 15px; + padding-top: 43px; + } + } + + &-title { + margin: 0; + margin-bottom: 22px; + color: white; + + @include on-tablet { + margin-bottom: 32px; + } + + @include on-big-desktop { + margin-bottom: 30px; + } + + &--blue { + color: $color-contrast-color; + } + } + + &-description { + height: 218px; + margin: 0; + color: $color-text-color; + + @include on-tablet { + width: 460px; + } + + @include on-desktop { + width: 429px; + } + + @include on-big-desktop { + width: 532px; + } + } + } + + &__words { + display: none; + + @include on-tablet { + display: flex; + gap: 20px; + } + + @include on-desktop { + gap: 17px; + } + } + + &__word { + display: block; + width: 62px; + height: 253px; + color: $color-contrast-color; + + @include on-desktop { + width: 83px; + height: 337px; + } + + &:nth-child(2n) { + rotate: 180deg; + } + + &:nth-child(2) { + color: #05c2df80; + } + + &:nth-child(3) { + color: #05c2df33; + } + + &:nth-child(4) { + color: #05c2df1a; + } + + &:nth-child(5) { + color: #05c2df0d; + } + + &--hidden-tablet { + display: none; + + @include on-desktop { + display: block; + } + } + } +} diff --git a/src/styles/benefits.scss b/src/styles/benefits.scss new file mode 100644 index 00000000..100f263b --- /dev/null +++ b/src/styles/benefits.scss @@ -0,0 +1,110 @@ +.benefits { + padding-block: 50px; + + @include on-tablet { + padding-block: 70px; + } + + @include on-desktop { + padding-block: 100px; + } + + @include on-big-desktop { + padding-block: 160px; + } + + &__title { + margin: 0; + margin-bottom: 32px; + color: white; + + @include on-tablet { + margin-bottom: 30px; + } + + @include on-desktop { + margin-bottom: 84px; + text-align: center; + } + + @include on-big-desktop { + margin-bottom: 82px; + } + + &--blue { + color: $color-contrast-color; + } + } + + &__info { + display: flex; + flex-direction: column; + gap: 20px; + + @include on-tablet { + flex-direction: row; + } + + @include on-big-desktop { + gap: 205px; + } + } + + &__button-buy { + display: none; + + @include on-desktop { + display: block; + margin-top: 90px; + margin-left: 430px; + } + + @include on-big-desktop { + display: none; + } + } + + &-card { + @include on-tablet { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + } + + &__icon { + display: none; + + @include on-tablet { + display: block; + width: 80px; + height: 80px; + margin-bottom: 25px; + } + + @include on-desktop { + margin-bottom: 34px; + } + } + + &__title { + margin: 0; + margin-bottom: 11px; + font-size: 16px; + color: white; + + @include on-tablet { + margin-bottom: 37px; + } + + @include on-desktop { + margin-bottom: 18px; + } + } + + &__description { + margin: 0; + color: $color-text-color; + } + } +} diff --git a/src/styles/card.scss b/src/styles/card.scss new file mode 100644 index 00000000..0bf41cc4 --- /dev/null +++ b/src/styles/card.scss @@ -0,0 +1,204 @@ +.card { + &__input { + --line-height: 1.3; + --digit-height: 23px; + --digit-width: 11px; + --letter-gap: 3.6px; + --group-gap: 20px; + --group-width: 55px; + --group-height: 32px; + + position: relative; + + width: 100vw; + width: calc((4 * var(--group-width)) + (3 * var(--group-gap))); + height: 32px; + margin-top: 17px; + + & input { + pointer-events: none; + + position: absolute; + inset: 0; + + border: none; + + opacity: 0; + background: transparent; + } + + @include on-tablet { + --digit-height: 26px; + --digit-width: 14.5px; + --letter-gap: 4px; + --group-gap: 32px; + --group-width: 70px; + --group-height: 32px; + } + + @include on-desktop { + --group-gap: 20px; + } + } + + &-visual { + pointer-events: auto; + display: flex; + gap: var(--group-gap); + + &__group { + display: flex; + gap: var(--letter-gap); + align-items: flex-start; + + width: var(--group-width); + height: var(--group-height); + padding-bottom: 9px; + border-bottom: 1px solid $color-dark-grey; + } + + &__group.active { + border-bottom-color: $color-contrast-color; + } + + &__digit { + width: var(--digit-width); + height: var(--digit-height); + + font-variation-settings: 'tnum'; + font-variant-numeric: tabular-nums; + line-height: var(--line-height); + text-align: center; + + &--filled { + color: white; + } + } + + &__placeholder { + color: $color-dark-grey; + } + + &__caret { + pointer-events: none; + + position: absolute; + + width: 2px; + height: var(--digit-height); + margin-left: 1px; + + opacity: 0; + background: $color-contrast-color; + + animation: blink 1s steps(1) infinite; + } + + &--focused { + .card-visual__caret { + opacity: 1; + } + } + + @keyframes blink { + 50% { + opacity: 0; + } + } + + &__logo { + position: absolute; + right: -84px; + + width: 54px; + height: 34px; + + opacity: 0; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + + transition: opacity $animation-speed ease; + + &--visa { + opacity: 1; + background-image: url('./../images/icon/icon-visa.svg'); + } + + &--mastercard { + opacity: 1; + background-image: url('./../images/icon/icon-mastercard.svg'); + } + } + } + + &-secure { + &__data { + display: flex; + grid-column: span 2; + flex-direction: row; + gap: 50px; + + @include on-tablet { + grid-column: 2 / 5; + gap: 145px; + } + + @include on-desktop { + grid-column: 2 / 11; + gap: 92px; + } + } + &__field { + display: flex; + flex-direction: column; + gap: 17px; + + &--expiration { + width: 130px; + } + + &--cvv { + width: 100px; + } + } + + &__input { + box-sizing: border-box; + height: 32px; + padding-bottom: 9px; + border: 0; + border-bottom: 1px solid #2f2f2f; + + color: white; + + background-color: inherit; + outline: none; + + &::placeholder { + color: $color-dark-grey; + } + + &:focus { + border-color: $color-contrast-color; + caret-color: $color-contrast-color; + } + + &--cvv { + width: 41px; + + @include on-desktop { + width: 49px; + } + } + + &--expiration { + width: 75px; + + @include on-desktop { + width: 90px; + } + } + } + } +} diff --git a/src/styles/city-dropdown.scss b/src/styles/city-dropdown.scss new file mode 100644 index 00000000..e9ea90f8 --- /dev/null +++ b/src/styles/city-dropdown.scss @@ -0,0 +1,70 @@ +.city-dropdown { + grid-column: span 2; + + @include on-tablet { + grid-column: span 3; + } + + @include on-desktop { + grid-column: span 6; + } + + @include on-big-desktop { + grid-column: span 8; + } + + &__select { + position: relative; + } + + &__selected { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + + height: 47px; + padding-inline: 24px 16px; + + background-color: $color-gradient-start; + &-label { + color: white; + } + } + + &__option { + color: white; + } + + &__options { + overflow: auto; + display: flex; + flex-direction: column; + gap: 10px; + + box-sizing: border-box; + width: 280px; + height: 235px; + padding-left: 24px; + + &::-webkit-scrollbar { + width: 1px; + } + + &::-webkit-scrollbar-thumb { + background-color: $color-contrast-color; + } + + &::-webkit-scrollbar-track { + background-color: #014954; + } + + @include on-tablet { + width: 340px; + } + + @include on-desktop { + width: 248px; + } + } +} diff --git a/src/styles/contacts.scss b/src/styles/contacts.scss new file mode 100644 index 00000000..09f02f15 --- /dev/null +++ b/src/styles/contacts.scss @@ -0,0 +1,206 @@ +.contacts { + padding-block: 50px; + + @include on-tablet { + position: relative; + padding-top: 70px; + padding-bottom: 130px; + } + + @include on-desktop { + padding-block: 100px; + } + + @include on-big-desktop { + padding-top: 156px; + padding-bottom: 205px; + } + + &__top { + @include on-desktop { + width: 338px; + } + + @include on-big-desktop { + width: 447px; + } + } + + &__wrapper { + display: flex; + flex-direction: column; + gap: 32px; + + @include on-tablet { + flex-direction: row; + gap: 22px; + } + + @include on-desktop { + gap: 201px; + } + + @include on-big-desktop { + gap: 290px; + } + } + + &__subtitle { + margin: 0; + margin-bottom: 11px; + color: $color-contrast-color; + + @include on-desktop { + margin-bottom: 13px; + } + } + + &__title { + margin: 0; + color: white; + + @include on-tablet { + margin-bottom: 50px; + } + + @include on-desktop { + margin-bottom: 26px; + } + + &--blue { + color: $color-contrast-color; + } + } + + &__description { + display: none; + color: $color-text-color; + + @include on-tablet { + display: block; + margin-bottom: 76px; + } + + &--mobile { + @include on-tablet { + display: none; + } + } + } + + &__data { + display: none; + + @include on-tablet { + display: flex; + flex-direction: column; + gap: 11px; + + line-height: 100%; + color: $color-text-color; + } + } + + &__form { + display: flex; + flex-direction: column; + gap: 24px; + + @include on-tablet { + width: 340px; + } + + @include on-desktop { + width: 521px; + } + + @include on-big-desktop { + width: 717px; + } + + &-field { + display: flex; + flex-direction: column; + gap: 6px; + + &--textarea { + flex-direction: column; + gap: 52px; + + @include on-desktop { + height: 88px; + } + } + + &--error { + color: red; + } + } + + &-label { + position: relative; + &--required { + &::after { + content: '*'; + position: absolute; + top: 0; + } + } + } + } + + &__button { + width: 100%; + margin-top: 6px; + margin-bottom: 30px; + + @include on-tablet { + width: 200px; + margin-top: 48px; + margin-bottom: 0; + } + + @include on-big-desktop { + margin-top: 50px; + } + } + + &__link-top { + display: none; + + @include on-tablet { + position: absolute; + right: 34px; + bottom: 130px; + + display: flex; + align-items: center; + justify-content: center; + + width: 48px; + height: 48px; + border: 1px solid $color-contrast-color; + border-radius: 50%; + + color: $color-contrast-color; + + background-repeat: no-repeat; + } + + @include on-desktop { + right: 110px; + bottom: 101px; + } + + @include on-big-desktop { + right: 238px; + bottom: 205px; + } + } + + &__image { + transform: rotate(90deg); + width: 15px; + height: 9px; + } +} diff --git a/src/styles/country-dropdown.scss b/src/styles/country-dropdown.scss new file mode 100644 index 00000000..09584d92 --- /dev/null +++ b/src/styles/country-dropdown.scss @@ -0,0 +1,70 @@ +.country-dropdown { + grid-column: span 2; + + @include on-tablet { + grid-column: span 3; + } + + @include on-desktop { + grid-column: span 6; + } + + @include on-big-desktop { + grid-column: span 8; + } + + &__select { + position: relative; + } + + &__selected { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + + height: 47px; + padding-inline: 24px 16px; + + background-color: $color-gradient-start; + &-label { + color: white; + } + } + + &__option { + color: white; + } + + &__options { + overflow: auto; + display: flex; + flex-direction: column; + gap: 10px; + + box-sizing: border-box; + width: 280px; + height: 235px; + padding-left: 24px; + + &::-webkit-scrollbar { + width: 1px; + } + + &::-webkit-scrollbar-thumb { + background-color: $color-contrast-color; + } + + &::-webkit-scrollbar-track { + background-color: #014954; + } + + @include on-tablet { + width: 340px; + } + + @include on-desktop { + width: 248px; + } + } +} diff --git a/src/styles/dropdown.scss b/src/styles/dropdown.scss new file mode 100644 index 00000000..9bed85f1 --- /dev/null +++ b/src/styles/dropdown.scss @@ -0,0 +1,59 @@ +.dropdown { + &__options { + pointer-events: none; + + position: absolute; + transform: translateY(-5px) scale(0.95); + + width: 60px; + + opacity: 0; + background-color: $color-gradient-start; + + transition: + opacity 0.2s, + transform 0.2s; + } + + &__opened { + .dropdown__options { + pointer-events: auto; + cursor: pointer; + + z-index: 2000; + left: 0; + transform: translateY(51px) scale(1); + + display: flex; + flex-direction: column; + + opacity: 1; + } + + .dropdown__option { + @include hover(color, $color-contrast-color); + } + + &-city { + .dropdown__options { + transform: translateY(3px) scale(1); + } + } + + &-country { + .dropdown__options { + transform: translateY(3px) scale(1); + } + } + + &-language { + .dropdown__options { + transform: translateY(35px) scale(1); + } + + .dropdown__option { + @include hover(color, white); + } + } + } +} diff --git a/src/styles/footer.scss b/src/styles/footer.scss new file mode 100644 index 00000000..4c4b1585 --- /dev/null +++ b/src/styles/footer.scss @@ -0,0 +1,145 @@ +.footer { + padding-top: 45px; + padding-bottom: 50px; + + @include on-tablet { + padding-block: 21px; + } + + @include on-desktop { + padding-block: 39px; + } + + &__wrapper { + display: flex; + gap: 81px; + + @include on-desktop { + gap: 275px; + } + + @include on-big-desktop { + gap: 471px; + } + } + + &__top { + display: flex; + flex-direction: column; + gap: 15px; + align-items: center; + + @include on-tablet { + flex-direction: row; + gap: 127px; + } + + @include on-desktop { + gap: 304px; + } + + @include on-big-desktop { + gap: 500px; + } + } + + &__logo { + width: 69px; + height: 14px; + + @include on-tablet { + width: 72px; + } + } + + &__nav { + display: flex; + flex-direction: column; + gap: 12px; + + @include on-tablet { + flex-direction: row; + gap: 43px; + } + } + + &__bottom { + display: flex; + flex-direction: column; + gap: 22px; + align-items: center; + + width: 130px; + } + + &__contacts { + display: flex; + flex-direction: column; + gap: 12px; + + @include on-tablet { + display: none; + } + } + + &__socials { + display: flex; + gap: 22px; + + @include on-tablet { + gap: 18px; + } + + &-link { + color: white; + text-decoration: none; + + @include hover(transform, scale(1.1)); + @include hover(color, $color-contrast-color); + } + + &-icon { + background-repeat: no-repeat; + + &--facebook { + width: 8px; + height: 15px; + + @include on-tablet { + width: 6px; + height: 12px; + } + } + + &--twitter { + width: 19px; + height: 14px; + + @include on-tablet { + width: 15px; + height: 11px; + } + } + + &--youtube { + width: 18px; + height: 14px; + + @include on-tablet { + width: 14px; + height: 11px; + } + } + + &--reddit { + width: 18px; + height: 18px; + + @include on-tablet { + width: 14px; + height: 14px; + } + } + } + } +} diff --git a/src/styles/form.scss b/src/styles/form.scss new file mode 100644 index 00000000..241811e2 --- /dev/null +++ b/src/styles/form.scss @@ -0,0 +1,133 @@ +.form { + &-label { + position: relative; + &--required { + &::after { + content: '*'; + position: absolute; + top: 0; + } + } + } + + &__input { + border: 0; + border-bottom: 1px solid #2f2f2f; + + color: white; + + background-color: inherit; + outline: none; + &:focus { + border-color: $color-contrast-color; + caret-color: $color-contrast-color; + } + } + + &-field { + display: flex; + grid-column: span 2; + flex-direction: column; + gap: 2px; + + @include on-tablet { + grid-column: span 3; + } + + @include on-desktop { + grid-column: span 6; + } + + @include on-big-desktop { + grid-column: span 8; + } + + &__payment { + grid-column: span 2; + + @include on-tablet { + grid-column: 2 / 6; + } + + @include on-desktop { + grid-column: 2 / 11; + } + } + + &:focus-within .form-label { + color: $color-contrast-color; + } + + &--error { + color: red; + + .form-label--required { + color: red; + } + + &:focus-within .form-label { + color: red; + } + + .form__input { + &:focus { + border-color: red; + caret-color: red; + } + } + } + } + + &__button { + grid-column: span 2; + + width: 100%; + height: 40px; + margin-top: 40px; + margin-bottom: 40px; + + @include on-tablet { + grid-column: 2 / 6; + height: 48px; + } + + @include on-desktop { + grid-column: span 6; + width: 200px; + margin-top: 28px; + } + + @include on-big-desktop { + margin-top: 62px; + } + + &--pay { + @include on-desktop { + grid-column: 2 / 7; + margin-top: 90px; + } + + @include on-big-desktop { + margin-top: 125px; + } + } + } + + &__textarea { + resize: none; + + height: 15px; + border: 0; + border-bottom: 1px solid #2f2f2f; + + color: white; + + background-color: inherit; + outline: none; + + &:focus { + border-color: $color-contrast-color; + caret-color: $color-contrast-color; + } + } +} diff --git a/src/styles/general/button.scss b/src/styles/general/button.scss new file mode 100644 index 00000000..b76da088 --- /dev/null +++ b/src/styles/general/button.scss @@ -0,0 +1,51 @@ +.button { + cursor: pointer; + border: none; + color: white; + + &--primary { + width: 200px; + height: 48px; + border-radius: 4px; + background-color: $color-contrast-color; + + @include hover(background-color, white); + @include hover(color, $color-contrast-color); + } + + &--video { + display: flex; + align-items: center; + + width: 211px; + height: 67px; + padding-left: 105px; + + background-color: inherit; + background-image: url('./../images/icon/icon-play.svg'); + + @include hover( + background-image, + url('./../images/icon/icon-play-hover.svg') + ); + } + + &--language { + padding: 0; + background-color: inherit; + } + + &__language--close { + width: 9px; + height: 17px; + + object-fit: cover; + background-color: inherit; + background-image: url('./../images/icon/icon-back.svg'); + background-repeat: no-repeat; + } + + &--menu-action { + background-color: inherit; + } +} diff --git a/src/styles/general/container.scss b/src/styles/general/container.scss new file mode 100644 index 00000000..244ccc35 --- /dev/null +++ b/src/styles/general/container.scss @@ -0,0 +1,3 @@ +.container { + @include content-padding-inline; +} diff --git a/src/styles/general/icon.scss b/src/styles/general/icon.scss new file mode 100644 index 00000000..971437a3 --- /dev/null +++ b/src/styles/general/icon.scss @@ -0,0 +1,23 @@ +.icon { + display: block; + object-fit: cover; + background-repeat: no-repeat; + + &--menu { + width: 30px; + height: 13px; + background-image: url('./../images/icon/icon-menu.svg'); + + @include hover(transform, scale(1.1)); + + @include on-desktop { + display: none; + } + } + + &--close { + width: 17px; + height: 17px; + background-image: url('./../images/icon/icon-close.svg'); + } +} diff --git a/src/styles/general/link.scss b/src/styles/general/link.scss new file mode 100644 index 00000000..f56ca931 --- /dev/null +++ b/src/styles/general/link.scss @@ -0,0 +1,14 @@ +.link { + color: white; + text-decoration: none; + + @include hover(transform, scale(1.1)); + + &--blue { + color: $color-contrast-color; + } + + &--contacts { + color: $color-text-color; + } +} diff --git a/src/styles/general/overlay.scss b/src/styles/general/overlay.scss new file mode 100644 index 00000000..14caf5f7 --- /dev/null +++ b/src/styles/general/overlay.scss @@ -0,0 +1,21 @@ +.overlay { + pointer-events: none; + + position: fixed; + z-index: 5; + inset: 0; + + border: 0; + + opacity: 0; + background: #000000b2; + + transition: opacity $animation-speed; + + &--active { + pointer-events: all; + width: 100vw; + height: 100vh; + opacity: 1; + } +} diff --git a/src/styles/general/page.scss b/src/styles/general/page.scss new file mode 100644 index 00000000..d15baea2 --- /dev/null +++ b/src/styles/general/page.scss @@ -0,0 +1,45 @@ +.page { + scroll-behavior: smooth; + + min-width: 320px; + margin: 0; + padding: 0; + + color: $color-text-color; + + background: linear-gradient(107.56deg, $color-gradient-start 0%, black 100%); + box-shadow: 4px 4px 40px 0 #00000040; + &__body { + margin: 0; + padding: 0; + } + + &__menu { + pointer-events: none; + + position: fixed; + top: 0; + right: 0; + left: 0; + transform: translateX(-100%); + + opacity: 0; + + transition: transform $animation-speed; + + &--opened { + pointer-events: all; + z-index: 1000; + transform: translateX(0); + opacity: 1; + } + } + + &:has(.page__menu--opened) { + overflow: hidden; + } + + &:has(.overlay--active) { + overflow: hidden; + } +} diff --git a/src/styles/header.scss b/src/styles/header.scss new file mode 100644 index 00000000..853ad3ec --- /dev/null +++ b/src/styles/header.scss @@ -0,0 +1,218 @@ +.header { + padding-bottom: 33px; + + @include on-tablet { + padding-bottom: 70px; + } + + @include on-desktop { + padding-bottom: 84px; + } + + &__wrapper { + display: flex; + flex-direction: column; + + @include on-tablet { + flex-direction: row-reverse; + justify-content: space-between; + } + } + + &__background { + position: relative; + width: 280px; + height: 172px; + + @include on-tablet { + width: 400px; + height: 240px; + padding-top: 30px; + } + + @include on-desktop { + width: 505px; + height: 300px; + padding: 0; + } + + @include on-big-desktop { + width: 900px; + height: 500px; + } + + &-image { + pointer-events: none; + + position: absolute; + + width: 100%; + height: 100%; + + opacity: 0; + object-fit: cover; + + transition: opacity $animation-speed ease; + &--active { + pointer-events: all; + opacity: 1; + } + } + } + + &__middle { + &-title { + margin-left: 20px; + } + } + + &__title { + margin: 0; + color: white; + + &--blue { + margin-bottom: 17px; + color: $color-contrast-color; + } + } + + &__price { + display: block; + margin-bottom: 25px; + color: white; + text-align: center; + + @include on-tablet { + text-align: left; + } + + @include on-desktop { + padding-left: 92px; + } + + @include on-big-desktop { + margin-bottom: 36px; + } + } + + &__info { + &-description { + display: block; + margin-bottom: 8px; + + @include on-tablet { + max-width: 340px; + margin-bottom: 10px; + } + + @include on-desktop { + padding-left: 92px; + } + + @include on-big-desktop { + max-width: 370px; + margin-bottom: 30px; + } + } + } + + &__video-button { + margin-bottom: 32px; + + @include on-tablet { + margin: 0; + } + + @include on-desktop { + margin-bottom: 93px; + margin-left: 92px; + } + } + + &__button-buy { + width: 100%; + height: 40px; + + @include on-tablet { + margin-top: 40px; + } + + @include on-desktop { + display: none; + } + } + + &__bottom { + display: none; + + @include on-desktop { + display: flex; + justify-content: space-between; + } + + &-links { + @include on-desktop { + display: flex; + gap: 39px; + } + } + + &-button { + display: flex; + flex-direction: column; + gap: 7px; + align-items: center; + + margin-left: 100px; + + color: $color-contrast-color; + + background-color: inherit; + + @include hover(transform, scale(1.1)); + } + } + + &__slider { + --steps: 3; + --step: 0; + + position: relative; + display: flex; + gap: 103px; + + &::before { + content: ''; + + position: absolute; + bottom: -10px; + + width: 100%; + border: 1px solid #212121; + } + + &::after { + content: ''; + + position: absolute; + bottom: -10px; + transform: translateX(calc(var(--step) * 100%)); + + width: calc(100% / var(--steps)); + border: 1px solid $color-contrast-color; + + transition: transform $animation-speed ease; + } + + &-button { + background-color: inherit; + + @include hover(color, $color-contrast-color); + + &--disabled { + pointer-events: none; + color: $color-text-color; + } + } + } +} diff --git a/src/styles/hotspot.scss b/src/styles/hotspot.scss new file mode 100644 index 00000000..8a22ee97 --- /dev/null +++ b/src/styles/hotspot.scss @@ -0,0 +1,297 @@ +.hotspot { + position: absolute; + + &--sensor { + top: -11px; + left: 60px; + + @include on-tablet { + top: -27px; + right: 231px; + left: unset; + } + + @include on-desktop { + top: 7px; + left: 101px; + } + + @include on-big-desktop { + left: 75px; + } + } + + &--batterries { + top: 80px; + right: 29px; + + @include on-tablet { + top: 145px; + right: 49px; + } + + @include on-desktop { + top: unset; + right: 354px; + bottom: 102px; + } + + @include on-big-desktop { + right: 430px; + bottom: 103px; + } + } + + &--connection { + bottom: 8px; + + @include on-tablet { + bottom: 19px; + left: 0; + } + + @include on-desktop { + top: 119px; + left: 226px; + } + + @include on-big-desktop { + top: 129px; + left: 170px; + } + } + + &__popover { + pointer-events: none; + + position: absolute; + transform: translate(-50%, -50%); + + width: 168px; + max-height: 200px; + padding-top: 17px; + padding-bottom: 22px; + padding-inline: 10px; + border-radius: 4%; + + opacity: 0; + background-color: $color-gradient-start; + + transition: + opacity $animation-speed ease, + transform $animation-speed ease; + + @include on-tablet { + max-height: 250px; + } + + @include on-desktop { + transform: translate(0); + opacity: 1; + background-color: inherit; + } + + &--sensor { + right: -50px; + + @include on-desktop { + top: -40px; + right: 640px; + } + + @include on-big-desktop { + right: 780px; + } + } + + &--batterries { + left: -80px; + + @include on-tablet { + top: -40px; + left: 70px; + } + + @include on-desktop { + left: 200px; + } + + @include on-big-desktop { + left: 250px; + } + } + + &--connection { + top: -40px; + left: 70px; + + @include on-desktop { + top: unset; + bottom: -20px; + left: -150px; + } + + @include on-big-desktop { + bottom: -30px; + left: -100px; + } + } + + &--active { + opacity: 1; + } + } + + &--active { + .hotspot__popover { + pointer-events: all; + transform: translateY(0); + opacity: 1; + } + } + + &__title { + display: none; + + @include on-desktop { + display: block; + margin-bottom: 21px; + color: white; + } + } + + &__button { + cursor: pointer; + + position: relative; + + width: 34px; + height: 34px; + border-color: #ffffff24; + border-radius: 50%; + + background-color: #05c2df; + background-size: cover; + + transition: background-color $animation-speed ease; + + @include hover(transform, scale(1.1)); + + @include on-desktop { + display: none; + } + + &::before, + &::after { + content: ''; + + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + + width: 12px; + height: 2px; + + background: white; + + transition: + transform $animation-speed ease, + opacity $animation-speed ease; + + @include on-tablet { + width: 21px; + } + } + + &::after { + transform: translate(-50%, -50%) rotate(90deg); + } + + @include on-tablet { + width: 62px; + height: 62px; + } + + &--active { + border-color: #ffffff24; + background-color: #07798b; + + &::after { + opacity: 0; + } + } + } + + &__text { + margin: 0; + + &--batterries { + @include on-desktop { + width: 338px; + } + } + + &--sensor { + @include on-desktop { + width: 250px; + } + } + + &--connection { + @include on-desktop { + width: 241px; + } + } + } + + &__line { + &--connection { + display: none; + + @include on-desktop { + display: block; + width: 134px; + height: 113px; + } + + @include on-big-desktop { + width: 240px; + height: 112px; + } + } + + &--sensor { + display: none; + + @include on-desktop { + display: block; + width: 403px; + height: 72px; + } + + @include on-big-desktop { + width: 431px; + } + } + + &--batterries { + display: none; + + @include on-desktop { + top: 0; + right: 0; + + display: block; + + width: 191px; + height: 245px; + } + + @include on-big-desktop { + width: 283px; + height: 245px; + } + } + } +} diff --git a/src/styles/language-dropdown.scss b/src/styles/language-dropdown.scss new file mode 100644 index 00000000..3720e9ad --- /dev/null +++ b/src/styles/language-dropdown.scss @@ -0,0 +1,55 @@ +.language-dropdown { + display: none; + + @include on-desktop { + display: block; + color: $color-contrast-color; + } + + &__options { + overflow: auto; + display: flex; + flex-direction: column; + gap: 12px; + + height: 111px; + border-radius: 4px; + + &::-webkit-scrollbar { + width: 1px; + } + + &::-webkit-scrollbar-thumb { + background-color: $color-contrast-color; + } + + &::-webkit-scrollbar-track { + background-color: #014954; + } + } + + &__select { + cursor: pointer; + + position: relative; + + display: flex; + + width: auto; + max-width: 70px; + height: 21px; + } + + &__selected { + display: flex; + flex-direction: row; + align-items: last baseline; + } + + &__arrow { + width: 9px; + height: 6px; + margin-left: 4px; + transition: transform $animation-speed; + } +} diff --git a/src/styles/main.scss b/src/styles/main.scss index fb9195d1..381edf4a 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -1,7 +1,34 @@ -@import 'utils'; -@import 'fonts'; -@import 'typography'; - -body { - background: $c-gray; -} +@import 'utils/fonts'; +@import 'utils/vars'; +@import 'utils/mixins'; +@import 'utils/typography'; +@import 'general/page'; +@import 'general/container'; +@import 'general/icon'; +@import 'general/link'; +@import 'general/overlay'; +@import 'modals/modal'; +@import 'top-bar'; +@import 'nav'; +@import 'dropdown'; +@import 'language-dropdown'; +@import 'general/button'; +@import 'header'; +@import 'menu'; +@import 'modals/faq'; +@import 'modals/help'; +@import 'modals/payment'; +@import 'form'; +@import 'country-dropdown'; +@import 'quantity'; +@import 'city-dropdown'; +@import 'card'; +@import 'more'; +@import 'svg'; +@import 'slider-about'; +@import 'about'; +@import 'tech'; +@import 'hotspot'; +@import 'benefits'; +@import 'contacts'; +@import 'footer'; diff --git a/src/styles/menu.scss b/src/styles/menu.scss new file mode 100644 index 00000000..0948c31d --- /dev/null +++ b/src/styles/menu.scss @@ -0,0 +1,102 @@ +.menu { + overflow: auto; + box-sizing: border-box; + height: 100vh; + background-color: $color-gradient-start; + + @include on-tablet { + height: 55vh; + max-height: 596px; + } + + @include on-desktop { + display: none; + } + + &--active { + pointer-events: all; + + z-index: 105; + transform: translateX(0); + + display: block; + + opacity: 1; + + transition: transform, $animation-speed; + } + + &--inactive { + pointer-events: none; + + position: fixed; + top: 0; + right: 0; + left: 0; + transform: translateX(-100%); + + opacity: 0; + } + + &__top { + display: flex; + justify-content: end; + + margin-bottom: 38px; + padding-top: 20px; + padding-right: 21px; + + @include on-tablet { + padding-top: 34px; + padding-right: 34px; + } + + &--language { + justify-content: start; + padding-top: 20px; + padding-left: 21px; + + @include on-tablet { + padding-top: 33px; + padding-left: 33px; + } + } + } + + &__nav { + display: flex; + flex-direction: column; + gap: 22px; + + padding-bottom: 22px; + padding-left: 21px; + + @include on-tablet { + padding-left: 152px; + } + } + + &__language-button--selected { + color: $color-contrast-color; + + &::after { + content: ''; + + position: absolute; + z-index: -1; + top: -11px; + left: -21px; + + width: 100vw; + height: 49px; + + background-color: #110e25; + + transition: width $animation-speed; + + @include on-tablet { + left: -152px; + } + } + } +} diff --git a/src/styles/modals/faq.scss b/src/styles/modals/faq.scss new file mode 100644 index 00000000..faab6e10 --- /dev/null +++ b/src/styles/modals/faq.scss @@ -0,0 +1,167 @@ +.faq { + box-sizing: border-box; + height: 100%; + padding-inline: 20px; + + @include on-tablet { + padding-inline: 34px; + } + + @include on-desktop { + padding-inline: 90px; + } + + @include on-big-desktop { + padding-right: 92px; + padding-left: 95px; + } + + &__title { + margin: 0; + margin-bottom: 30px; + padding-top: 68px; + color: white; + + &--blue { + color: $color-contrast-color; + } + + @include on-tablet { + max-width: 280px; + } + + @include on-desktop { + max-width: 520px; + margin-bottom: 50px; + padding-top: 60px; + } + + @include on-big-desktop { + max-width: 622px; + margin-bottom: 37px; + padding-top: 70px; + } + } + + &__info { + display: flex; + flex-direction: column; + gap: 13px; + + @include on-tablet { + gap: 18px; + } + + @include on-desktop { + gap: 15px; + } + } + + &__card { + box-sizing: border-box; + max-height: 84px; + padding-top: 20px; + padding-bottom: 12px; + padding-inline: 12px; + border: 1px solid $color-contrast-color; + border-radius: 4px; + + transition: max-height $animation-speed; + + @include on-tablet { + max-height: 54px; + padding-left: 30px; + padding-block: 14px; + } + + @include on-desktop { + max-height: 60px; + padding-block: 18px; + } + + &-arrow { + display: none; + + @include on-desktop { + rotate: -90deg; + + display: block; + + width: 9px; + height: 6px; + padding-top: 10px; + + transition: rotate, $animation-speed; + } + } + + &-answer { + pointer-events: none; + margin-top: 0; + margin-bottom: 10px; + opacity: 0; + + @include on-tablet { + margin-bottom: 15px; + } + + @include on-desktop { + margin-bottom: 20px; + } + } + + &-date { + pointer-events: none; + + margin-top: 0; + margin-bottom: 14px; + + color: #545454; + + opacity: 0; + + @include on-tablet { + margin-bottom: 24px; + } + + @include on-desktop { + margin-bottom: 21px; + } + + @include on-big-desktop { + margin-bottom: 23px; + } + } + + &--active { + max-height: 608px; + padding-bottom: 0; + + .faq__card-answer { + opacity: 1; + } + + .faq__card-date { + opacity: 1; + } + + .faq__card-arrow { + rotate: 0deg; + } + } + + &-title { + margin: 0; + margin-bottom: 18px; + color: $color-contrast-color; + + &-wrapper { + cursor: pointer; + display: flex; + justify-content: space-between; + + @include hover(transform, scale(1.01)); + } + } + } +} diff --git a/src/styles/modals/help.scss b/src/styles/modals/help.scss new file mode 100644 index 00000000..33ec2d31 --- /dev/null +++ b/src/styles/modals/help.scss @@ -0,0 +1,94 @@ +.help { + height: 100%; + padding-top: 68px; + padding-inline: 20px; + + @include on-tablet { + padding-top: 102px; + padding-inline: 34px; + } + + @include on-desktop { + padding-top: 60px; + padding-inline: 90px; + } + + @include on-big-desktop { + padding-inline: 93px; + } + + &__title { + margin: 0; + margin-bottom: 30px; + color: white; + + @include on-desktop { + margin-bottom: 50px; + } + &--blue { + color: $color-contrast-color; + } + } + + &__info { + margin-bottom: 30px; + + @include on-tablet { + margin-bottom: 20px; + } + + &-goal { + box-sizing: border-box; + margin-top: 0; + margin-bottom: 32px; + } + + &-contacts { + box-sizing: border-box; + margin-top: 0; + } + } + + &__links { + display: flex; + flex-direction: column; + gap: 30px; + + @include on-tablet { + flex-direction: row; + gap: 152px; + } + + @include on-desktop { + gap: 65px; + } + + @include on-big-desktop { + gap: 71px; + } + } + + &__product-info { + display: flex; + flex-direction: column; + gap: 20px; + + @include on-tablet { + gap: 20px; + } + } + + &__contacts { + display: flex; + flex-direction: column; + gap: 11px; + + @include on-tablet { + gap: 20px; + } + + &-link { + color: $color-text-color; + } + } +} diff --git a/src/styles/modals/modal.scss b/src/styles/modals/modal.scss new file mode 100644 index 00000000..20fc0f43 --- /dev/null +++ b/src/styles/modals/modal.scss @@ -0,0 +1,147 @@ +.modal { + --inline-position: 0; + --block-position: 0; + + pointer-events: none; + + position: fixed; + z-index: 101; + inset: var(--block-position) var(--inline-position) var(--block-position) + var(--inline-position); + inset: 0; + transform: translateX(-100%); + + overflow: hidden auto; + overscroll-behavior: none; + + width: auto; + height: auto; + + opacity: 0; + background-color: $color-gradient-start; + &--active { + pointer-events: all; + transform: translateX(0); + opacity: 1; + } + + &--video { + aspect-ratio: auto; + border-radius: 4px; + + @include on-desktop { + --block-position: calc((100% - 486px) / 2); + --inline-position: calc((100% - 876px) / 2); + } + + & iframe { + width: 100%; + height: 100%; + border: none; + } + } + + &--faq { + border-radius: 4px; + + @include on-desktop { + --block-position: max(calc((100% - 854px) / 2), 0px); + --inline-position: calc((100% - 880px) / 2); + } + + @include on-big-desktop { + --block-position: max(calc((100% - 793px) / 2), 0px); + --inline-position: calc((100% - 1083px) / 2); + } + } + + &--help { + @include on-desktop { + --block-position: max(calc((100% - 550px) / 2), 0px); + --inline-position: calc((100% - 880px) / 2); + } + + @include on-big-desktop { + --block-position: max(calc((100% - 518px) / 2), 0px); + --inline-position: calc((100% - 1083px) / 2); + } + } + + &__content { + width: 100vw; + height: 100vh; + + &--video { + @include on-desktop { + width: 876px; + height: 486px; + } + } + + &--faq { + @include on-desktop { + width: 880px; + max-height: 854px; + } + + @include on-big-desktop { + width: 1083px; + max-height: 793px; + } + } + + &--help { + height: 100%; + + @include on-tablet { + max-height: 596px; + } + + @include on-desktop { + width: 880px; + max-height: 550px; + } + + @include on-big-desktop { + width: 1083px; + max-height: 518px; + } + } + } + + &__close { + cursor: pointer; + + position: fixed; + z-index: inherit; + top: 20px; + right: 20px; + + width: 17px; + height: 17px; + border: 0; + + background-color: transparent; + background-image: url('./../images/icon/icon-close.svg'); + + @include on-tablet { + top: 34px; + right: 34px; + } + + @include on-desktop { + top: 18px; + right: 18px; + } + + @include on-big-desktop { + top: 28px; + right: 28px; + } + + &--video { + top: 15px; + right: 13px; + } + } +} diff --git a/src/styles/modals/payment.scss b/src/styles/modals/payment.scss new file mode 100644 index 00000000..e49cfedc --- /dev/null +++ b/src/styles/modals/payment.scss @@ -0,0 +1,386 @@ +.payment { + &__step { + pointer-events: none; + + position: absolute; + right: 0; + left: 0; + transform: translateX(-100%); + + display: none; + + box-sizing: border-box; + height: calc(100% - 100px); + padding-inline: 20px; + + opacity: 0; + background: linear-gradient( + 107.56deg, + $color-gradient-start 0%, + black 100% + ); + box-shadow: 4px 4px 40px 0 #00000040; + + @include on-tablet { + height: calc(100% - 107px); + padding-inline: 34px; + } + + @include on-desktop { + height: calc(100vh - 107px); + padding-inline: 110px; + } + + @include on-big-desktop { + padding-inline: 235px; + } + + &--active { + pointer-events: all; + + position: relative; + transform: translateX(0); + + overflow: auto; + display: block; + + opacity: 1; + + transition: transform, $animation-speed; + } + + &-indicator { + --steps: 3; + --step: 0; + + width: auto; + height: 18px; + + &::after { + content: ''; + + position: absolute; + bottom: -17px; + left: -20px; + transform: translateX(calc(var(--step) * 100%)); + + width: calc(100vw / var(--steps)); + border: 1px solid $color-contrast-color; + + transition: transform $animation-speed ease; + + @include on-tablet { + bottom: -10px; + left: -34px; + } + + @include on-desktop { + bottom: 0; + left: 0; + + width: 4px; + height: 4px; + border-radius: 50%; + + opacity: 0; + background-color: $color-contrast-color; + } + } + + &--active { + color: $color-contrast-color; + + &::after { + transform: translateX(calc(var(--step) * 100%)); + + @include on-desktop { + transform: translateX(var(--dot-x)); + opacity: 1; + } + } + } + } + } + + &__top-bar { + display: flex; + flex-direction: column; + gap: 33px; + + box-sizing: border-box; + height: 100px; + padding-top: 20px; + padding-inline: 20px; + + background: linear-gradient( + 107.56deg, + $color-gradient-start 0%, + black 100% + ); + background-color: $color-gradient-start; + box-shadow: 4px 4px 40px 0 #00000040; + + @include on-tablet { + height: 107px; + padding-top: 30px; + padding-inline: 34px; + } + + @include on-desktop { + flex-direction: row; + gap: 191px; + padding-top: 65px; + padding-inline: 110px; + } + + @include on-big-desktop { + gap: 288px; + padding-inline: 235px; + } + + &-link { + cursor: pointer; + display: flex; + width: 58px; + height: 12px; + + @include hover(transform, scale(1.1)); + + @include on-tablet { + width: 67px; + height: 14px; + } + + @include on-desktop { + width: 78px; + height: 16px; + } + } + + &-logo { + width: 100%; + } + } + + &__step-bar { + --dot-x: 0; + + position: relative; + display: flex; + justify-content: space-between; + + &::before { + content: ''; + + position: absolute; + bottom: -17px; + left: -20px; + + box-sizing: border-box; + width: 100vw; + border: 1px solid #2f2f2f; + + @include on-tablet { + bottom: -10px; + left: -34px; + } + + @include on-desktop { + display: none; + } + } + + @include on-tablet { + min-width: 584px; + padding-left: 54px; + } + + @include on-desktop { + width: 647px; + } + + @include on-big-desktop { + width: 842px; + } + } + + &__complete { + &-info { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + } + + &-title { + margin: 0; + margin-top: 90px; + margin-bottom: 16px; + color: white; + + &--blue { + color: $color-contrast-color; + } + + @include on-tablet { + max-width: 680px; + margin-top: 180px; + margin-bottom: 20px; + } + + @include on-desktop { + max-width: 707px; + margin-top: 140px; + margin-bottom: 36px; + } + + @include on-big-desktop { + margin-top: 236px; + margin-bottom: 56px; + } + } + + &-description { + display: block; + margin-bottom: 30px; + color: white; + text-align: center; + + @include on-tablet { + margin-bottom: 50px; + } + + @include on-big-desktop { + margin-bottom: 70px; + } + } + } + + &__homepage-button { + width: 100%; + height: 40px; + + @include on-tablet { + width: 458px; + height: 48px; + } + + @include on-desktop { + width: 218px; + } + } + + &__order { + @include on-desktop { + display: flex; + gap: 80px; + box-sizing: border-box; + padding-top: 102px; + } + + @include on-big-desktop { + padding-top: 219px; + } + &-top { + padding-top: 30px; + padding-bottom: 30px; + padding-left: 14px; + + @include on-tablet { + padding-top: 40px; + padding-bottom: 48px; + padding-left: 0; + } + + @include on-desktop { + padding-top: 0; + padding-bottom: 0; + } + } + + &-price { + display: flex; + gap: 75px; + + @include on-tablet { + gap: 148px; + margin-left: 122px; + } + + @include on-desktop { + margin-left: 0; + } + } + + &-bottom { + @include on-big-desktop { + padding-top: 43px; + } + } + + &-form { + display: flex; + flex-direction: column; + gap: 30px; + + @include page-grid; + } + + &-background { + display: none; + + @include on-tablet { + display: block; + width: 524px; + height: 277px; + margin-left: 70px; + } + + @include on-desktop { + width: 442px; + height: 279px; + margin-top: 29px; + margin-bottom: 48px; + margin-left: 0; + + object-fit: cover; + } + + @include on-big-desktop { + width: 800px; + height: 447px; + margin-top: 0; + margin-bottom: 0; + } + } + } + + &__price { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; + + @include on-tablet { + gap: 20px; + align-items: start; + } + + &-amount { + color: $color-contrast-color; + } + } + + &__pay { + @include on-desktop { + display: flex; + gap: 19px; + box-sizing: border-box; + padding-top: 102px; + } + + @include on-big-desktop { + padding-top: 219px; + } + } +} diff --git a/src/styles/more.scss b/src/styles/more.scss new file mode 100644 index 00000000..629edaf4 --- /dev/null +++ b/src/styles/more.scss @@ -0,0 +1,170 @@ +.more { + max-height: 67px; + transition: height $animation-speed ease; + + @include on-tablet { + padding-top: 70px; + } + + @include on-desktop { + max-height: 0; + padding-top: 0; + } + + &-info { + pointer-events: none; + + transform: translateY(-100%); + + display: flex; + flex-direction: column; + gap: 11px; + + opacity: 0; + + transition: + opacity $animation-speed ease, + transform $animation-speed ease; + + @include on-tablet { + grid-column: span 3; + text-align: center; + } + + @include on-big-desktop { + grid-column: span 4; + } + + &__title { + margin: 0; + color: white; + + @include on-tablet { + gap: 20px; + } + } + + &__description { + height: 49px; + margin: 0; + color: $color-text-color; + + @include on-tablet { + height: 77px; + } + + @include on-desktop { + height: 97px; + } + + @include on-big-desktop { + height: 76px; + } + } + + &__icon { + display: none; + + @include on-tablet { + display: block; + align-self: center; + + width: 84px; + height: 84px; + margin-bottom: 22px; + + @include hover(transform, scale(1.1)); + } + + @include on-big-desktop { + width: 98px; + height: 81px; + } + } + } + + &--active { + max-height: 100%; + padding-bottom: 50px; + .more-info { + pointer-events: all; + transform: translateY(0); + opacity: 1; + } + + @include on-desktop { + padding-block: 100px; + + .more__top { + transform: translateY(0); + opacity: 1; + } + } + + @include on-big-desktop { + padding-block: 158px; + } + } + + &__wrapper { + display: flex; + flex-direction: column; + gap: 30px; + + @include on-desktop { + gap: 83px; + } + + @include on-big-desktop { + gap: 70px; + } + } + + &__top { + cursor: pointer; + height: 67px; + text-align: center; + + @include hover(transform, scale(1.1)); + + @include on-desktop { + cursor: auto; + transform: translateY(-100%); + opacity: 0; + transition: + opacity $animation-speed ease, + transform $animation-speed ease; + + @include hover(transform, none); + } + } + + &__bottom { + display: flex; + flex-direction: column; + gap: 20px; + + @include on-tablet { + @include page-grid; + } + } + + &__description { + margin: 0; + color: $color-contrast-color; + } + + &__title { + margin: 0; + margin-bottom: 12px; + color: white; + + @include on-desktop { + margin-bottom: 16px; + } + + &--blue { + color: $color-contrast-color; + } + } +} diff --git a/src/styles/nav.scss b/src/styles/nav.scss new file mode 100644 index 00000000..71502d5e --- /dev/null +++ b/src/styles/nav.scss @@ -0,0 +1,46 @@ +.nav { + list-style: none; + + &--horizontal { + display: none; + + @include on-desktop { + display: flex; + gap: 36px; + } + } + + &__item { + @include hover(transform, scale(1.1)); + } + + &__button { + @include hover(color, $color-contrast-color); + + position: relative; + + &::after { + content: ''; + + position: absolute; + z-index: -1; + top: -11px; + left: -21px; + + width: 0; + height: 49px; + + background-color: #110e25; + + transition: width $animation-speed; + + @include on-tablet { + left: -152px; + } + } + + &:hover::after { + width: 100vw; + } + } +} diff --git a/src/styles/quantity.scss b/src/styles/quantity.scss new file mode 100644 index 00000000..3ce5bfa0 --- /dev/null +++ b/src/styles/quantity.scss @@ -0,0 +1,46 @@ +.quantity { + &-label { + padding-left: 6px; + } + + &-dropdown { + display: flex; + flex-direction: column; + gap: 10px; + + @include on-tablet { + gap: 20px; + } + + &__select { + position: relative; + + display: flex; + align-items: center; + justify-content: center; + + box-sizing: border-box; + width: 90px; + height: 41px; + padding-left: 30px; + + background-color: $color-gradient-start; + } + + &__selected { + display: flex; + gap: 21px; + color: white; + } + + &__options { + width: 90px; + color: white; + } + + &__option { + width: 100%; + text-align: center; + } + } +} diff --git a/src/styles/slider-about.scss b/src/styles/slider-about.scss new file mode 100644 index 00000000..8ca2ab42 --- /dev/null +++ b/src/styles/slider-about.scss @@ -0,0 +1,155 @@ +.slider-about { + --steps: 5; + --step: 0; + &__content { + height: 207px; + + @include on-tablet { + width: 340px; + height: 289px; + } + + @include on-desktop { + display: flex; + gap: 23px; + width: 474px; + height: 300px; + } + + @include on-big-desktop { + width: 666px; + height: 307px; + } + } + + &__counter { + display: none; + color: $color-contrast-color; + + @include on-desktop { + display: block; + display: flex; + width: 21px; + } + } + + &__images { + position: relative; + height: 189px; + + @include on-tablet { + height: 270px; + } + + @include on-desktop { + width: 430px; + height: 290px; + } + + @include on-big-desktop { + width: 622px; + } + } + + &__image { + pointer-events: none; + + position: absolute; + transform: translateX(-100%); + + width: 100%; + height: 100%; + + opacity: 0; + object-fit: cover; + + transition: + transform $animation-speed ease, + opacity $animation-speed ease; + + &--active { + pointer-events: all; + transform: translateX(0); + opacity: 1; + } + } + + &__buttons { + display: none; + + @include on-desktop { + position: relative; + + display: flex; + gap: 103px; + + width: 205px; + margin-top: 12px; + margin-left: 40px; + + &::before { + content: ''; + + position: absolute; + bottom: -10px; + + width: 100%; + border-bottom: 1px solid #212121; + } + &::after { + content: ''; + + position: absolute; + bottom: -10px; + transform: translateX(calc(var(--step) * 100%)); + + width: calc(100% / var(--steps)); + border: 1px solid $color-contrast-color; + + transition: transform $animation-speed ease; + } + } + + @include on-big-desktop { + margin-top: 12px; + } + } + + &__button { + padding: 0; + background-color: inherit; + + @include hover(color, $color-contrast-color); + + &--disabled { + pointer-events: none; + color: $color-text-color; + } + } + + &__dots { + display: flex; + gap: 6px; + justify-content: center; + margin-top: 14px; + + @include on-tablet { + margin-top: 15px; + } + + @include on-desktop { + display: none; + } + } + + &__dot { + width: 4px; + height: 4px; + border-radius: 50%; + background-color: #484848; + + &--active { + background-color: #ababab; + } + } +} diff --git a/src/styles/svg.scss b/src/styles/svg.scss new file mode 100644 index 00000000..093253f9 --- /dev/null +++ b/src/styles/svg.scss @@ -0,0 +1,3 @@ +.svg { + display: none; +} diff --git a/src/styles/tech.scss b/src/styles/tech.scss new file mode 100644 index 00000000..275f2b30 --- /dev/null +++ b/src/styles/tech.scss @@ -0,0 +1,89 @@ +.tech { + padding-block: 50px; + + @include on-tablet { + padding-block: 80px; + } + + @include on-desktop { + padding-block: 100px; + } + + @include on-big-desktop { + padding-block: 160px; + } + + &__title { + color: white; + + &--blue { + color: $color-contrast-color; + } + + @include on-desktop { + display: flex; + justify-content: flex-end; + margin-right: 75px; + } + } + + &__content { + position: relative; + + width: 197px; + height: 194px; + margin-top: 30px; + margin-left: 42px; + + @include on-tablet { + width: 415px; + height: 380px; + } + + @include on-desktop { + width: 1055px; + height: 355px; + margin-top: 80px; + margin-left: 3px; + } + + @include on-big-desktop { + width: 1175px; + margin-left: 192px; + } + } + + &__background { + position: relative; + width: 100%; + + @include on-tablet { + width: 358px; + height: 354px; + margin-left: 57px; + } + + @include on-desktop { + width: 297px; + height: 294px; + margin: 0; + margin-top: 61px; + margin-left: 357px; + } + } + + &__ellipse { + display: none; + + @include on-desktop { + position: absolute; + bottom: 53px; + left: 341px; + + display: block; + + width: 40px; + height: 201px; + } + } +} diff --git a/src/styles/top-bar.scss b/src/styles/top-bar.scss new file mode 100644 index 00000000..6b840788 --- /dev/null +++ b/src/styles/top-bar.scss @@ -0,0 +1,59 @@ +.top-bar { + display: flex; + align-items: center; + justify-content: space-between; + padding-block: 18px 14px; + + @include on-tablet { + padding-block: 30px 55px; + } + + @include on-desktop { + padding-block: 47px 101px; + } + + @include on-big-desktop { + padding-bottom: 232px; + } + + &__left { + display: flex; + flex-direction: row; + + @include on-desktop { + gap: 34px; + align-items: center; + } + } + + &__link { + cursor: pointer; + display: flex; + width: 58px; + height: 12px; + + @include hover(transform, scale(1.1)); + } + + &__logo { + width: 100%; + } + + &__navigation { + display: flex; + gap: 37px; + align-items: center; + + @include on-big-desktop { + gap: 35px; + } + } + + &__button { + display: none; + + @include on-desktop { + display: block; + } + } +} diff --git a/src/styles/utils/_extends.scss b/src/styles/utils/_extends.scss deleted file mode 100644 index d7201e7b..00000000 --- a/src/styles/utils/_extends.scss +++ /dev/null @@ -1,4 +0,0 @@ -%h1 { - font-family: Roboto, sans-serif; - font-weight: 400; -} diff --git a/src/styles/utils/_fonts.scss b/src/styles/utils/_fonts.scss new file mode 100644 index 00000000..8dd86917 --- /dev/null +++ b/src/styles/utils/_fonts.scss @@ -0,0 +1,6 @@ +@font-face { + font-family: Inter; + font-weight: 100 900; + font-style: normal; + src: url('./../fonts/Inter.ttf') format('truetype'); +} diff --git a/src/styles/utils/_mixins.scss b/src/styles/utils/_mixins.scss index 80c79780..64171911 100644 --- a/src/styles/utils/_mixins.scss +++ b/src/styles/utils/_mixins.scss @@ -1,6 +1,102 @@ +@use 'sass:map'; + @mixin hover($_property, $_toValue) { - transition: #{$_property} 0.3s; + transition: #{$_property} $animation-speed; &:hover { #{$_property}: $_toValue; } } + +@mixin on-tablet { + @media (min-width: $tablet-min-width) { + @content; + } +} + +@mixin on-desktop { + @media (min-width: $desktop-min-width) { + @content; + } +} + +@mixin on-big-desktop { + @media (min-width: $big-desktop-min-width) { + @content; + } +} + +@mixin set-font($fontProperties) { + $size-map: map.get($fontProperties, size); + + font-family: map.get($fontProperties, font); + font-size: font-size($size-map, mobile); + font-weight: map.get($fontProperties, weight); + font-style: map.get($fontProperties, style); + line-height: map.get($fontProperties, height); + text-transform: map.get($fontProperties, transorm); + letter-spacing: map.get($fontProperties, spacing); + + @include on-tablet { + font-size: font-size($size-map, tablet, mobile); + } + + @include on-desktop { + font-size: font-size($size-map, desktop, tablet, mobile); + } + + @include on-big-desktop { + font-size: font-size($size-map, big-desktop, desktop, tablet, mobile); + } +} + +@mixin content-padding-inline { + --padding: 20px; + + padding-inline: var(--padding); + + @include on-tablet { + --padding: 34px; + } + + @include on-desktop { + --padding: 110px; + } + + @include on-big-desktop { + --padding: 234px; + } +} + +@function font-size($map, $keys...) { + @each $key in $keys { + @if map.has-key($map, $key) { + @return map.get($map, $key); + } + } + + @return null; +} + +@mixin page-grid { + --columns: 2; + + display: grid; + grid-template-columns: repeat(var(--columns), 1fr); + gap: 30px 19px; + + @include on-tablet { + --columns: 6; + } + + @include on-desktop { + --columns: 12; + + gap: 40px 20px; + } + + @include on-big-desktop { + --columns: 16; + + gap: 40px 19px; + } +} diff --git a/src/styles/utils/_typography.scss b/src/styles/utils/_typography.scss new file mode 100644 index 00000000..fc9e0d2b --- /dev/null +++ b/src/styles/utils/_typography.scss @@ -0,0 +1,5 @@ +@each $name, $styles in $fonts { + .font-#{$name} { + @include set-font($styles); + } +} diff --git a/src/styles/utils/_vars.scss b/src/styles/utils/_vars.scss index aeb006ff..a55002d2 100644 --- a/src/styles/utils/_vars.scss +++ b/src/styles/utils/_vars.scss @@ -1 +1,209 @@ -$c-gray: #eee; +$animation-speed: 0.3s; +$color-contrast-color: #05c2df; +$ccolor-background-black: #05040b; +$color-dark-grey: #2f2f2f; +$color-text-color: #929292; +$color-gradient-start: #191536; +$main-font: Inter, Arial, Helvetica, sans-serif; +$tablet-min-width: 640px; +$desktop-min-width: 1280px; +$big-desktop-min-width: 1922px; +$fonts: ( + h1: ( + font: $main-font, + weight: 400, + size: ( + mobile: 26px, + tablet: 26px, + desktop: 46px, + big-desktop: 54px, + ), + height: 130%, + ), + h1-bold: ( + font: $main-font, + weight: 900, + size: ( + mobile: 26px, + tablet: 26px, + desktop: 46px, + big-desktop: 54px, + ), + height: 130%, + ), + h2: ( + font: $main-font, + weight: 400, + size: ( + mobile: 21px, + tablet: 21px, + desktop: 36px, + big-desktop: 36px, + ), + height: 100%, + ), + h2-bold: ( + font: $main-font, + weight: 900, + size: ( + mobile: 21px, + tablet: 21px, + desktop: 36px, + big-desktop: 36px, + ), + height: 100%, + ), + button-primary: ( + font: $main-font, + weight: 500, + size: ( + mobile: 14px, + tablet: 16px, + desktop: 16px, + big-desktop: 16px, + ), + height: normal, + ), + button-footer: ( + font: $main-font, + weight: 400, + size: ( + mobile: 13px, + tablet: 14px, + desktop: 14px, + big-desktop: 14px, + ), + height: 150%, + ), + main: ( + font: $main-font, + weight: 400, + size: ( + mobile: 16px, + ), + height: 150%, + ), + secondary: ( + font: $main-font, + weight: 400, + size: ( + mobile: 14px, + ), + height: normal, + ), + small: ( + font: $main-font, + weight: 400, + size: ( + mobile: 12px, + desktop: 14px, + ), + height: normal, + ), + header-info: ( + font: $main-font, + weight: 500, + size: ( + mobile: 16px, + big-desktop: 20px, + ), + height: normal, + ), + subtitle: ( + font: $main-font, + weight: 900, + size: ( + mobile: 16px, + tablet: 18px, + ), + height: normal, + ), + ordering-secondary: ( + font: $main-font, + weight: 400, + size: ( + mobile: 18px, + tablet: 20px, + ), + height: normal, + ), + menu: ( + font: $main-font, + weight: 500, + size: ( + mobile: 21px, + ), + height: normal, + ), + select-quanity: ( + font: $main-font, + weight: 500, + size: ( + mobile: 20px, + ), + height: normal, + ), + ordering-price: ( + font: $main-font, + weight: 500, + size: ( + mobile: 26px, + tablet: 36px, + ), + height: normal, + ), + ordering-h2: ( + font: $main-font, + weight: 500, + size: ( + mobile: 26px, + tablet: 46px, + ), + height: normal, + ), + ordering-h2-bold: ( + font: $main-font, + weight: 900, + size: ( + mobile: 26px, + tablet: 46px, + ), + height: normal, + ), + price: ( + font: $main-font, + weight: 500, + size: ( + mobile: 18px, + big-desktop: 20px, + ), + height: normal, + ), + ordering-step: ( + font: $main-font, + weight: 500, + size: ( + mobile: 12px, + tablet: 14px, + ), + height: normal, + ), + ordering-thanks: ( + font: $main-font, + weight: 500, + size: ( + mobile: 16px, + tablet: 18px, + ), + height: 130%, + ), + about-words: ( + font: $main-font, + weight: 900, + size: ( + tablet: 48px, + desktop: 64px, + ), + height: 130%, + ), +);