full nav change
This commit is contained in:
378
package-lock.json
generated
378
package-lock.json
generated
@@ -35,6 +35,7 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "*",
|
||||
"cmdk": "^1.1.1",
|
||||
@@ -53,7 +54,7 @@
|
||||
"recharts": "^2.15.2",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwind-merge": "*",
|
||||
"tailwindcss": "^4.1.13",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"vaul": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -92,7 +93,6 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -109,7 +109,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -126,7 +125,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -143,7 +141,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -160,7 +157,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -177,7 +173,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -194,7 +189,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -211,7 +205,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -228,7 +221,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -245,7 +237,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -262,7 +253,6 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -279,7 +269,6 @@
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -296,7 +285,6 @@
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -313,7 +301,6 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -330,7 +317,6 @@
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -347,7 +333,6 @@
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -364,7 +349,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -381,7 +365,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -398,7 +381,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -415,7 +397,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -432,7 +413,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -449,7 +429,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -466,7 +445,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -483,7 +461,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -500,7 +477,6 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -517,7 +493,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1956,7 +1931,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1970,7 +1944,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1984,7 +1957,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1998,7 +1970,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2012,7 +1983,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2026,7 +1996,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2040,7 +2009,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2054,7 +2022,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2068,7 +2035,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2082,7 +2048,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2096,7 +2061,6 @@
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2110,7 +2074,6 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2124,7 +2087,6 @@
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2138,7 +2100,6 @@
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2152,7 +2113,6 @@
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2166,7 +2126,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2180,7 +2139,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2194,7 +2152,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2208,7 +2165,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2222,7 +2178,6 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2236,7 +2191,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2484,6 +2438,12 @@
|
||||
"tailwindcss": "4.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/node/node_modules/tailwindcss": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
|
||||
"integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz",
|
||||
@@ -2730,6 +2690,274 @@
|
||||
"tailwindcss": "4.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/postcss/node_modules/tailwindcss": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
|
||||
"integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tailwindcss/vite": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.14.tgz",
|
||||
"integrity": "sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tailwindcss/node": "4.1.14",
|
||||
"@tailwindcss/oxide": "4.1.14",
|
||||
"tailwindcss": "4.1.14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^5.2.0 || ^6 || ^7"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/node": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz",
|
||||
"integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.4",
|
||||
"enhanced-resolve": "^5.18.3",
|
||||
"jiti": "^2.6.0",
|
||||
"lightningcss": "1.30.1",
|
||||
"magic-string": "^0.30.19",
|
||||
"source-map-js": "^1.2.1",
|
||||
"tailwindcss": "4.1.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz",
|
||||
"integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.4",
|
||||
"tar": "^7.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tailwindcss/oxide-android-arm64": "4.1.14",
|
||||
"@tailwindcss/oxide-darwin-arm64": "4.1.14",
|
||||
"@tailwindcss/oxide-darwin-x64": "4.1.14",
|
||||
"@tailwindcss/oxide-freebsd-x64": "4.1.14",
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14",
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.14",
|
||||
"@tailwindcss/oxide-linux-arm64-musl": "4.1.14",
|
||||
"@tailwindcss/oxide-linux-x64-gnu": "4.1.14",
|
||||
"@tailwindcss/oxide-linux-x64-musl": "4.1.14",
|
||||
"@tailwindcss/oxide-wasm32-wasi": "4.1.14",
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.14",
|
||||
"@tailwindcss/oxide-win32-x64-msvc": "4.1.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-android-arm64": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz",
|
||||
"integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-darwin-arm64": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz",
|
||||
"integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-darwin-x64": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz",
|
||||
"integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-freebsd-x64": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz",
|
||||
"integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz",
|
||||
"integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz",
|
||||
"integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-arm64-musl": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz",
|
||||
"integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz",
|
||||
"integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz",
|
||||
"integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-wasm32-wasi": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz",
|
||||
"integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==",
|
||||
"bundleDependencies": [
|
||||
"@napi-rs/wasm-runtime",
|
||||
"@emnapi/core",
|
||||
"@emnapi/runtime",
|
||||
"@tybys/wasm-util",
|
||||
"@emnapi/wasi-threads",
|
||||
"tslib"
|
||||
],
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "^1.5.0",
|
||||
"@emnapi/runtime": "^1.5.0",
|
||||
"@emnapi/wasi-threads": "^1.1.0",
|
||||
"@napi-rs/wasm-runtime": "^1.0.5",
|
||||
"@tybys/wasm-util": "^0.10.1",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz",
|
||||
"integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-win32-x64-msvc": {
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz",
|
||||
"integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-array": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz",
|
||||
@@ -2797,14 +3025,13 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.13.tgz",
|
||||
"integrity": "sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
@@ -3125,7 +3352,6 @@
|
||||
"version": "0.25.9",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
|
||||
"integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -3182,7 +3408,6 @@
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
@@ -3227,7 +3452,6 @@
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
@@ -3273,9 +3497,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
|
||||
"integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==",
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
@@ -3561,9 +3785,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
|
||||
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
|
||||
"integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minipass": "^7.1.2"
|
||||
@@ -3572,21 +3796,6 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
||||
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mkdirp": "dist/cjs/src/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/motion": {
|
||||
"version": "12.23.12",
|
||||
"resolved": "https://registry.npmjs.org/motion/-/motion-12.23.12.tgz",
|
||||
@@ -3675,7 +3884,6 @@
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -3974,7 +4182,6 @@
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz",
|
||||
"integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
@@ -4056,9 +4263,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
|
||||
"integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==",
|
||||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
|
||||
"integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
@@ -4075,16 +4282,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
||||
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
||||
"version": "7.5.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz",
|
||||
"integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
"chownr": "^3.0.0",
|
||||
"minipass": "^7.1.2",
|
||||
"minizlib": "^3.0.1",
|
||||
"mkdirp": "^3.0.1",
|
||||
"minizlib": "^3.1.0",
|
||||
"yallist": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -4101,7 +4307,6 @@
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
@@ -4124,7 +4329,7 @@
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/use-callback-ref": {
|
||||
@@ -4218,7 +4423,6 @@
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
||||
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "*",
|
||||
"cmdk": "^1.1.1",
|
||||
@@ -48,7 +49,7 @@
|
||||
"recharts": "^2.15.2",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwind-merge": "*",
|
||||
"tailwindcss": "^4.1.13",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"vaul": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ReactNode } from 'react';
|
||||
import Navbar from './components/Navbar';
|
||||
import { CitySubmenu } from './components/CitySubmenu';
|
||||
import { Footer } from './components/Footer';
|
||||
|
||||
interface User {
|
||||
@@ -11,7 +10,6 @@ interface User {
|
||||
interface LayoutProps {
|
||||
children: ReactNode;
|
||||
activeCity?: string;
|
||||
showCitySubmenu?: boolean;
|
||||
onSignInClick?: () => void; // ✅ optional
|
||||
onSignOutClick?: () => void;
|
||||
user?: User | null;
|
||||
@@ -20,7 +18,6 @@ interface LayoutProps {
|
||||
export function Layout({
|
||||
children,
|
||||
activeCity = 'Melbourne',
|
||||
showCitySubmenu = false,
|
||||
onSignInClick,
|
||||
onSignOutClick,
|
||||
user
|
||||
@@ -37,9 +34,6 @@ export function Layout({
|
||||
user={user}
|
||||
/>
|
||||
|
||||
{/* City Submenu */}
|
||||
{showCitySubmenu && <CitySubmenu onClose={() => {}} />}
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="flex-1">{children}</main>
|
||||
|
||||
|
||||
@@ -282,7 +282,6 @@ export function AttractionsPage({
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
user={user}
|
||||
showCitySubmenu={true}
|
||||
>
|
||||
<div className="container mx-auto px-4 pt-56 pb-16">
|
||||
{/* Page Header */}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/
|
||||
import { Badge } from './ui/badge';
|
||||
import { Input } from './ui/input';
|
||||
import Navbar from './Navbar';
|
||||
import { CitySubmenu } from './CitySubmenu';
|
||||
// import { CitySubmenu } from './CitySubmenu';
|
||||
import { MobileAppSection } from './MobileAppSection';
|
||||
import { WhyChooseCityCards } from './WhyChooseCityCards';
|
||||
import { EnhancedTestimonials } from './EnhancedTestimonials';
|
||||
@@ -226,7 +226,7 @@ export function BlogsPage({
|
||||
user={user}
|
||||
/>
|
||||
|
||||
<CitySubmenu
|
||||
{/* <CitySubmenu
|
||||
currentPage={currentPage}
|
||||
onClose={() => {}}
|
||||
onHomeClick={onHomeClick}
|
||||
@@ -235,7 +235,7 @@ export function BlogsPage({
|
||||
onPassesClick={onPassesClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<div className="container mx-auto px-4 pt-52 pb-12 relative z-10">
|
||||
{/* Page Header */}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Textarea } from './ui/textarea';
|
||||
import Navbar from './Navbar';
|
||||
import { Footer } from './Footer';
|
||||
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||||
import { Layout } from '../Layout';
|
||||
|
||||
interface CheckoutPageProps {
|
||||
onBackClick: () => void;
|
||||
@@ -179,33 +180,12 @@ export function CheckoutPage({
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Navbar */}
|
||||
<Navbar
|
||||
activeCity="Paris"
|
||||
onCityChange={() => {}}
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onCheckoutClick={onCheckoutClick}
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onProfileClick={onProfileClick}
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
onPostCardsClick={onPostCardsClick}
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
currentPage={currentPage}
|
||||
isUserSignedIn={!!user}
|
||||
user={user}
|
||||
/>
|
||||
<Layout
|
||||
activeCity="Melbourne"
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
user={user}
|
||||
>
|
||||
|
||||
{/* Header Section */}
|
||||
<section className="pt-32 pb-8 bg-gradient-to-br from-muted/30 to-background">
|
||||
@@ -748,20 +728,7 @@ export function CheckoutPage({
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Footer */}
|
||||
<Footer
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onSignInClick={onSignInClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onContactUsClick={onContactUsClick}
|
||||
currentPage={currentPage}
|
||||
/>
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { Button } from './ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card';
|
||||
import { Badge } from './ui/badge';
|
||||
import Navbar from './Navbar';
|
||||
import SubNavbar from './SubNavbar';
|
||||
// import SubNavbar from './SubNavbar';
|
||||
import { Footer } from './Footer';
|
||||
import { MobileAppSection } from './MobileAppSection';
|
||||
import { EnhancedTestimonials } from './EnhancedTestimonials';
|
||||
@@ -13,6 +13,7 @@ import { FAQPage } from './FAQPage';
|
||||
import { HowItWorks } from './HowItWorks';
|
||||
import { WhyChooseCityCards } from './WhyChooseCityCards';
|
||||
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||||
import { Layout } from '../Layout';
|
||||
|
||||
interface User {
|
||||
email: string;
|
||||
@@ -73,35 +74,15 @@ export function CityCardsPage({
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Navbar */}
|
||||
<Navbar
|
||||
activeCity=""
|
||||
onCityChange={() => {}}
|
||||
<Layout
|
||||
activeCity="Landingpage"
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onCheckoutClick={onCheckoutClick}
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onProfileClick={onProfileClick}
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
onPostCardsClick={onPostCardsClick}
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
currentPage="citycards"
|
||||
isUserSignedIn={!!user}
|
||||
user={user}
|
||||
/>
|
||||
>
|
||||
|
||||
{/* Sub Navbar */}
|
||||
<SubNavbar
|
||||
{/* Sub Navbar */}
|
||||
{/* <SubNavbar
|
||||
activeTab="citycards"
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
@@ -109,283 +90,270 @@ export function CityCardsPage({
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative pt-52 pb-20 overflow-hidden">
|
||||
{/* Background gradient */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-secondary/5 to-background"></div>
|
||||
{/* Hero Section */}
|
||||
<section className="relative pt-52 pb-20 overflow-hidden">
|
||||
{/* Background gradient */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-secondary/5 to-background"></div>
|
||||
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
<motion.div
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
<h1 className="font-merchant text-4xl md:text-5xl lg:text-6xl leading-tight mb-6">
|
||||
<span className="font-light">What Are</span>{' '}
|
||||
<span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
|
||||
City Cards?
|
||||
</span>
|
||||
</h1>
|
||||
<p className="font-poppins text-xl leading-relaxed font-normal text-gray-600 mb-8 max-w-2xl mx-auto">
|
||||
CityCards are your all-in-one pass to explore cities like never before. Get access to top attractions,
|
||||
skip the lines, and save money while discovering amazing experiences.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Decorative elements */}
|
||||
<div className="absolute top-20 left-10 w-20 h-20 bg-primary/10 rounded-full blur-xl"></div>
|
||||
<div className="absolute bottom-20 right-10 w-32 h-32 bg-secondary/10 rounded-full blur-xl"></div>
|
||||
</section>
|
||||
|
||||
{/* Get Your City Cards Section */}
|
||||
<section className="py-16">
|
||||
<div className="container mx-auto px-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="font-merchant text-3xl mb-4">Get your City Cards</h2>
|
||||
<p className="text-gray-600 font-poppins max-w-2xl mx-auto">
|
||||
Choose from our range of passes designed for every type of traveler and every budget
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
|
||||
{/* Selective Pass */}
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
<motion.div
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.3 }}
|
||||
className="relative flex"
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
<Card className="relative transition-all duration-300 cursor-pointer flex flex-col w-full border-gray-200 shadow-md hover:shadow-lg hover:border-primary/30">
|
||||
<CardHeader className="text-center pb-6 pt-8 flex-shrink-0">
|
||||
<CardTitle className="font-poppins text-2xl font-bold mb-2 text-gray-900">
|
||||
SELECTIVE PASS
|
||||
</CardTitle>
|
||||
<CardDescription className="text-gray-600 mb-6 leading-relaxed font-poppins h-[48px] flex items-center justify-center">
|
||||
Perfect for travelers who want to explore selected attractions at their own pace with essential features.
|
||||
</CardDescription>
|
||||
|
||||
{/* Pricing */}
|
||||
<div className="mb-6">
|
||||
<div className="flex items-baseline justify-center gap-2 mb-2">
|
||||
<span className="text-4xl font-bold text-gray-900">$59.99</span>
|
||||
<span className="text-gray-500 font-poppins">/ per person</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 font-poppins h-[20px]">
|
||||
<span className="line-through mr-2">$89.99</span>
|
||||
<span className="text-green-600 font-medium">Save 33%</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="pt-0 flex flex-col flex-1">
|
||||
{/* Features List - Fixed Height */}
|
||||
<div className="space-y-3 mb-8 flex-1 min-h-[200px]">
|
||||
{[
|
||||
'Access to selected attractions',
|
||||
'Limited number of attractions per pass',
|
||||
'Flexible validity period',
|
||||
'Priority entry where available',
|
||||
'Mobile ticket delivery',
|
||||
'Standard customer support'
|
||||
].map((feature, index) => (
|
||||
<div key={index} className="flex items-start gap-3">
|
||||
<Check className="w-5 h-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span className="text-sm text-gray-700 font-poppins leading-relaxed">{feature}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* CTA Button - Fixed at bottom */}
|
||||
<div className="mt-auto flex-shrink-0">
|
||||
<Button
|
||||
className="w-full py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 bg-gray-900 hover:bg-primary text-white hover:shadow-lg font-poppins"
|
||||
onClick={onCheckoutClick}
|
||||
>
|
||||
PURCHASE NOW
|
||||
</Button>
|
||||
|
||||
<p className="text-xs text-gray-500 text-center mt-4 font-poppins h-[32px] flex items-center justify-center">
|
||||
✓ Free cancellation up to 24 hours • Instant delivery
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
|
||||
{/* Unlimited Pass */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.4 }}
|
||||
className="relative flex"
|
||||
>
|
||||
<Card className="relative transition-all duration-300 cursor-pointer flex flex-col w-full ring-2 ring-primary shadow-xl">
|
||||
|
||||
{/* Popular Badge */}
|
||||
<div className="absolute -top-4 left-1/2 transform -translate-x-1/2 z-10">
|
||||
<Badge className="bg-gradient-to-r from-yellow-400 to-orange-500 text-black px-6 py-2 font-semibold shadow-lg">
|
||||
⭐ Most Popular
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<CardHeader className="text-center pb-6 pt-8 flex-shrink-0">
|
||||
<CardTitle className="font-poppins text-2xl font-bold mb-2 text-gray-900">
|
||||
UNLIMITED CARD
|
||||
</CardTitle>
|
||||
<CardDescription className="text-gray-600 mb-6 leading-relaxed font-poppins h-[48px] flex items-center justify-center">
|
||||
The ultimate experience for adventure seekers who want unlimited access to all attractions with premium features.
|
||||
</CardDescription>
|
||||
|
||||
{/* Pricing */}
|
||||
<div className="mb-6">
|
||||
<div className="flex items-baseline justify-center gap-2 mb-2">
|
||||
<span className="text-4xl font-bold text-gray-900">$89.99</span>
|
||||
<span className="text-gray-500 font-poppins">/ per person</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 font-poppins h-[20px]">
|
||||
<span className="line-through mr-2">$149.99</span>
|
||||
<span className="text-green-600 font-medium">Save 40%</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="pt-0 flex flex-col flex-1">
|
||||
{/* Features List - Fixed Height */}
|
||||
<div className="space-y-3 mb-8 flex-1 min-h-[200px]">
|
||||
{[
|
||||
'Unlimited access to all attractions',
|
||||
'Time-limited validity (7 days)',
|
||||
'Skip-the-line access',
|
||||
'Expert guide inclusion',
|
||||
'Mobile app access',
|
||||
'Premium customer support'
|
||||
].map((feature, index) => (
|
||||
<div key={index} className="flex items-start gap-3">
|
||||
<Check className="w-5 h-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span className="text-sm text-gray-700 font-poppins leading-relaxed">{feature}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* CTA Button - Fixed at bottom */}
|
||||
<div className="mt-auto flex-shrink-0">
|
||||
<Button
|
||||
className="w-full py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 bg-gradient-to-r from-primary to-secondary hover:from-primary/90 hover:to-secondary/90 text-white shadow-lg hover:shadow-xl font-poppins"
|
||||
onClick={onCheckoutClick}
|
||||
>
|
||||
PURCHASE NOW
|
||||
</Button>
|
||||
|
||||
<p className="text-xs text-gray-500 text-center mt-4 font-poppins h-[32px] flex items-center justify-center">
|
||||
✓ Free cancellation up to 24 hours • Instant delivery
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<h1 className="font-merchant text-4xl md:text-5xl lg:text-6xl leading-tight mb-6">
|
||||
<span className="font-light">What Are</span>{' '}
|
||||
<span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
|
||||
City Cards?
|
||||
</span>
|
||||
</h1>
|
||||
<p className="font-poppins text-xl leading-relaxed font-normal text-gray-600 mb-8 max-w-2xl mx-auto">
|
||||
CityCards are your all-in-one pass to explore cities like never before. Get access to top attractions,
|
||||
skip the lines, and save money while discovering amazing experiences.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* How It Works Section */}
|
||||
<HowItWorks />
|
||||
{/* Decorative elements */}
|
||||
<div className="absolute top-20 left-10 w-20 h-20 bg-primary/10 rounded-full blur-xl"></div>
|
||||
<div className="absolute bottom-20 right-10 w-32 h-32 bg-secondary/10 rounded-full blur-xl"></div>
|
||||
</section>
|
||||
|
||||
{/* Why Choose CityCards Section */}
|
||||
<WhyChooseCityCards />
|
||||
{/* Get Your City Cards Section */}
|
||||
<section className="py-16">
|
||||
<div className="container mx-auto px-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="font-merchant text-3xl mb-4">Get your City Cards</h2>
|
||||
<p className="text-gray-600 font-poppins max-w-2xl mx-auto">
|
||||
Choose from our range of passes designed for every type of traveler and every budget
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Benefits Section */}
|
||||
<div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
|
||||
{/* Selective Pass */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.3 }}
|
||||
className="relative flex"
|
||||
>
|
||||
<Card className="relative transition-all duration-300 cursor-pointer flex flex-col w-full border-gray-200 shadow-md hover:shadow-lg hover:border-primary/30">
|
||||
<CardHeader className="text-center pb-6 pt-8 flex-shrink-0">
|
||||
<CardTitle className="font-poppins text-2xl font-bold mb-2 text-gray-900">
|
||||
SELECTIVE PASS
|
||||
</CardTitle>
|
||||
<CardDescription className="text-gray-600 mb-6 leading-relaxed font-poppins h-[48px] flex items-center justify-center">
|
||||
Perfect for travelers who want to explore selected attractions at their own pace with essential features.
|
||||
</CardDescription>
|
||||
|
||||
{/* Pricing */}
|
||||
<div className="mb-6">
|
||||
<div className="flex items-baseline justify-center gap-2 mb-2">
|
||||
<span className="text-4xl font-bold text-gray-900">$59.99</span>
|
||||
<span className="text-gray-500 font-poppins">/ per person</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 font-poppins h-[20px]">
|
||||
<span className="line-through mr-2">$89.99</span>
|
||||
<span className="text-green-600 font-medium">Save 33%</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
{/* Ready to Explore Melbourne Section */}
|
||||
<CardContent className="pt-0 flex flex-col flex-1">
|
||||
{/* Features List - Fixed Height */}
|
||||
<div className="space-y-3 mb-8 flex-1 min-h-[200px]">
|
||||
{[
|
||||
'Access to selected attractions',
|
||||
'Limited number of attractions per pass',
|
||||
'Flexible validity period',
|
||||
'Priority entry where available',
|
||||
'Mobile ticket delivery',
|
||||
'Standard customer support'
|
||||
].map((feature, index) => (
|
||||
<div key={index} className="flex items-start gap-3">
|
||||
<Check className="w-5 h-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span className="text-sm text-gray-700 font-poppins leading-relaxed">{feature}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* CTA Button - Fixed at bottom */}
|
||||
<div className="mt-auto flex-shrink-0">
|
||||
<Button
|
||||
className="w-full py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 bg-gray-900 hover:bg-primary text-white hover:shadow-lg font-poppins"
|
||||
onClick={onCheckoutClick}
|
||||
>
|
||||
PURCHASE NOW
|
||||
</Button>
|
||||
|
||||
{/* FAQ Section */}
|
||||
<section className="py-16 bg-gray-50">
|
||||
<div className="container mx-auto px-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="font-merchant text-3xl mb-4">Frequently Asked Questions</h2>
|
||||
<p className="text-gray-600 font-poppins max-w-2xl mx-auto">
|
||||
Everything you need to know about CityCards
|
||||
</p>
|
||||
</motion.div>
|
||||
<p className="text-xs text-gray-500 text-center mt-4 font-poppins h-[32px] flex items-center justify-center">
|
||||
✓ Free cancellation up to 24 hours • Instant delivery
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{
|
||||
question: "How do CityCards work?",
|
||||
answer: "CityCards are digital passes that give you access to multiple attractions in a city. Simply download our app, activate your card, and show it at participating attractions for instant entry."
|
||||
},
|
||||
{
|
||||
question: "Can I use my CityCard for multiple days?",
|
||||
answer: "Yes! Depending on the pass you choose, CityCards can be valid for 1, 2, 3, 5, or 7 consecutive days from your first use."
|
||||
},
|
||||
{
|
||||
question: "What's included in an Unlimited Pass?",
|
||||
answer: "The Unlimited Pass includes access to all participating attractions in your chosen city, plus additional perks like discounts at restaurants and shops."
|
||||
},
|
||||
{
|
||||
question: "Do I need to book attractions in advance?",
|
||||
answer: "Most attractions allow walk-in access with your CityCard, but some popular attractions may require advance booking through our app to guarantee entry."
|
||||
},
|
||||
{
|
||||
question: "What if I don't use all my attractions?",
|
||||
answer: "There's no pressure to visit every attraction. Your CityCard gives you the flexibility to explore at your own pace and choose what interests you most."
|
||||
}
|
||||
].map((faq, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.3 + index * 0.1 }}
|
||||
>
|
||||
<Card className="hover:shadow-md transition-shadow duration-300">
|
||||
<CardContent className="p-6">
|
||||
<h3 className="font-merchant text-lg mb-3">{faq.question}</h3>
|
||||
<p className="text-gray-600 font-poppins">{faq.answer}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
))}
|
||||
{/* Unlimited Pass */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.4 }}
|
||||
className="relative flex"
|
||||
>
|
||||
<Card className="relative transition-all duration-300 cursor-pointer flex flex-col w-full ring-2 ring-primary shadow-xl">
|
||||
|
||||
{/* Popular Badge */}
|
||||
<div className="absolute -top-4 left-1/2 transform -translate-x-1/2 z-10">
|
||||
<Badge className="bg-gradient-to-r from-yellow-400 to-orange-500 text-black px-6 py-2 font-semibold shadow-lg">
|
||||
⭐ Most Popular
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<CardHeader className="text-center pb-6 pt-8 flex-shrink-0">
|
||||
<CardTitle className="font-poppins text-2xl font-bold mb-2 text-gray-900">
|
||||
UNLIMITED CARD
|
||||
</CardTitle>
|
||||
<CardDescription className="text-gray-600 mb-6 leading-relaxed font-poppins h-[48px] flex items-center justify-center">
|
||||
The ultimate experience for adventure seekers who want unlimited access to all attractions with premium features.
|
||||
</CardDescription>
|
||||
|
||||
{/* Pricing */}
|
||||
<div className="mb-6">
|
||||
<div className="flex items-baseline justify-center gap-2 mb-2">
|
||||
<span className="text-4xl font-bold text-gray-900">$89.99</span>
|
||||
<span className="text-gray-500 font-poppins">/ per person</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 font-poppins h-[20px]">
|
||||
<span className="line-through mr-2">$149.99</span>
|
||||
<span className="text-green-600 font-medium">Save 40%</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="pt-0 flex flex-col flex-1">
|
||||
{/* Features List - Fixed Height */}
|
||||
<div className="space-y-3 mb-8 flex-1 min-h-[200px]">
|
||||
{[
|
||||
'Unlimited access to all attractions',
|
||||
'Time-limited validity (7 days)',
|
||||
'Skip-the-line access',
|
||||
'Expert guide inclusion',
|
||||
'Mobile app access',
|
||||
'Premium customer support'
|
||||
].map((feature, index) => (
|
||||
<div key={index} className="flex items-start gap-3">
|
||||
<Check className="w-5 h-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span className="text-sm text-gray-700 font-poppins leading-relaxed">{feature}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* CTA Button - Fixed at bottom */}
|
||||
<div className="mt-auto flex-shrink-0">
|
||||
<Button
|
||||
className="w-full py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 bg-gradient-to-r from-primary to-secondary hover:from-primary/90 hover:to-secondary/90 text-white shadow-lg hover:shadow-xl font-poppins"
|
||||
onClick={onCheckoutClick}
|
||||
>
|
||||
PURCHASE NOW
|
||||
</Button>
|
||||
|
||||
<p className="text-xs text-gray-500 text-center mt-4 font-poppins h-[32px] flex items-center justify-center">
|
||||
✓ Free cancellation up to 24 hours • Instant delivery
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
{/* Mobile App Section */}
|
||||
<MobileAppSection />
|
||||
{/* How It Works Section */}
|
||||
<HowItWorks />
|
||||
|
||||
{/* Customer Reviews */}
|
||||
<EnhancedTestimonials />
|
||||
{/* Why Choose CityCards Section */}
|
||||
<WhyChooseCityCards />
|
||||
|
||||
{/* Footer */}
|
||||
<Footer
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onSignInClick={onSignInClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onContactUsClick={onContactUsClick}
|
||||
currentPage={currentPage}
|
||||
/>
|
||||
{/* Benefits Section */}
|
||||
|
||||
|
||||
{/* Ready to Explore Melbourne Section */}
|
||||
|
||||
|
||||
{/* FAQ Section */}
|
||||
<section className="py-16 bg-gray-50">
|
||||
<div className="container mx-auto px-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="font-merchant text-3xl mb-4">Frequently Asked Questions</h2>
|
||||
<p className="text-gray-600 font-poppins max-w-2xl mx-auto">
|
||||
Everything you need to know about CityCards
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{
|
||||
question: "How do CityCards work?",
|
||||
answer: "CityCards are digital passes that give you access to multiple attractions in a city. Simply download our app, activate your card, and show it at participating attractions for instant entry."
|
||||
},
|
||||
{
|
||||
question: "Can I use my CityCard for multiple days?",
|
||||
answer: "Yes! Depending on the pass you choose, CityCards can be valid for 1, 2, 3, 5, or 7 consecutive days from your first use."
|
||||
},
|
||||
{
|
||||
question: "What's included in an Unlimited Pass?",
|
||||
answer: "The Unlimited Pass includes access to all participating attractions in your chosen city, plus additional perks like discounts at restaurants and shops."
|
||||
},
|
||||
{
|
||||
question: "Do I need to book attractions in advance?",
|
||||
answer: "Most attractions allow walk-in access with your CityCard, but some popular attractions may require advance booking through our app to guarantee entry."
|
||||
},
|
||||
{
|
||||
question: "What if I don't use all my attractions?",
|
||||
answer: "There's no pressure to visit every attraction. Your CityCard gives you the flexibility to explore at your own pace and choose what interests you most."
|
||||
}
|
||||
].map((faq, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.3 + index * 0.1 }}
|
||||
>
|
||||
<Card className="hover:shadow-md transition-shadow duration-300">
|
||||
<CardContent className="p-6">
|
||||
<h3 className="font-merchant text-lg mb-3">{faq.question}</h3>
|
||||
<p className="text-gray-600 font-poppins">{faq.answer}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Mobile App Section */}
|
||||
<MobileAppSection />
|
||||
|
||||
{/* Customer Reviews */}
|
||||
<EnhancedTestimonials />
|
||||
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,223 +1,223 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { motion } from 'motion/react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
// import { useState, useEffect } from 'react';
|
||||
// import { motion } from 'motion/react';
|
||||
// import { useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
interface CitySubmenuProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
// interface CitySubmenuProps {
|
||||
// onClose: () => void;
|
||||
// }
|
||||
|
||||
interface SubmenuItem {
|
||||
id: string;
|
||||
label: string;
|
||||
path?: string;
|
||||
action?: () => void;
|
||||
}
|
||||
// interface SubmenuItem {
|
||||
// id: string;
|
||||
// label: string;
|
||||
// path?: string;
|
||||
// action?: () => void;
|
||||
// }
|
||||
|
||||
export function CitySubmenu({ onClose }: CitySubmenuProps) {
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const [activeItem, setActiveItem] = useState<string | null>(null);
|
||||
// export function CitySubmenu({ onClose }: CitySubmenuProps) {
|
||||
// const [isScrolled, setIsScrolled] = useState(false);
|
||||
// const [activeItem, setActiveItem] = useState<string | null>(null);
|
||||
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
// const location = useLocation();
|
||||
// const navigate = useNavigate();
|
||||
|
||||
// Direct submenu items for Melbourne
|
||||
const submenuItems: SubmenuItem[] = [
|
||||
{
|
||||
id: 'melbourne',
|
||||
label: 'Melbourne',
|
||||
path: '/melbourne'
|
||||
},
|
||||
{
|
||||
id: 'attractions',
|
||||
label: 'Attractions',
|
||||
path: '/attractions'
|
||||
},
|
||||
{
|
||||
id: 'buy-now',
|
||||
label: 'Buy Now',
|
||||
path: '/passes'
|
||||
},
|
||||
{
|
||||
id: 'blogs',
|
||||
label: 'Blogs',
|
||||
path: '/blogs'
|
||||
},
|
||||
{
|
||||
id: 'how-it-works',
|
||||
label: 'How It Works',
|
||||
path: '/how-it-works'
|
||||
}
|
||||
];
|
||||
// // Direct submenu items for Melbourne
|
||||
// const submenuItems: SubmenuItem[] = [
|
||||
// {
|
||||
// id: 'melbourne',
|
||||
// label: 'Melbourne',
|
||||
// path: '/melbourne'
|
||||
// },
|
||||
// {
|
||||
// id: 'attractions',
|
||||
// label: 'Attractions',
|
||||
// path: '/attractions'
|
||||
// },
|
||||
// {
|
||||
// id: 'buy-now',
|
||||
// label: 'Buy Now',
|
||||
// path: '/passes'
|
||||
// },
|
||||
// {
|
||||
// id: 'blogs',
|
||||
// label: 'Blogs',
|
||||
// path: '/blogs'
|
||||
// },
|
||||
// {
|
||||
// id: 'how-it-works',
|
||||
// label: 'How It Works',
|
||||
// path: '/how-it-works'
|
||||
// }
|
||||
// ];
|
||||
|
||||
// Handle scroll effects
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
const scrolled = window.scrollY > 20;
|
||||
setIsScrolled(scrolled);
|
||||
};
|
||||
// // Handle scroll effects
|
||||
// useEffect(() => {
|
||||
// const handleScroll = () => {
|
||||
// const scrolled = window.scrollY > 20;
|
||||
// setIsScrolled(scrolled);
|
||||
// };
|
||||
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
// window.addEventListener('scroll', handleScroll);
|
||||
// return () => window.removeEventListener('scroll', handleScroll);
|
||||
// }, []);
|
||||
|
||||
// Determine active item based on current route
|
||||
useEffect(() => {
|
||||
const currentItem = submenuItems.find(item =>
|
||||
item.path && location.pathname === item.path
|
||||
);
|
||||
setActiveItem(currentItem?.id || null);
|
||||
}, [location.pathname]);
|
||||
// // Determine active item based on current route
|
||||
// useEffect(() => {
|
||||
// const currentItem = submenuItems.find(item =>
|
||||
// item.path && location.pathname === item.path
|
||||
// );
|
||||
// setActiveItem(currentItem?.id || null);
|
||||
// }, [location.pathname]);
|
||||
|
||||
const handleSubmenuItemClick = (item: SubmenuItem) => {
|
||||
if (item.path) {
|
||||
navigate(item.path);
|
||||
}
|
||||
setActiveItem(item.id);
|
||||
item.action?.();
|
||||
onClose();
|
||||
};
|
||||
// const handleSubmenuItemClick = (item: SubmenuItem) => {
|
||||
// if (item.path) {
|
||||
// navigate(item.path);
|
||||
// }
|
||||
// setActiveItem(item.id);
|
||||
// item.action?.();
|
||||
// onClose();
|
||||
// };
|
||||
|
||||
const isSubmenuItemActive = (itemId: string) => {
|
||||
return activeItem === itemId;
|
||||
};
|
||||
// const isSubmenuItemActive = (itemId: string) => {
|
||||
// return activeItem === itemId;
|
||||
// };
|
||||
|
||||
// Render direct submenu items
|
||||
const renderSubmenu = () => (
|
||||
<div className="flex items-center gap-1">
|
||||
{submenuItems.map((item) => (
|
||||
<motion.button
|
||||
key={item.id}
|
||||
onClick={() => handleSubmenuItemClick(item)}
|
||||
className={`font-poppins font-medium text-base relative px-4 py-2.5 transition-all duration-300 whitespace-nowrap rounded-full ${
|
||||
isSubmenuItemActive(item.id)
|
||||
? 'bg-primary text-white shadow-md'
|
||||
: 'text-gray-700 hover:text-white hover:bg-gray-800'
|
||||
}`}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{item.label}
|
||||
// // Render direct submenu items
|
||||
// const renderSubmenu = () => (
|
||||
// <div className="flex items-center gap-1">
|
||||
// {submenuItems.map((item) => (
|
||||
// <motion.button
|
||||
// key={item.id}
|
||||
// onClick={() => handleSubmenuItemClick(item)}
|
||||
// className={`font-poppins font-medium text-base relative px-4 py-2.5 transition-all duration-300 whitespace-nowrap rounded-full ${
|
||||
// isSubmenuItemActive(item.id)
|
||||
// ? 'bg-primary text-white shadow-md'
|
||||
// : 'text-gray-700 hover:text-white hover:bg-gray-800'
|
||||
// }`}
|
||||
// whileHover={{ scale: 1.02 }}
|
||||
// whileTap={{ scale: 0.98 }}
|
||||
// >
|
||||
// {item.label}
|
||||
|
||||
{!isSubmenuItemActive(item.id) && (
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-gray-800 rounded-full -z-10"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileHover={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
/>
|
||||
)}
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
// {!isSubmenuItemActive(item.id) && (
|
||||
// <motion.div
|
||||
// className="absolute inset-0 bg-gray-800 rounded-full -z-10"
|
||||
// initial={{ opacity: 0, scale: 0.9 }}
|
||||
// whileHover={{ opacity: 1, scale: 1 }}
|
||||
// transition={{ duration: 0.2 }}
|
||||
// />
|
||||
// )}
|
||||
// </motion.button>
|
||||
// ))}
|
||||
// </div>
|
||||
// );
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Desktop Submenu */}
|
||||
<motion.div
|
||||
className="fixed top-[120px] left-1/2 transform -translate-x-1/2 z-30 hidden lg:block"
|
||||
initial={{ y: -20, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{
|
||||
duration: 0.6,
|
||||
ease: [0.25, 0.1, 0.25, 1],
|
||||
delay: 0.4
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200"
|
||||
initial={{ scale: 0.9 }}
|
||||
animate={{
|
||||
scale: isScrolled ? 0.95 : 1,
|
||||
y: isScrolled ? 2 : 0,
|
||||
boxShadow: isScrolled
|
||||
? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
|
||||
: "0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03)"
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
>
|
||||
{renderSubmenu()}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
// return (
|
||||
// <>
|
||||
// {/* Desktop Submenu */}
|
||||
// <motion.div
|
||||
// className="fixed top-[120px] left-1/2 transform -translate-x-1/2 z-30 hidden lg:block"
|
||||
// initial={{ y: -20, opacity: 0 }}
|
||||
// animate={{ y: 0, opacity: 1 }}
|
||||
// transition={{
|
||||
// duration: 0.6,
|
||||
// ease: [0.25, 0.1, 0.25, 1],
|
||||
// delay: 0.4
|
||||
// }}
|
||||
// >
|
||||
// <motion.div
|
||||
// className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200"
|
||||
// initial={{ scale: 0.9 }}
|
||||
// animate={{
|
||||
// scale: isScrolled ? 0.95 : 1,
|
||||
// y: isScrolled ? 2 : 0,
|
||||
// boxShadow: isScrolled
|
||||
// ? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
|
||||
// : "0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03)"
|
||||
// }}
|
||||
// transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
// >
|
||||
// {renderSubmenu()}
|
||||
// </motion.div>
|
||||
// </motion.div>
|
||||
|
||||
{/* Mobile Submenu */}
|
||||
<motion.div
|
||||
className="fixed top-[100px] left-4 right-4 z-30 md:hidden"
|
||||
initial={{ y: -20, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{
|
||||
duration: 0.6,
|
||||
ease: [0.25, 0.1, 0.25, 1],
|
||||
delay: 0.4
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-2xl px-3 py-3 shadow-lg border border-gray-200"
|
||||
initial={{ scale: 0.9 }}
|
||||
animate={{
|
||||
scale: isScrolled ? 0.95 : 1,
|
||||
y: isScrolled ? 2 : 0,
|
||||
boxShadow: isScrolled
|
||||
? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
|
||||
: "0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03)"
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
>
|
||||
<div className="flex items-center gap-2 overflow-x-auto scrollbar-hide">
|
||||
{submenuItems.map((item) => (
|
||||
<motion.button
|
||||
key={item.id}
|
||||
onClick={() => handleSubmenuItemClick(item)}
|
||||
className={`relative px-3 py-2 text-sm font-medium transition-all duration-300 whitespace-nowrap rounded-xl flex-shrink-0 ${
|
||||
isSubmenuItemActive(item.id)
|
||||
? 'bg-primary text-white shadow-md'
|
||||
: 'text-gray-700 hover:text-white hover:bg-gray-800'
|
||||
}`}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{item.label}
|
||||
// {/* Mobile Submenu */}
|
||||
// <motion.div
|
||||
// className="fixed top-[100px] left-4 right-4 z-30 md:hidden"
|
||||
// initial={{ y: -20, opacity: 0 }}
|
||||
// animate={{ y: 0, opacity: 1 }}
|
||||
// transition={{
|
||||
// duration: 0.6,
|
||||
// ease: [0.25, 0.1, 0.25, 1],
|
||||
// delay: 0.4
|
||||
// }}
|
||||
// >
|
||||
// <motion.div
|
||||
// className="bg-white rounded-2xl px-3 py-3 shadow-lg border border-gray-200"
|
||||
// initial={{ scale: 0.9 }}
|
||||
// animate={{
|
||||
// scale: isScrolled ? 0.95 : 1,
|
||||
// y: isScrolled ? 2 : 0,
|
||||
// boxShadow: isScrolled
|
||||
// ? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
|
||||
// : "0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03)"
|
||||
// }}
|
||||
// transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
// >
|
||||
// <div className="flex items-center gap-2 overflow-x-auto scrollbar-hide">
|
||||
// {submenuItems.map((item) => (
|
||||
// <motion.button
|
||||
// key={item.id}
|
||||
// onClick={() => handleSubmenuItemClick(item)}
|
||||
// className={`relative px-3 py-2 text-sm font-medium transition-all duration-300 whitespace-nowrap rounded-xl flex-shrink-0 ${
|
||||
// isSubmenuItemActive(item.id)
|
||||
// ? 'bg-primary text-white shadow-md'
|
||||
// : 'text-gray-700 hover:text-white hover:bg-gray-800'
|
||||
// }`}
|
||||
// whileHover={{ scale: 1.02 }}
|
||||
// whileTap={{ scale: 0.98 }}
|
||||
// >
|
||||
// {item.label}
|
||||
|
||||
{!isSubmenuItemActive(item.id) && (
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-gray-800 rounded-xl -z-10"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileHover={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
/>
|
||||
)}
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
// {!isSubmenuItemActive(item.id) && (
|
||||
// <motion.div
|
||||
// className="absolute inset-0 bg-gray-800 rounded-xl -z-10"
|
||||
// initial={{ opacity: 0, scale: 0.9 }}
|
||||
// whileHover={{ opacity: 1, scale: 1 }}
|
||||
// transition={{ duration: 0.2 }}
|
||||
// />
|
||||
// )}
|
||||
// </motion.button>
|
||||
// ))}
|
||||
// </div>
|
||||
// </motion.div>
|
||||
// </motion.div>
|
||||
|
||||
{/* Medium Screen Submenu */}
|
||||
<motion.div
|
||||
className="fixed top-[110px] left-1/2 transform -translate-x-1/2 z-30 hidden md:block lg:hidden"
|
||||
initial={{ y: -20, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{
|
||||
duration: 0.6,
|
||||
ease: [0.25, 0.1, 0.25, 1],
|
||||
delay: 0.4
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200"
|
||||
initial={{ scale: 0.9 }}
|
||||
animate={{
|
||||
scale: isScrolled ? 0.95 : 1,
|
||||
y: isScrolled ? 2 : 0,
|
||||
boxShadow: isScrolled
|
||||
? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
|
||||
: "0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03)"
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
>
|
||||
{renderSubmenu()}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
// {/* Medium Screen Submenu */}
|
||||
// <motion.div
|
||||
// className="fixed top-[110px] left-1/2 transform -translate-x-1/2 z-30 hidden md:block lg:hidden"
|
||||
// initial={{ y: -20, opacity: 0 }}
|
||||
// animate={{ y: 0, opacity: 1 }}
|
||||
// transition={{
|
||||
// duration: 0.6,
|
||||
// ease: [0.25, 0.1, 0.25, 1],
|
||||
// delay: 0.4
|
||||
// }}
|
||||
// >
|
||||
// <motion.div
|
||||
// className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200"
|
||||
// initial={{ scale: 0.9 }}
|
||||
// animate={{
|
||||
// scale: isScrolled ? 0.95 : 1,
|
||||
// y: isScrolled ? 2 : 0,
|
||||
// boxShadow: isScrolled
|
||||
// ? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
|
||||
// : "0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03)"
|
||||
// }}
|
||||
// transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
// >
|
||||
// {renderSubmenu()}
|
||||
// </motion.div>
|
||||
// </motion.div>
|
||||
// </>
|
||||
// );
|
||||
// }
|
||||
@@ -2,9 +2,10 @@ import { motion } from 'motion/react';
|
||||
import { Wifi, MapPin, Camera, Users, Smartphone, QrCode, Check, ArrowRight } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import Navbar from './Navbar';
|
||||
import { SubNavbar } from './SubNavbar';
|
||||
// import { SubNavbar } from './SubNavbar';
|
||||
import { Footer } from './Footer';
|
||||
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||||
import { Layout } from '../Layout';
|
||||
|
||||
interface EsimsPageProps {
|
||||
onBackClick: () => void;
|
||||
@@ -90,34 +91,15 @@ export function EsimsPage({
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
{/* Navbar */}
|
||||
<Navbar
|
||||
activeCity="Paris"
|
||||
onCityChange={() => {}}
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onCheckoutClick={onCheckoutClick}
|
||||
<Layout
|
||||
activeCity="Landingpage"
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onProfileClick={onProfileClick}
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
onPostCardsClick={onPostCardsClick}
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
currentPage={currentPage}
|
||||
isUserSignedIn={!!user}
|
||||
user={user}
|
||||
/>
|
||||
>
|
||||
|
||||
{/* SubNavbar for Products */}
|
||||
<SubNavbar
|
||||
{/* SubNavbar for Products */}
|
||||
{/* <SubNavbar
|
||||
activeTab="esims"
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
@@ -125,190 +107,190 @@ export function EsimsPage({
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
{/* Hero Section - eSIM Focus */}
|
||||
<section className="relative pt-52 pb-20 overflow-hidden" style={{ backgroundColor: '#FFF5F5' }}>
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
<motion.div
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
<h1 className="font-poppins text-5xl md:text-6xl lg:text-7xl leading-tight mb-6">
|
||||
<span className="font-normal" style={{ color: '#1F2937' }}>Stay Connected Instantly</span>
|
||||
<br />
|
||||
<span className="font-normal" style={{ color: '#1F2937' }}>with Your</span>{' '}
|
||||
<span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
|
||||
Complimentary eSIM
|
||||
</span>
|
||||
</h1>
|
||||
<p className="font-poppins text-xl md:text-2xl leading-relaxed font-normal text-gray-600 mb-8 max-w-3xl mx-auto">
|
||||
Because every unforgettable trip starts with seamless connectivity.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Benefits Section */}
|
||||
<section className="py-20 bg-white">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-4">
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>With your </span>
|
||||
<span className="font-bold" style={{ color: '#F95F62' }}>eSIM</span>
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>, you can:</span>
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
|
||||
{benefits.map((benefit, index) => {
|
||||
const IconComponent = benefit.icon;
|
||||
return (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||||
className="flex gap-4 p-6 rounded-2xl transition-all duration-300 hover:shadow-lg"
|
||||
style={{ backgroundColor: '#FFF5F5' }}
|
||||
>
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-12 h-12 rounded-full flex items-center justify-center" style={{ backgroundColor: '#F95F62' }}>
|
||||
<IconComponent className="w-6 h-6 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-poppins text-lg font-semibold mb-2" style={{ color: '#1F2937' }}>
|
||||
{benefit.title}
|
||||
</h3>
|
||||
<p className="font-poppins text-base" style={{ color: '#4B5563' }}>
|
||||
{benefit.description}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* QR Code Process Section */}
|
||||
<section className="py-20" style={{ backgroundColor: '#FFF5F5' }}>
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-4">
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>Simple </span>
|
||||
<span className="font-bold" style={{ color: '#F95F62' }}>3-Step Process</span>
|
||||
</h2>
|
||||
<p className="font-poppins text-xl" style={{ color: '#4B5563' }}>
|
||||
Get connected in seconds
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="max-w-5xl mx-auto">
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{qrSteps.map((step, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: index * 0.2 }}
|
||||
className="relative"
|
||||
>
|
||||
{/* Connecting Line */}
|
||||
{index < qrSteps.length - 1 && (
|
||||
<div className="hidden md:block absolute top-16 left-1/2 w-full h-0.5 -z-10" style={{ backgroundColor: '#F95F62', opacity: 0.3 }} />
|
||||
)}
|
||||
|
||||
<div className="bg-white rounded-2xl p-8 text-center shadow-lg hover:shadow-xl transition-shadow duration-300">
|
||||
{/* Step Number */}
|
||||
<div className="w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-6" style={{ backgroundColor: '#F95F62' }}>
|
||||
<span className="font-poppins font-bold text-2xl text-white">{step.step}</span>
|
||||
</div>
|
||||
|
||||
{/* Icon */}
|
||||
<div className="mb-4">
|
||||
{index === 0 && <QrCode className="w-12 h-12 mx-auto" style={{ color: '#F95F62' }} />}
|
||||
{index === 1 && <Smartphone className="w-12 h-12 mx-auto" style={{ color: '#F95F62' }} />}
|
||||
{index === 2 && <Wifi className="w-12 h-12 mx-auto" style={{ color: '#F95F62' }} />}
|
||||
</div>
|
||||
|
||||
{/* Label */}
|
||||
<h3 className="font-poppins text-xl font-bold mb-3" style={{ color: '#1F2937' }}>
|
||||
{step.label}
|
||||
</h3>
|
||||
|
||||
{/* Description */}
|
||||
<p className="font-poppins text-base" style={{ color: '#4B5563' }}>
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CityCard Logo Trust Anchor */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
whileInView={{ opacity: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8, delay: 0.4 }}
|
||||
className="text-center mt-16"
|
||||
>
|
||||
<div className="inline-flex items-center gap-3 px-6 py-3 bg-white rounded-full shadow-md">
|
||||
<Check className="w-5 h-5" style={{ color: '#F95F62' }} />
|
||||
<span className="font-poppins font-semibold text-lg" style={{ color: '#1F2937' }}>
|
||||
Powered by <span style={{ color: '#F95F62' }}>CityCard</span>
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Closing Statement Section */}
|
||||
<section className="py-20 bg-white">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
>
|
||||
<p className="font-poppins text-2xl md:text-3xl leading-relaxed mb-8" style={{ color: '#1F2937' }}>
|
||||
It's one more way <span className="font-bold" style={{ color: '#F95F62' }}>CityCard</span> makes your journey <span className="font-semibold" style={{ color: '#F95F62' }}>smarter</span> and more <span className="font-semibold" style={{ color: '#F95F62' }}>effortless</span>.
|
||||
</p>
|
||||
|
||||
<button
|
||||
onClick={onCheckoutClick}
|
||||
className="group px-10 py-5 rounded-full flex items-center gap-3 mx-auto transition-all duration-300 hover:scale-105 shadow-lg hover:shadow-xl font-poppins font-semibold text-lg text-white"
|
||||
style={{ backgroundColor: '#F95F62' }}
|
||||
{/* Hero Section - eSIM Focus */}
|
||||
<section className="relative pt-52 pb-20 overflow-hidden" style={{ backgroundColor: '#FFF5F5' }}>
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
<motion.div
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
Start Your Journey Today
|
||||
<ArrowRight className="w-6 h-6 group-hover:translate-x-1 transition-transform duration-300" />
|
||||
</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
<h1 className="font-poppins text-5xl md:text-6xl lg:text-7xl leading-tight mb-6">
|
||||
<span className="font-normal" style={{ color: '#1F2937' }}>Stay Connected Instantly</span>
|
||||
<br />
|
||||
<span className="font-normal" style={{ color: '#1F2937' }}>with Your</span>{' '}
|
||||
<span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
|
||||
Complimentary eSIM
|
||||
</span>
|
||||
</h1>
|
||||
<p className="font-poppins text-xl md:text-2xl leading-relaxed font-normal text-gray-600 mb-8 max-w-3xl mx-auto">
|
||||
Because every unforgettable trip starts with seamless connectivity.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Footer />
|
||||
{/* Benefits Section */}
|
||||
<section className="py-20 bg-white">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-4">
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>With your </span>
|
||||
<span className="font-bold" style={{ color: '#F95F62' }}>eSIM</span>
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>, you can:</span>
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
|
||||
{benefits.map((benefit, index) => {
|
||||
const IconComponent = benefit.icon;
|
||||
return (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||||
className="flex gap-4 p-6 rounded-2xl transition-all duration-300 hover:shadow-lg"
|
||||
style={{ backgroundColor: '#FFF5F5' }}
|
||||
>
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-12 h-12 rounded-full flex items-center justify-center" style={{ backgroundColor: '#F95F62' }}>
|
||||
<IconComponent className="w-6 h-6 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-poppins text-lg font-semibold mb-2" style={{ color: '#1F2937' }}>
|
||||
{benefit.title}
|
||||
</h3>
|
||||
<p className="font-poppins text-base" style={{ color: '#4B5563' }}>
|
||||
{benefit.description}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* QR Code Process Section */}
|
||||
<section className="py-20" style={{ backgroundColor: '#FFF5F5' }}>
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-4">
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>Simple </span>
|
||||
<span className="font-bold" style={{ color: '#F95F62' }}>3-Step Process</span>
|
||||
</h2>
|
||||
<p className="font-poppins text-xl" style={{ color: '#4B5563' }}>
|
||||
Get connected in seconds
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="max-w-5xl mx-auto">
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{qrSteps.map((step, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: index * 0.2 }}
|
||||
className="relative"
|
||||
>
|
||||
{/* Connecting Line */}
|
||||
{index < qrSteps.length - 1 && (
|
||||
<div className="hidden md:block absolute top-16 left-1/2 w-full h-0.5 -z-10" style={{ backgroundColor: '#F95F62', opacity: 0.3 }} />
|
||||
)}
|
||||
|
||||
<div className="bg-white rounded-2xl p-8 text-center shadow-lg hover:shadow-xl transition-shadow duration-300">
|
||||
{/* Step Number */}
|
||||
<div className="w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-6" style={{ backgroundColor: '#F95F62' }}>
|
||||
<span className="font-poppins font-bold text-2xl text-white">{step.step}</span>
|
||||
</div>
|
||||
|
||||
{/* Icon */}
|
||||
<div className="mb-4">
|
||||
{index === 0 && <QrCode className="w-12 h-12 mx-auto" style={{ color: '#F95F62' }} />}
|
||||
{index === 1 && <Smartphone className="w-12 h-12 mx-auto" style={{ color: '#F95F62' }} />}
|
||||
{index === 2 && <Wifi className="w-12 h-12 mx-auto" style={{ color: '#F95F62' }} />}
|
||||
</div>
|
||||
|
||||
{/* Label */}
|
||||
<h3 className="font-poppins text-xl font-bold mb-3" style={{ color: '#1F2937' }}>
|
||||
{step.label}
|
||||
</h3>
|
||||
|
||||
{/* Description */}
|
||||
<p className="font-poppins text-base" style={{ color: '#4B5563' }}>
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CityCard Logo Trust Anchor */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
whileInView={{ opacity: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8, delay: 0.4 }}
|
||||
className="text-center mt-16"
|
||||
>
|
||||
<div className="inline-flex items-center gap-3 px-6 py-3 bg-white rounded-full shadow-md">
|
||||
<Check className="w-5 h-5" style={{ color: '#F95F62' }} />
|
||||
<span className="font-poppins font-semibold text-lg" style={{ color: '#1F2937' }}>
|
||||
Powered by <span style={{ color: '#F95F62' }}>CityCard</span>
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Closing Statement Section */}
|
||||
<section className="py-20 bg-white">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
>
|
||||
<p className="font-poppins text-2xl md:text-3xl leading-relaxed mb-8" style={{ color: '#1F2937' }}>
|
||||
It's one more way <span className="font-bold" style={{ color: '#F95F62' }}>CityCard</span> makes your journey <span className="font-semibold" style={{ color: '#F95F62' }}>smarter</span> and more <span className="font-semibold" style={{ color: '#F95F62' }}>effortless</span>.
|
||||
</p>
|
||||
|
||||
<button
|
||||
onClick={onCheckoutClick}
|
||||
className="group px-10 py-5 rounded-full flex items-center gap-3 mx-auto transition-all duration-300 hover:scale-105 shadow-lg hover:shadow-xl font-poppins font-semibold text-lg text-white"
|
||||
style={{ backgroundColor: '#F95F62' }}
|
||||
>
|
||||
Start Your Journey Today
|
||||
<ArrowRight className="w-6 h-6 group-hover:translate-x-1 transition-transform duration-300" />
|
||||
</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Input } from './ui/input';
|
||||
import { Badge } from './ui/badge';
|
||||
import { Card, CardContent } from './ui/card';
|
||||
import Navbar from './Navbar';
|
||||
import { CitySubmenu } from './CitySubmenu';
|
||||
// import { CitySubmenu } from './CitySubmenu';
|
||||
import { Footer } from './Footer';
|
||||
import { MobileAppSection } from './MobileAppSection';
|
||||
import { WhyChooseCityCards } from './WhyChooseCityCards';
|
||||
@@ -214,7 +214,7 @@ export function FAQPage({
|
||||
user={user}
|
||||
/>
|
||||
|
||||
<CitySubmenu
|
||||
{/* <CitySubmenu
|
||||
currentPage={currentPage}
|
||||
onClose={() => {}}
|
||||
onHomeClick={onHomeClick}
|
||||
@@ -223,7 +223,7 @@ export function FAQPage({
|
||||
onPassesClick={onPassesClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<div className="container mx-auto px-4 pt-52 pb-12">
|
||||
{/* Page Header */}
|
||||
|
||||
@@ -2,11 +2,12 @@ import { motion } from 'motion/react';
|
||||
import { BadgePercent, Clock, Crown, Check, ArrowRight } from 'lucide-react';
|
||||
import { Button } from './ui/button';
|
||||
import Navbar from './Navbar';
|
||||
import { SubNavbar } from './SubNavbar';
|
||||
// import { SubNavbar } from './SubNavbar';
|
||||
import { Footer } from './Footer';
|
||||
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||||
import cityCardsLogo from '../assets/cityLogo.png';
|
||||
import marriottHotelImage from '../assets/marriott-hotel.png';
|
||||
import { Layout } from '../Layout';
|
||||
|
||||
interface HotelDiscountsPageProps {
|
||||
onBackClick: () => void;
|
||||
@@ -80,35 +81,15 @@ export function HotelDiscountsPage({
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
{/* Navbar */}
|
||||
<Navbar
|
||||
activeCity="Paris"
|
||||
onCityChange={() => {}}
|
||||
onHomeClick={onHomeClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onCheckoutClick={onCheckoutClick}
|
||||
<Layout
|
||||
activeCity="Landingpage"
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onProfileClick={onProfileClick}
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
onPostCardsClick={onPostCardsClick}
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
currentPage={currentPage}
|
||||
isUserSignedIn={!!user}
|
||||
user={user}
|
||||
/>
|
||||
>
|
||||
|
||||
{/* Sub Navbar */}
|
||||
<SubNavbar
|
||||
{/* Sub Navbar */}
|
||||
{/* <SubNavbar
|
||||
activePage="hotel-discounts"
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
@@ -116,184 +97,184 @@ export function HotelDiscountsPage({
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative pt-64 pb-20 overflow-hidden">
|
||||
{/* Background Image with Overlay */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<ImageWithFallback
|
||||
src={marriottHotelImage}
|
||||
alt="Marriott Hotel"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/40 via-black/40 to-background" />
|
||||
</div>
|
||||
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="text-center"
|
||||
>
|
||||
{/* CityCard Logo */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="flex justify-center mb-8"
|
||||
>
|
||||
</motion.div>
|
||||
|
||||
{/* Heading */}
|
||||
<h1 className="font-poppins text-4xl md:text-5xl lg:text-6xl leading-tight mb-6 font-semibold text-white max-w-4xl mx-auto">
|
||||
Enjoy 20% Off Iconic Marriott Hotels — Exclusively with CityCard
|
||||
</h1>
|
||||
|
||||
{/* Tagline */}
|
||||
<p className="font-poppins text-xl md:text-2xl leading-relaxed font-normal text-white/90 max-w-2xl mx-auto">
|
||||
Make every stay as unforgettable as the city you're exploring.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 1: Partnership Introduction - White Background */}
|
||||
<section className="py-20 md:py-28 bg-white">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
>
|
||||
<p className="font-poppins text-2xl md:text-3xl lg:text-4xl leading-relaxed font-normal mb-8" style={{ color: '#1F2937' }}>
|
||||
Your CityCard unlocks more than just attractions — it also opens doors to exceptional stays.
|
||||
</p>
|
||||
<p className="font-poppins text-xl md:text-2xl leading-relaxed font-normal" style={{ color: '#4B5563' }}>
|
||||
Thanks to our exclusive partnership with <span className="font-semibold" style={{ color: '#F95F62' }}>Marriott Hotels</span>, CityCard holders enjoy <span className="font-semibold" style={{ color: '#F95F62' }}>20% off best available rates</span> across a curated selection of properties in the city.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 2: Hotel Variety - Pink Background */}
|
||||
<section className="py-20 md:py-28" style={{ backgroundColor: '#FFF5F5' }}>
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
>
|
||||
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-6">
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>Choose from a </span>
|
||||
<span className="font-bold" style={{ color: '#F95F62' }}>Wide Variety</span>
|
||||
</h2>
|
||||
<p className="font-poppins text-xl md:text-2xl leading-relaxed font-normal" style={{ color: '#4B5563' }}>
|
||||
Choose from a wide variety of Marriott hotels — from elegant urban hideaways and premium city-centre locations to luxurious five-star experiences — all designed to make your trip <span className="font-semibold" style={{ color: '#F95F62' }}>effortless</span>, <span className="font-semibold" style={{ color: '#F95F62' }}>comfortable</span>, and <span className="font-semibold" style={{ color: '#F95F62' }}>memorable</span>.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 3: Benefits - White Background with Pink Cards */}
|
||||
<section className="py-20 md:py-28 bg-white">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
{/* Heading */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-4">
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>Simply use your CityCard</span>
|
||||
<br />
|
||||
<span className="font-bold" style={{ color: '#F95F62' }}>booking link to:</span>
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
||||
{/* Benefits Grid */}
|
||||
<div className="grid md:grid-cols-3 gap-8 max-w-5xl mx-auto mb-16">
|
||||
{benefits.map((benefit, index) => {
|
||||
const IconComponent = benefit.icon;
|
||||
return (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||||
className="flex flex-col items-center text-center p-6 rounded-2xl transition-all duration-300 hover:shadow-lg"
|
||||
style={{ backgroundColor: '#FFF5F5' }}
|
||||
>
|
||||
<div className="w-16 h-16 rounded-full flex items-center justify-center mb-6" style={{ backgroundColor: '#F95F62' }}>
|
||||
<IconComponent className="w-8 h-8 text-white" />
|
||||
</div>
|
||||
<h3 className="font-poppins text-lg font-semibold mb-3" style={{ color: '#1F2937' }}>
|
||||
{benefit.title}
|
||||
</h3>
|
||||
<p className="font-poppins text-base font-normal" style={{ color: '#4B5563' }}>
|
||||
{benefit.description}
|
||||
</p>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
{/* Hero Section */}
|
||||
<section className="relative pt-64 pb-20 overflow-hidden">
|
||||
{/* Background Image with Overlay */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<ImageWithFallback
|
||||
src={marriottHotelImage}
|
||||
alt="Marriott Hotel"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/40 via-black/40 to-background" />
|
||||
</div>
|
||||
|
||||
{/* Closing Statement */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8, delay: 0.4 }}
|
||||
className="text-center"
|
||||
>
|
||||
<div className="max-w-4xl mx-auto mb-8">
|
||||
<p className="font-poppins text-2xl md:text-3xl leading-relaxed font-normal" style={{ color: '#1F2937' }}>
|
||||
It's just one more way <span className="font-bold" style={{ color: '#F95F62' }}>CityCard</span> makes exploring <span className="font-semibold" style={{ color: '#F95F62' }}>smarter</span>, <span className="font-semibold" style={{ color: '#F95F62' }}>simpler</span>, and <span className="font-semibold" style={{ color: '#F95F62' }}>more rewarding</span>.
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="text-center"
|
||||
>
|
||||
{/* CityCard Logo */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="flex justify-center mb-8"
|
||||
>
|
||||
</motion.div>
|
||||
|
||||
{/* Heading */}
|
||||
<h1 className="font-poppins text-4xl md:text-5xl lg:text-6xl leading-tight mb-6 font-semibold text-white max-w-4xl mx-auto">
|
||||
Enjoy 20% Off Iconic Marriott Hotels — Exclusively with CityCard
|
||||
</h1>
|
||||
|
||||
{/* Tagline */}
|
||||
<p className="font-poppins text-xl md:text-2xl leading-relaxed font-normal text-white/90 max-w-2xl mx-auto">
|
||||
Make every stay as unforgettable as the city you're exploring.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 1: Partnership Introduction - White Background */}
|
||||
<section className="py-20 md:py-28 bg-white">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
>
|
||||
<p className="font-poppins text-2xl md:text-3xl lg:text-4xl leading-relaxed font-normal mb-8" style={{ color: '#1F2937' }}>
|
||||
Your CityCard unlocks more than just attractions — it also opens doors to exceptional stays.
|
||||
</p>
|
||||
<p className="font-poppins text-xl md:text-2xl leading-relaxed font-normal" style={{ color: '#4B5563' }}>
|
||||
Thanks to our exclusive partnership with <span className="font-semibold" style={{ color: '#F95F62' }}>Marriott Hotels</span>, CityCard holders enjoy <span className="font-semibold" style={{ color: '#F95F62' }}>20% off best available rates</span> across a curated selection of properties in the city.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 2: Hotel Variety - Pink Background */}
|
||||
<section className="py-20 md:py-28" style={{ backgroundColor: '#FFF5F5' }}>
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="max-w-4xl mx-auto text-center"
|
||||
>
|
||||
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-6">
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>Choose from a </span>
|
||||
<span className="font-bold" style={{ color: '#F95F62' }}>Wide Variety</span>
|
||||
</h2>
|
||||
<p className="font-poppins text-xl md:text-2xl leading-relaxed font-normal" style={{ color: '#4B5563' }}>
|
||||
Choose from a wide variety of Marriott hotels — from elegant urban hideaways and premium city-centre locations to luxurious five-star experiences — all designed to make your trip <span className="font-semibold" style={{ color: '#F95F62' }}>effortless</span>, <span className="font-semibold" style={{ color: '#F95F62' }}>comfortable</span>, and <span className="font-semibold" style={{ color: '#F95F62' }}>memorable</span>.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 3: Benefits - White Background with Pink Cards */}
|
||||
<section className="py-20 md:py-28 bg-white">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
{/* Heading */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-4">
|
||||
<span className="font-light" style={{ color: '#1F2937' }}>Simply use your CityCard</span>
|
||||
<br />
|
||||
<span className="font-bold" style={{ color: '#F95F62' }}>booking link to:</span>
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
||||
{/* Benefits Grid */}
|
||||
<div className="grid md:grid-cols-3 gap-8 max-w-5xl mx-auto mb-16">
|
||||
{benefits.map((benefit, index) => {
|
||||
const IconComponent = benefit.icon;
|
||||
return (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||||
className="flex flex-col items-center text-center p-6 rounded-2xl transition-all duration-300 hover:shadow-lg"
|
||||
style={{ backgroundColor: '#FFF5F5' }}
|
||||
>
|
||||
<div className="w-16 h-16 rounded-full flex items-center justify-center mb-6" style={{ backgroundColor: '#F95F62' }}>
|
||||
<IconComponent className="w-8 h-8 text-white" />
|
||||
</div>
|
||||
<h3 className="font-poppins text-lg font-semibold mb-3" style={{ color: '#1F2937' }}>
|
||||
{benefit.title}
|
||||
</h3>
|
||||
<p className="font-poppins text-base font-normal" style={{ color: '#4B5563' }}>
|
||||
{benefit.description}
|
||||
</p>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={onCheckoutClick}
|
||||
className="group px-10 py-5 rounded-full flex items-center gap-3 mx-auto transition-all duration-300 hover:scale-105 shadow-lg hover:shadow-xl font-poppins font-semibold text-lg text-white"
|
||||
style={{ backgroundColor: '#F95F62' }}
|
||||
{/* Closing Statement */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8, delay: 0.4 }}
|
||||
className="text-center"
|
||||
>
|
||||
Get Your CityCard Today
|
||||
<ArrowRight className="w-6 h-6 group-hover:translate-x-1 transition-transform duration-300" />
|
||||
</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
<div className="max-w-4xl mx-auto mb-8">
|
||||
<p className="font-poppins text-2xl md:text-3xl leading-relaxed font-normal" style={{ color: '#1F2937' }}>
|
||||
It's just one more way <span className="font-bold" style={{ color: '#F95F62' }}>CityCard</span> makes exploring <span className="font-semibold" style={{ color: '#F95F62' }}>smarter</span>, <span className="font-semibold" style={{ color: '#F95F62' }}>simpler</span>, and <span className="font-semibold" style={{ color: '#F95F62' }}>more rewarding</span>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Trust Anchor Section with Logo */}
|
||||
<section className="py-16 bg-white border-t border-gray-100">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="flex flex-col items-center text-center"
|
||||
>
|
||||
<img
|
||||
src={cityCardsLogo}
|
||||
alt="CityCard"
|
||||
className="h-12 md:h-14 w-auto object-contain mb-6"
|
||||
/>
|
||||
<p className="font-poppins text-lg md:text-xl font-normal max-w-2xl" style={{ color: '#4B5563' }}>
|
||||
Your gateway to unforgettable city experiences and exceptional hotel stays
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
<button
|
||||
onClick={onCheckoutClick}
|
||||
className="group px-10 py-5 rounded-full flex items-center gap-3 mx-auto transition-all duration-300 hover:scale-105 shadow-lg hover:shadow-xl font-poppins font-semibold text-lg text-white"
|
||||
style={{ backgroundColor: '#F95F62' }}
|
||||
>
|
||||
Get Your CityCard Today
|
||||
<ArrowRight className="w-6 h-6 group-hover:translate-x-1 transition-transform duration-300" />
|
||||
</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Trust Anchor Section with Logo */}
|
||||
<section className="py-16 bg-white border-t border-gray-100">
|
||||
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="flex flex-col items-center text-center"
|
||||
>
|
||||
<img
|
||||
src={cityCardsLogo}
|
||||
alt="CityCard"
|
||||
className="h-12 md:h-14 w-auto object-contain mb-6"
|
||||
/>
|
||||
<p className="font-poppins text-lg md:text-xl font-normal max-w-2xl" style={{ color: '#4B5563' }}>
|
||||
Your gateway to unforgettable city experiences and exceptional hotel stays
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Button } from './ui/button';
|
||||
import { Card, CardContent } from './ui/card';
|
||||
import { Badge } from './ui/badge';
|
||||
import Navbar from './Navbar';
|
||||
import { CitySubmenu } from './CitySubmenu';
|
||||
// import { CitySubmenu } from './CitySubmenu';
|
||||
import { AttractionHassleFreeSection } from './AttractionHassleFreeSection';
|
||||
import { MobileAppSection } from './MobileAppSection';
|
||||
import { WhyChooseCityCards } from './WhyChooseCityCards';
|
||||
@@ -189,7 +189,7 @@ export function HowItWorksPage({
|
||||
user={user}
|
||||
/>
|
||||
|
||||
<CitySubmenu
|
||||
{/* <CitySubmenu
|
||||
currentPage={currentPage}
|
||||
onClose={() => {}}
|
||||
onHomeClick={onHomeClick}
|
||||
@@ -198,7 +198,7 @@ export function HowItWorksPage({
|
||||
onPassesClick={onPassesClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<div className="container mx-auto px-4 pt-52 pb-12 relative z-10">
|
||||
{/* Page Header */}
|
||||
|
||||
@@ -5,12 +5,13 @@ import { Button } from './ui/button';
|
||||
import { Card, CardContent } from './ui/card';
|
||||
import { Badge } from './ui/badge';
|
||||
import Navbar from './Navbar';
|
||||
import SubNavbar from './SubNavbar';
|
||||
// import SubNavbar from './SubNavbar';
|
||||
import { Footer } from './Footer';
|
||||
import { MobileAppSection } from './MobileAppSection';
|
||||
import { EnhancedTestimonials } from './EnhancedTestimonials';
|
||||
import { HowItWorks } from './HowItWorks';
|
||||
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||||
import { Layout } from '../Layout';
|
||||
|
||||
interface User {
|
||||
email: string;
|
||||
@@ -75,34 +76,15 @@ export function MagicItineraryPage({
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Navbar */}
|
||||
<Navbar
|
||||
activeCity=""
|
||||
onCityChange={() => {}}
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onCheckoutClick={onCheckoutClick}
|
||||
onHomeClick={onHomeClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onProfileClick={onProfileClick}
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
onPostCardsClick={onPostCardsClick}
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
currentPage="magic-itinerary"
|
||||
isUserSignedIn={!!user}
|
||||
user={user}
|
||||
/>
|
||||
<Layout
|
||||
activeCity="Melbourne"
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
user={user}
|
||||
>
|
||||
|
||||
{/* Sub Navbar */}
|
||||
<SubNavbar
|
||||
{/* <SubNavbar
|
||||
activeTab="magic-itinerary"
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
@@ -110,7 +92,7 @@ export function MagicItineraryPage({
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative pt-52 pb-20 overflow-hidden">
|
||||
@@ -379,20 +361,8 @@ export function MagicItineraryPage({
|
||||
{/* Customer Reviews */}
|
||||
<EnhancedTestimonials />
|
||||
|
||||
{/* Footer */}
|
||||
<Footer
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onSignInClick={onSignInClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onContactUsClick={onContactUsClick}
|
||||
currentPage={currentPage}
|
||||
/>
|
||||
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -379,22 +379,6 @@ export function MelbournePage({
|
||||
|
||||
{/* Melbourne FAQ Section */}
|
||||
<MelbourneFAQ />
|
||||
|
||||
{/* Footer */}
|
||||
<Footer
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onHomeClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onSignInClick={onSignInClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onContactUsClick={onContactUsClick}
|
||||
currentPage="melbourne"
|
||||
/>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
@@ -56,16 +56,50 @@ export default function Navbar({
|
||||
const [activeLanguageDropdown, setActiveLanguageDropdown] = useState(false);
|
||||
const [activeCartDropdown, setActiveCartDropdown] = useState(false);
|
||||
const [activeUserDropdown, setActiveUserDropdown] = useState(false);
|
||||
const [activeExploreCardDropdown, setActiveExploreCardDropdown] = useState(false);
|
||||
const [activeCityDropdown, setActiveCityDropdown] = useState(false);
|
||||
|
||||
const languageRef = useRef<HTMLDivElement>(null);
|
||||
const cartRef = useRef<HTMLDivElement>(null);
|
||||
const userRef = useRef<HTMLDivElement>(null);
|
||||
const exploreCardRef = useRef<HTMLDivElement>(null);
|
||||
const cityRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Available cities
|
||||
const cities = [
|
||||
{ id: 'melbourne', label: 'Melbourne' },
|
||||
{ id: 'sydney', label: 'Sydney' },
|
||||
{ id: 'brisbane', label: 'Brisbane' },
|
||||
{ id: 'perth', label: 'Perth' }
|
||||
];
|
||||
|
||||
// Check if we're on landing page
|
||||
const isLandingPage = location.pathname === '/';
|
||||
|
||||
// Landing page navigation items
|
||||
const landingPageNavigationItems = [
|
||||
{ label: 'CityCards', path: '/citycards' },
|
||||
{ label: 'Postcards', path: '/postcards' },
|
||||
{ label: 'eSIMs', path: '/esims' },
|
||||
{ label: 'Hotel Discount', path: '/hotel-discounts' },
|
||||
{ label: 'Offers', path: '/offers' }
|
||||
];
|
||||
|
||||
// Melbourne-specific navigation items (without /melbourne in paths)
|
||||
const melbourneNavigationItems = [
|
||||
{ label: 'Attractions', path: '/attractions' },
|
||||
{ label: 'Magic Itinerary', path: '/magic-itinerary' },
|
||||
{ label: 'Super Savings', path: '/comming-soon' },
|
||||
{ label: 'How It Works', path: '/how-it-works' },
|
||||
{ label: 'Your Card', path: '/passes' }
|
||||
];
|
||||
|
||||
// Get current navigation items based on page and city
|
||||
const navigationItems = isLandingPage
|
||||
? landingPageNavigationItems
|
||||
: (activeCity.toLowerCase() === 'melbourne' ? melbourneNavigationItems : landingPageNavigationItems);
|
||||
|
||||
// Languages available
|
||||
const languages: DropdownItem[] = [
|
||||
{ id: 'en', label: 'English', icon: <span className="text-base">🇺🇸</span> },
|
||||
@@ -74,61 +108,26 @@ export default function Navbar({
|
||||
{ id: 'it', label: 'Italiano', icon: <span className="text-base">🇮🇹</span> },
|
||||
];
|
||||
|
||||
// Explore Card dropdown items with router navigation
|
||||
const exploreCardItems: DropdownItem[] = [
|
||||
{
|
||||
id: 'citycards',
|
||||
label: 'CityCards',
|
||||
path: '/citycards'
|
||||
},
|
||||
{
|
||||
id: 'magic-itinerary',
|
||||
label: 'Magic Itinerary',
|
||||
path: '/magic-itinerary'
|
||||
},
|
||||
{
|
||||
id: 'postcards',
|
||||
label: 'PostCards',
|
||||
path: '/postcards'
|
||||
},
|
||||
{
|
||||
id: 'offers',
|
||||
label: 'Offers',
|
||||
path: '/offers'
|
||||
},
|
||||
{
|
||||
id: 'esims',
|
||||
label: 'eSIMs',
|
||||
path: '/esims'
|
||||
},
|
||||
{
|
||||
id: 'hotel-discounts',
|
||||
label: 'Hotel Discounts',
|
||||
path: '/hotel-discounts'
|
||||
}
|
||||
];
|
||||
|
||||
// Mock cart items
|
||||
const cartItems: CartItem[] = [
|
||||
{ id: '1', name: 'Sydney 2-Day Pass', price: '$89', quantity: 1 },
|
||||
{ id: '2', name: 'Melbourne Premium Pass', price: '$129', quantity: 1 },
|
||||
];
|
||||
|
||||
// Section IDs for navigation
|
||||
const sectionIds = [
|
||||
'hero-section',
|
||||
'why-choose-section',
|
||||
'variety-adventures-section',
|
||||
'how-it-works-section',
|
||||
'magic-itinerary-section',
|
||||
'book-attraction-section',
|
||||
'custom-postcards-section',
|
||||
'upcoming-cities-section',
|
||||
'trust-section',
|
||||
'mobile-app-section'
|
||||
];
|
||||
|
||||
const scrollToSection = (index: number) => {
|
||||
const sectionIds = [
|
||||
'hero-section',
|
||||
'why-choose-section',
|
||||
'variety-adventures-section',
|
||||
'how-it-works-section',
|
||||
'magic-itinerary-section',
|
||||
'book-attraction-section',
|
||||
'custom-postcards-section',
|
||||
'upcoming-cities-section',
|
||||
'trust-section',
|
||||
'mobile-app-section'
|
||||
];
|
||||
|
||||
const sectionId = sectionIds[index];
|
||||
const element = document.getElementById(sectionId);
|
||||
if (element) {
|
||||
@@ -153,27 +152,27 @@ export default function Navbar({
|
||||
}, []);
|
||||
|
||||
// Close dropdowns when clicking outside
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
setTimeout(() => {
|
||||
if (languageRef.current && !languageRef.current.contains(event.target as Node)) {
|
||||
setActiveLanguageDropdown(false);
|
||||
}
|
||||
if (cartRef.current && !cartRef.current.contains(event.target as Node)) {
|
||||
setActiveCartDropdown(false);
|
||||
}
|
||||
if (userRef.current && !userRef.current.contains(event.target as Node)) {
|
||||
setActiveUserDropdown(false);
|
||||
}
|
||||
if (exploreCardRef.current && !exploreCardRef.current.contains(event.target as Node)) {
|
||||
setActiveExploreCardDropdown(false);
|
||||
}
|
||||
}, 10);
|
||||
};
|
||||
// useEffect(() => {
|
||||
// const handleClickOutside = (event: MouseEvent) => {
|
||||
// setTimeout(() => {
|
||||
// if (languageRef.current && !languageRef.current.contains(event.target as Node)) {
|
||||
// setActiveLanguageDropdown(false);
|
||||
// }
|
||||
// if (cartRef.current && !cartRef.current.contains(event.target as Node)) {
|
||||
// setActiveCartDropdown(false);
|
||||
// }
|
||||
// if (userRef.current && !userRef.current.contains(event.target as Node)) {
|
||||
// setActiveUserDropdown(false);
|
||||
// }
|
||||
// if (cityRef.current && !cityRef.current.contains(event.target as Node)) {
|
||||
// setActiveCityDropdown(false);
|
||||
// }
|
||||
// }, 10);
|
||||
// };
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, []);
|
||||
// document.addEventListener('mousedown', handleClickOutside);
|
||||
// return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
// }, []);
|
||||
|
||||
const handleNavClick = (path: string) => {
|
||||
navigate(path);
|
||||
@@ -184,10 +183,21 @@ export default function Navbar({
|
||||
return location.pathname === path;
|
||||
};
|
||||
|
||||
// Handle Explore Card dropdown item click
|
||||
const handleExploreCardItemClick = (path: string) => {
|
||||
navigate(path);
|
||||
setActiveExploreCardDropdown(false);
|
||||
// Handle city change
|
||||
// Handle city change
|
||||
const handleCityChange = (city: string) => {
|
||||
console.log('City selected:', city); // Debug log
|
||||
onCityChange(city);
|
||||
setActiveCityDropdown(false);
|
||||
|
||||
// Navigate based on city selection
|
||||
if (city.toLowerCase() === 'melbourne') {
|
||||
console.log('Navigating to Melbourne'); // Debug log
|
||||
navigate('/melbourne');
|
||||
} else {
|
||||
console.log('Navigating to coming soon'); // Debug log
|
||||
navigate('/comming-soon');
|
||||
}
|
||||
};
|
||||
|
||||
// Calculate cart total
|
||||
@@ -196,14 +206,7 @@ export default function Navbar({
|
||||
return total + (price * item.quantity);
|
||||
}, 0);
|
||||
|
||||
// Navigation items with router paths
|
||||
const navigationItems = [
|
||||
{ label: 'How It Works', path: '/how-it-works' },
|
||||
{ label: 'Your Card', path: '/passes' },
|
||||
{ label: 'FAQ', path: '/faq' }
|
||||
];
|
||||
|
||||
// Dropdown component with proper ref forwarding and glassmorphism
|
||||
// Simple Dropdown component without blinking
|
||||
const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(({
|
||||
isOpen,
|
||||
onToggle,
|
||||
@@ -212,86 +215,70 @@ export default function Navbar({
|
||||
title,
|
||||
className = ""
|
||||
}, ref) => (
|
||||
<div ref={ref} className={`relative ${className}`} style={{ height: 'auto', minHeight: 'auto' }}>
|
||||
<motion.button
|
||||
onClick={onToggle}
|
||||
className="relative"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
<div ref={ref} className={`relative ${className}`}>
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onToggle();
|
||||
}}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{trigger}
|
||||
</motion.button>
|
||||
</div>
|
||||
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10, scale: 0.95 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
exit={{ opacity: 0, y: 10, scale: 0.95 }}
|
||||
transition={{ duration: 0.2, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
className="absolute top-full right-0 mt-2 bg-white/95 backdrop-blur-xl rounded-2xl shadow-xl border border-white/20 min-w-[280px] max-w-[320px] overflow-hidden z-50"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '100%',
|
||||
right: '0',
|
||||
marginTop: '0.5rem'
|
||||
}}
|
||||
>
|
||||
{title && (
|
||||
<div className="px-5 py-4 border-b border-gray-100/50">
|
||||
<h3 className="font-merchant font-semibold text-gray-900 text-base">{title}</h3>
|
||||
</div>
|
||||
)}
|
||||
<>
|
||||
{/* Backdrop to capture outside clicks */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="fixed inset-0 z-40"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onToggle();
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="py-3 px-2">
|
||||
{items.map((item, index) => (
|
||||
<motion.button
|
||||
key={item.id}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
{/* Dropdown content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10, scale: 0.95 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
exit={{ opacity: 0, y: 10, scale: 0.95 }}
|
||||
transition={{ duration: 0.2, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
className="absolute top-full left-0 mt-2 bg-white/95 backdrop-blur-xl rounded-2xl shadow-xl border border-white/20 min-w-[200px] overflow-hidden z-50"
|
||||
onClick={(e) => e.stopPropagation()} // Prevent clicks inside from closing
|
||||
>
|
||||
{title && (
|
||||
<div className="px-5 py-4 border-b border-gray-100/50">
|
||||
<h3 className="font-merchant font-semibold text-gray-900 text-base">{title}</h3>
|
||||
</div>
|
||||
)}
|
||||
|
||||
// Handle router navigation for items with paths
|
||||
if (item.path) {
|
||||
navigate(item.path);
|
||||
}
|
||||
<div className="py-2">
|
||||
{items.map((item, index) => (
|
||||
<div
|
||||
key={item.id}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
console.log('City dropdown item clicked:', item.label);
|
||||
|
||||
// Handle action if provided
|
||||
if (item.action && item.id !== 'total') {
|
||||
item.action();
|
||||
}
|
||||
|
||||
// Only close dropdown for actionable items
|
||||
if (item.id === 'checkout' || item.path || (item.id !== 'total' && !item.action)) {
|
||||
setTimeout(() => onToggle(), 100);
|
||||
}
|
||||
}}
|
||||
className={`w-full flex items-center justify-between text-left transition-colors duration-200 ${item.id === 'checkout'
|
||||
? 'bg-gradient-to-r from-primary to-secondary hover:from-primary/90 hover:to-secondary/90 text-white font-medium rounded-lg px-4 py-2.5 mb-1 mt-2'
|
||||
: item.id === 'total'
|
||||
? 'cursor-default font-semibold border-t border-gray-100/50 pt-4 px-3 py-2'
|
||||
: 'hover:bg-gray-50/80 px-3 py-2.5 rounded-md'
|
||||
}`}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: index * 0.05 }}
|
||||
disabled={item.id === 'total'}
|
||||
>
|
||||
<div className="flex items-center space-x-3">
|
||||
{item.icon}
|
||||
<span className={`text-sm font-medium ${item.id === 'checkout' ? 'text-white' :
|
||||
item.id === 'total' ? 'text-gray-900' : 'text-gray-700'
|
||||
}`}>{item.label}</span>
|
||||
if (item.action) {
|
||||
item.action();
|
||||
}
|
||||
// Don't call onToggle here - let the backdrop handle closing
|
||||
}}
|
||||
className="px-4 py-2.5 hover:bg-gray-50/80 cursor-pointer transition-colors duration-200"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium text-gray-700">{item.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
{item.badge && (
|
||||
<span className="bg-primary text-primary-foreground text-xs px-2 py-1 rounded-full">
|
||||
{item.badge}
|
||||
</span>
|
||||
)}
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
@@ -304,14 +291,14 @@ export default function Navbar({
|
||||
<>
|
||||
{/* Desktop Navbar - Enhanced Glassmorphism */}
|
||||
<motion.nav
|
||||
className="fixed top-6 left-0 right-0 z-50 hidden lg:block"
|
||||
className="fixed top-0 left-0 right-0 z-50 hidden lg:block"
|
||||
initial={{ y: -100, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.6, ease: [0.25, 0.1, 0.25, 1], delay: 0.2 }}
|
||||
>
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="">
|
||||
<motion.div
|
||||
className={`w-full transition-all duration-500 ease-out rounded-full px-8 py-4 bg-white backdrop-blur-[20px] border border-white/20 ${isScrolled
|
||||
className={`w-full transition-all duration-500 ease-out px-8 py-4 bg-white backdrop-blur-[20px] border border-white/20 ${isScrolled
|
||||
? 'shadow-[0_10px_15px_-3px_rgba(0,0,0,0.08),0_4px_6px_-2px_rgba(0,0,0,0.05)]'
|
||||
: 'shadow-lg shadow-black/5'
|
||||
}`}
|
||||
@@ -340,20 +327,12 @@ export default function Navbar({
|
||||
</motion.div>
|
||||
|
||||
<div className="absolute left-1/2 -translate-x-1/2 flex items-center gap-5">
|
||||
{/* Explore Card - First Item - No Dropdown */}
|
||||
<Link
|
||||
to="/citycards"
|
||||
className="flex items-center space-x-1 text-gray-700 hover:text-gray-900 text-base font-medium transition-colors duration-200 cursor-pointer rounded-lg hover:bg-gray-50/50 px-2 py-1"
|
||||
>
|
||||
<span>Explore Card</span>
|
||||
</Link>
|
||||
|
||||
{/* Other Navigation Items */}
|
||||
{/* Navigation Items based on page type */}
|
||||
{navigationItems.map((item) => (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
className={`relative px-0 py-2 text-base font-medium transition-all duration-200 whitespace-nowrap group capitalize ${isNavItemActive(item.path)
|
||||
className={`relative px-0 py-2 text-base font-medium transition-all duration-200 whitespace-nowrap group ${isNavItemActive(item.path)
|
||||
? 'text-primary'
|
||||
: 'text-gray-700 hover:text-gray-900'
|
||||
}`}
|
||||
@@ -384,6 +363,40 @@ export default function Navbar({
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
{/* City Dropdown */}
|
||||
{/* City Dropdown */}
|
||||
<Dropdown
|
||||
ref={cityRef}
|
||||
isOpen={activeCityDropdown}
|
||||
onToggle={() => {
|
||||
console.log('City dropdown toggled');
|
||||
// Add a small delay to prevent rapid state changes
|
||||
setTimeout(() => {
|
||||
setActiveCityDropdown(!activeCityDropdown);
|
||||
}, 50);
|
||||
}}
|
||||
items={cities.map(city => ({
|
||||
id: 'city-change',
|
||||
label: city.label,
|
||||
action: () => {
|
||||
console.log('City action called:', city.id);
|
||||
handleCityChange(city.id);
|
||||
}
|
||||
}))}
|
||||
title="Select City"
|
||||
trigger={
|
||||
<div className="flex items-center space-x-1.5 text-gray-700 hover:text-gray-900 text-base font-medium transition-colors duration-200 cursor-pointer rounded-lg hover:bg-gray-50/50 px-2 py-1">
|
||||
<span>
|
||||
{isLandingPage
|
||||
? 'Select City'
|
||||
: activeCity.charAt(0).toUpperCase() + activeCity.slice(1)
|
||||
}
|
||||
</span>
|
||||
<ChevronDown className={`w-3.5 h-3.5 transition-transform duration-200 ${activeCityDropdown ? 'rotate-180' : ''}`} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Right Section */}
|
||||
@@ -512,6 +525,30 @@ export default function Navbar({
|
||||
|
||||
{/* Mobile Actions */}
|
||||
<div className="flex items-center space-x-2">
|
||||
{/* Mobile City Selector */}
|
||||
<Dropdown
|
||||
ref={cityRef}
|
||||
isOpen={activeCityDropdown}
|
||||
onToggle={() => setActiveCityDropdown(!activeCityDropdown)}
|
||||
items={cities.map(city => ({
|
||||
id: 'city-change',
|
||||
label: city.label,
|
||||
action: () => handleCityChange(city.id)
|
||||
}))}
|
||||
title="Select City"
|
||||
trigger={
|
||||
<div className="flex items-center space-x-1 text-gray-700 hover:text-gray-900 text-sm font-medium transition-colors duration-200 cursor-pointer rounded-lg hover:bg-gray-50/50 px-2 py-1">
|
||||
<span>
|
||||
{isLandingPage
|
||||
? 'Select City'
|
||||
: activeCity.charAt(0).toUpperCase() + activeCity.slice(1)
|
||||
}
|
||||
</span>
|
||||
<ChevronDown className={`w-3.5 h-3.5 transition-transform duration-200 ${activeCityDropdown ? 'rotate-180' : ''}`} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Mobile Cart */}
|
||||
<motion.button
|
||||
className="relative text-gray-700 hover:text-gray-900 p-2 transition-colors duration-200 rounded-lg hover:bg-gray-50/50"
|
||||
@@ -572,15 +609,10 @@ export default function Navbar({
|
||||
</div>
|
||||
|
||||
<div className="p-6 space-y-6">
|
||||
{/* Mobile Navigation Links */}
|
||||
{/* Navigation Links based on page type */}
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{ label: 'How It Works', path: '/how-it-works' },
|
||||
{ label: 'Cities', path: '/melbourne' },
|
||||
{ label: 'Attractions', path: '/attractions' },
|
||||
{ label: 'Your Card', path: '/passes' },
|
||||
{ label: 'Deals', path: '/offers' }
|
||||
].map((item) => (
|
||||
<h3 className="text-lg font-semibold text-gray-900 px-4">Navigation</h3>
|
||||
{navigationItems.map((item) => (
|
||||
<motion.button
|
||||
key={item.path}
|
||||
onClick={() => handleNavClick(item.path)}
|
||||
@@ -596,22 +628,21 @@ export default function Navbar({
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Mobile Explore Card Section */}
|
||||
{/* City Selection in Mobile Menu */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-semibold text-gray-900 px-4">Explore Card</h3>
|
||||
{exploreCardItems.map((item) => (
|
||||
<h3 className="text-lg font-semibold text-gray-900 px-4">Select City</h3>
|
||||
{cities.map((city) => (
|
||||
<motion.button
|
||||
key={item.id}
|
||||
onClick={() => {
|
||||
if (item.path) {
|
||||
handleNavClick(item.path);
|
||||
}
|
||||
}}
|
||||
className="w-full flex items-center justify-between py-3 px-4 rounded-lg text-left transition-colors duration-200 text-gray-700 hover:bg-gray-100/70 hover:text-gray-900"
|
||||
key={city.id}
|
||||
onClick={() => handleCityChange(city.id)}
|
||||
className={`w-full flex items-center justify-between py-3 px-4 rounded-lg text-left transition-colors duration-200 ${activeCity === city.id
|
||||
? 'bg-primary/10 text-primary font-medium'
|
||||
: 'text-gray-700 hover:bg-gray-100/70 hover:text-gray-900'
|
||||
}`}
|
||||
whileHover={{ x: 4 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<span className="text-base">{item.label}</span>
|
||||
<span className="text-base">{city.label}</span>
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -8,13 +8,14 @@ import { Badge } from './ui/badge';
|
||||
import { Separator } from './ui/separator';
|
||||
import { Checkbox } from './ui/checkbox';
|
||||
import Navbar from './Navbar';
|
||||
import SubNavbar from './SubNavbar';
|
||||
// import SubNavbar from './SubNavbar';
|
||||
import { Footer } from './Footer';
|
||||
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||||
import { TrustSection } from './TrustSection';
|
||||
import { MobileAppSection } from './MobileAppSection';
|
||||
import { ReviewsSection } from './ReviewsSection';
|
||||
import { TrustedCompanies } from './TrustedCompanies';
|
||||
import { Layout } from '../Layout';
|
||||
|
||||
interface OffersPageProps {
|
||||
onBackClick: () => void;
|
||||
@@ -280,35 +281,15 @@ export function OffersPage({
|
||||
// Not logged in - show marketing/landing page
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Navbar
|
||||
activeCity="Paris"
|
||||
onCityChange={() => {}}
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onCheckoutClick={onCheckoutClick}
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onProfileClick={onProfileClick}
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
onPostCardsClick={onPostCardsClick}
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
currentPage={currentPage}
|
||||
isUserSignedIn={!!user}
|
||||
user={user}
|
||||
/>
|
||||
<Layout
|
||||
activeCity="Landingpage"
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
user={user}
|
||||
>
|
||||
|
||||
{/* Sub Navbar */}
|
||||
<SubNavbar
|
||||
{/* <SubNavbar
|
||||
activeTab="offers"
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
@@ -316,7 +297,7 @@ export function OffersPage({
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative pt-52 pb-20 overflow-hidden">
|
||||
@@ -592,24 +573,7 @@ export function OffersPage({
|
||||
<MobileAppSection />
|
||||
</section>
|
||||
|
||||
<Footer
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onCheckoutClick={onCheckoutClick}
|
||||
onSignInClick={onSignInClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onProfileClick={onProfileClick}
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
onPostCardsClick={onPostCardsClick}
|
||||
onOffersClick={onOffersClick}
|
||||
/>
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,13 +5,14 @@ import { Button } from './ui/button';
|
||||
import { Card, CardContent } from './ui/card';
|
||||
import { Badge } from './ui/badge';
|
||||
import Navbar from './Navbar';
|
||||
import SubNavbar from './SubNavbar';
|
||||
// import SubNavbar from './SubNavbar';
|
||||
import { Footer } from './Footer';
|
||||
import { MobileAppSection } from './MobileAppSection';
|
||||
import { EnhancedTestimonials } from './EnhancedTestimonials';
|
||||
import { CustomPostcards } from './CustomPostcards';
|
||||
import { HowItWorks } from './HowItWorks';
|
||||
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||||
import { Layout } from '../Layout';
|
||||
|
||||
interface User {
|
||||
email: string;
|
||||
@@ -72,34 +73,15 @@ export function PostCardsPage({
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Navbar */}
|
||||
<Navbar
|
||||
activeCity=""
|
||||
onCityChange={() => {}}
|
||||
onSignInClick={onSignInClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onCheckoutClick={onCheckoutClick}
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onAboutUsClick={onAboutUsClick}
|
||||
onProfileClick={onProfileClick}
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
onPostCardsClick={onPostCardsClick}
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
currentPage="postcards"
|
||||
isUserSignedIn={!!user}
|
||||
user={user}
|
||||
/>
|
||||
<Layout
|
||||
activeCity="Landingpage"
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
user={user}
|
||||
>
|
||||
|
||||
{/* Sub Navbar */}
|
||||
<SubNavbar
|
||||
{/* <SubNavbar
|
||||
activeTab="postcards"
|
||||
onCityCardsClick={onCityCardsClick}
|
||||
onMagicItineraryClick={onMagicItineraryClick}
|
||||
@@ -107,7 +89,7 @@ export function PostCardsPage({
|
||||
onOffersClick={onOffersClick}
|
||||
onEsimsClick={onEsimsClick}
|
||||
onHotelDiscountsClick={onHotelDiscountsClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative pt-52 pb-20 overflow-hidden">
|
||||
@@ -249,20 +231,8 @@ export function PostCardsPage({
|
||||
{/* Customer Reviews */}
|
||||
<EnhancedTestimonials />
|
||||
|
||||
{/* Footer */}
|
||||
<Footer
|
||||
onHomeClick={onHomeClick}
|
||||
onMelbourneClick={onMelbourneClick}
|
||||
onPassesClick={onPassesClick}
|
||||
onSignInClick={onSignInClick}
|
||||
onAttractionsClick={onAttractionsClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
onFAQClick={onFAQClick}
|
||||
onPrivacyPolicyClick={onPrivacyPolicyClick}
|
||||
onContactUsClick={onContactUsClick}
|
||||
currentPage={currentPage}
|
||||
/>
|
||||
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
||||
import { motion, useScroll, useTransform } from 'motion/react';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
import Navbar from './Navbar';
|
||||
import { CitySubmenu } from './CitySubmenu';
|
||||
// import { CitySubmenu } from './CitySubmenu';
|
||||
import { Footer } from './Footer';
|
||||
import { MobileAppSection } from './MobileAppSection';
|
||||
import { WhyChooseCityCards } from './WhyChooseCityCards';
|
||||
@@ -95,7 +95,7 @@ export function PrivacyPolicyPage({
|
||||
user={user}
|
||||
/>
|
||||
|
||||
<CitySubmenu
|
||||
{/* <CitySubmenu
|
||||
currentPage={currentPage}
|
||||
onClose={() => {}}
|
||||
onHomeClick={onHomeClick}
|
||||
@@ -104,7 +104,7 @@ export function PrivacyPolicyPage({
|
||||
onPassesClick={onPassesClick}
|
||||
onBlogsClick={onBlogsClick}
|
||||
onHowItWorksClick={onHowItWorksClick}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<div className="container mx-auto px-4 pt-52 pb-12 relative z-10">
|
||||
{/* Page Header */}
|
||||
|
||||
@@ -1,107 +1,107 @@
|
||||
|
||||
import { motion } from 'motion/react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
// import { motion } from 'motion/react';
|
||||
// import { useNavigate } from 'react-router-dom';
|
||||
|
||||
interface SubNavbarProps {
|
||||
activePage?: 'citycards' | 'magic-itinerary' | 'postcards' | 'offers' | 'esims' | 'hotel-discounts';
|
||||
activeTab?: 'citycards' | 'magic-itinerary' | 'postcards' | 'offers' | 'esims' | 'hotel-discounts';
|
||||
}
|
||||
// interface SubNavbarProps {
|
||||
// activePage?: 'citycards' | 'magic-itinerary' | 'postcards' | 'offers' | 'esims' | 'hotel-discounts';
|
||||
// activeTab?: 'citycards' | 'magic-itinerary' | 'postcards' | 'offers' | 'esims' | 'hotel-discounts';
|
||||
// }
|
||||
|
||||
export function SubNavbar({
|
||||
activeTab,
|
||||
activePage,
|
||||
}: SubNavbarProps) {
|
||||
const navigate = useNavigate();
|
||||
const activeProduct = activePage || activeTab;
|
||||
// export function SubNavbar({
|
||||
// activeTab,
|
||||
// activePage,
|
||||
// }: SubNavbarProps) {
|
||||
// const navigate = useNavigate();
|
||||
// const activeProduct = activePage || activeTab;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 'citycards',
|
||||
label: 'CityCards',
|
||||
path: '/citycards'
|
||||
},
|
||||
{
|
||||
id: 'magic-itinerary',
|
||||
label: 'Magic Itinerary',
|
||||
path: '/magic-itinerary'
|
||||
},
|
||||
{
|
||||
id: 'postcards',
|
||||
label: 'PostCards',
|
||||
path: '/postcards'
|
||||
},
|
||||
{
|
||||
id: 'offers',
|
||||
label: 'Offers',
|
||||
path: '/offers'
|
||||
},
|
||||
{
|
||||
id: 'esims',
|
||||
label: 'eSIMs',
|
||||
path: '/esims'
|
||||
},
|
||||
{
|
||||
id: 'hotel-discounts',
|
||||
label: 'Hotel Discounts',
|
||||
path: '/hotel-discounts'
|
||||
}
|
||||
];
|
||||
// const products = [
|
||||
// {
|
||||
// id: 'citycards',
|
||||
// label: 'CityCards',
|
||||
// path: '/citycards'
|
||||
// },
|
||||
// {
|
||||
// id: 'magic-itinerary',
|
||||
// label: 'Magic Itinerary',
|
||||
// path: '/magic-itinerary'
|
||||
// },
|
||||
// {
|
||||
// id: 'postcards',
|
||||
// label: 'PostCards',
|
||||
// path: '/postcards'
|
||||
// },
|
||||
// {
|
||||
// id: 'offers',
|
||||
// label: 'Offers',
|
||||
// path: '/offers'
|
||||
// },
|
||||
// {
|
||||
// id: 'esims',
|
||||
// label: 'eSIMs',
|
||||
// path: '/esims'
|
||||
// },
|
||||
// {
|
||||
// id: 'hotel-discounts',
|
||||
// label: 'Hotel Discounts',
|
||||
// path: '/hotel-discounts'
|
||||
// }
|
||||
// ];
|
||||
|
||||
const handleProductClick = (path: string) => {
|
||||
navigate(path);
|
||||
};
|
||||
// const handleProductClick = (path: string) => {
|
||||
// navigate(path);
|
||||
// };
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className="fixed top-[120px] left-1/2 transform -translate-x-1/2 z-30 hidden lg:block"
|
||||
initial={{ y: -20, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{
|
||||
duration: 0.6,
|
||||
ease: [0.25, 0.1, 0.25, 1],
|
||||
delay: 0.4
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200"
|
||||
initial={{ scale: 0.9 }}
|
||||
animate={{
|
||||
scale: 1,
|
||||
y: 0,
|
||||
boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03)"
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
{products.map((product) => (
|
||||
<motion.button
|
||||
key={product.id}
|
||||
onClick={() => handleProductClick(product.path)}
|
||||
className={`font-poppins font-medium text-base relative px-4 py-2.5 transition-all duration-300 whitespace-nowrap rounded-full ${
|
||||
activeProduct === product.id
|
||||
? 'bg-primary text-white shadow-md'
|
||||
: 'text-gray-700 hover:text-white hover:bg-gray-800'
|
||||
}`}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{product.label}
|
||||
// return (
|
||||
// <motion.div
|
||||
// className="fixed w-full z-30 hidden lg:block"
|
||||
// initial={{ y: -20, opacity: 0 }}
|
||||
// animate={{ y: 0, opacity: 1 }}
|
||||
// transition={{
|
||||
// duration: 0.6,
|
||||
// ease: [0.25, 0.1, 0.25, 1],
|
||||
// delay: 0.4
|
||||
// }}
|
||||
// style={{ top: '80px' }}
|
||||
// >
|
||||
// <motion.div
|
||||
// className="bg-white px-2 py-2 shadow-lg border border-gray-200"
|
||||
// initial={{ scale: 0.9 }}
|
||||
// animate={{
|
||||
// scale: 1,
|
||||
// y: 0,
|
||||
// boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03)"
|
||||
// }}
|
||||
// transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
// >
|
||||
// <div className="flex items-center gap-1 justify-center">
|
||||
// {products.map((product) => (
|
||||
// <motion.button
|
||||
// key={product.id}
|
||||
// onClick={() => handleProductClick(product.path)}
|
||||
// className={`font-poppins font-medium text-base relative px-4 py-2.5 transition-all duration-300 whitespace-nowrap rounded-full ${activeProduct === product.id
|
||||
// ? 'bg-primary text-white shadow-md'
|
||||
// : 'text-gray-700 hover:text-white hover:bg-gray-800'
|
||||
// }`}
|
||||
// whileHover={{ scale: 1.02 }}
|
||||
// whileTap={{ scale: 0.98 }}
|
||||
// >
|
||||
// {product.label}
|
||||
|
||||
{/* Hover effect for non-active items */}
|
||||
{activeProduct !== product.id && (
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-gray-800 rounded-full -z-10"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileHover={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
/>
|
||||
)}
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
// {/* Hover effect for non-active items */}
|
||||
// {activeProduct !== product.id && (
|
||||
// <motion.div
|
||||
// className="absolute inset-0 bg-gray-800 rounded-full -z-10"
|
||||
// initial={{ opacity: 0, scale: 0.9 }}
|
||||
// whileHover={{ opacity: 1, scale: 1 }}
|
||||
// transition={{ duration: 0.2 }}
|
||||
// />
|
||||
// )}
|
||||
// </motion.button>
|
||||
// ))}
|
||||
// </div>
|
||||
// </motion.div>
|
||||
// </motion.div>
|
||||
// );
|
||||
// }
|
||||
|
||||
export default SubNavbar;
|
||||
// export default SubNavbar;
|
||||
@@ -1,3 +1,4 @@
|
||||
@import "tailwindcss";
|
||||
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap");
|
||||
/*! tailwindcss v4.1.3 | MIT License | https://tailwindcss.com */
|
||||
@layer properties {
|
||||
|
||||
@@ -22,11 +22,10 @@ const ComingSoonPage: React.FC<ComingSoonPageProps> = ({
|
||||
|
||||
return (
|
||||
<Layout
|
||||
activeCity=""
|
||||
activeCity="Melbourne"
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
user={user}
|
||||
showCitySubmenu={false}
|
||||
>
|
||||
<div
|
||||
className="relative z-10 min-h-screen flex items-end justify-start pt-24 pb-16 bg-cover bg-center bg-no-repeat"
|
||||
|
||||
@@ -434,7 +434,7 @@ export function FAQPage({ onHomeClick,
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
// user={user}
|
||||
showCitySubmenu={false}
|
||||
// showCitySubmenu={false}
|
||||
>
|
||||
|
||||
{/* Main Content */}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Link } from 'react-router-dom';
|
||||
import { ChevronDown, MapPin, Star, Shield, Clock, Smartphone } from 'lucide-react';
|
||||
import Navbar from '../components/Navbar';
|
||||
import { Footer } from '../components/Footer';
|
||||
import { CitySubmenu } from '../components/CitySubmenu';
|
||||
// import { CitySubmenu } from '../components/CitySubmenu';
|
||||
import heroBannerImage from '../assets/landing-hero.png';
|
||||
import { Button } from '../components/ui/button';
|
||||
import { LandingWhyChooseCityCards } from '../components/LandingWhyChooseCityCards';
|
||||
@@ -102,9 +102,9 @@ export function LandingPage({ onSignInClick,
|
||||
/>
|
||||
|
||||
{/* City Submenu */}
|
||||
<CitySubmenu
|
||||
{/* <CitySubmenu
|
||||
onClose={() => { }}
|
||||
/>
|
||||
/> */}
|
||||
{/* Hero Section */}
|
||||
<div
|
||||
className="relative z-10 min-h-screen flex items-end justify-start pt-24 pb-16 bg-cover bg-center bg-no-repeat"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@import "tailwindcss";
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
Reference in New Issue
Block a user