full nav change

This commit is contained in:
priyanshuvish
2025-10-17 17:59:08 +05:30
parent 475956ae1a
commit ac5eded430
24 changed files with 1495 additions and 1479 deletions

378
package-lock.json generated
View File

@@ -35,6 +35,7 @@
"@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-toggle-group": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8", "@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/postcss": "^4.1.13", "@tailwindcss/postcss": "^4.1.13",
"@tailwindcss/vite": "^4.1.14",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "*", "clsx": "*",
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
@@ -53,7 +54,7 @@
"recharts": "^2.15.2", "recharts": "^2.15.2",
"sonner": "^2.0.3", "sonner": "^2.0.3",
"tailwind-merge": "*", "tailwind-merge": "*",
"tailwindcss": "^4.1.13", "tailwindcss": "^4.1.14",
"vaul": "^1.1.2" "vaul": "^1.1.2"
}, },
"devDependencies": { "devDependencies": {
@@ -92,7 +93,6 @@
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -109,7 +109,6 @@
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -126,7 +125,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -143,7 +141,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -160,7 +157,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -177,7 +173,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -194,7 +189,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -211,7 +205,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -228,7 +221,6 @@
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -245,7 +237,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -262,7 +253,6 @@
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -279,7 +269,6 @@
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -296,7 +285,6 @@
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -313,7 +301,6 @@
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -330,7 +317,6 @@
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -347,7 +333,6 @@
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -364,7 +349,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -381,7 +365,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -398,7 +381,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -415,7 +397,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -432,7 +413,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -449,7 +429,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -466,7 +445,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -483,7 +461,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -500,7 +477,6 @@
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -517,7 +493,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -1956,7 +1931,6 @@
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -1970,7 +1944,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -1984,7 +1957,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -1998,7 +1970,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2012,7 +1983,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2026,7 +1996,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2040,7 +2009,6 @@
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2054,7 +2022,6 @@
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2068,7 +2035,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2082,7 +2048,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2096,7 +2061,6 @@
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2110,7 +2074,6 @@
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2124,7 +2087,6 @@
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2138,7 +2100,6 @@
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2152,7 +2113,6 @@
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2166,7 +2126,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2180,7 +2139,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2194,7 +2152,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2208,7 +2165,6 @@
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2222,7 +2178,6 @@
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2236,7 +2191,6 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2484,6 +2438,12 @@
"tailwindcss": "4.1.13" "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": { "node_modules/@tailwindcss/oxide": {
"version": "4.1.13", "version": "4.1.13",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz",
@@ -2730,6 +2690,274 @@
"tailwindcss": "4.1.13" "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": { "node_modules/@types/d3-array": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz",
@@ -2797,14 +3025,13 @@
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.19.13", "version": "20.19.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.13.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.13.tgz",
"integrity": "sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==", "integrity": "sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==",
"dev": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.21.0" "undici-types": "~6.21.0"
@@ -3125,7 +3352,6 @@
"version": "0.25.9", "version": "0.25.9",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
"integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
"dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -3182,7 +3408,6 @@
"version": "6.5.0", "version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=12.0.0" "node": ">=12.0.0"
@@ -3227,7 +3452,6 @@
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
@@ -3273,9 +3497,9 @@
} }
}, },
"node_modules/jiti": { "node_modules/jiti": {
"version": "2.5.1", "version": "2.6.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
"integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
"license": "MIT", "license": "MIT",
"bin": { "bin": {
"jiti": "lib/jiti-cli.mjs" "jiti": "lib/jiti-cli.mjs"
@@ -3561,9 +3785,9 @@
} }
}, },
"node_modules/minizlib": { "node_modules/minizlib": {
"version": "3.0.2", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"minipass": "^7.1.2" "minipass": "^7.1.2"
@@ -3572,21 +3796,6 @@
"node": ">= 18" "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": { "node_modules/motion": {
"version": "12.23.12", "version": "12.23.12",
"resolved": "https://registry.npmjs.org/motion/-/motion-12.23.12.tgz", "resolved": "https://registry.npmjs.org/motion/-/motion-12.23.12.tgz",
@@ -3675,7 +3884,6 @@
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=12" "node": ">=12"
@@ -3974,7 +4182,6 @@
"version": "4.50.1", "version": "4.50.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz",
"integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/estree": "1.0.8" "@types/estree": "1.0.8"
@@ -4056,9 +4263,9 @@
} }
}, },
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "4.1.13", "version": "4.1.14",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
"integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==", "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/tapable": { "node_modules/tapable": {
@@ -4075,16 +4282,15 @@
} }
}, },
"node_modules/tar": { "node_modules/tar": {
"version": "7.4.3", "version": "7.5.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz",
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@isaacs/fs-minipass": "^4.0.0", "@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0", "chownr": "^3.0.0",
"minipass": "^7.1.2", "minipass": "^7.1.2",
"minizlib": "^3.0.1", "minizlib": "^3.1.0",
"mkdirp": "^3.0.1",
"yallist": "^5.0.0" "yallist": "^5.0.0"
}, },
"engines": { "engines": {
@@ -4101,7 +4307,6 @@
"version": "0.2.15", "version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fdir": "^6.5.0", "fdir": "^6.5.0",
@@ -4124,7 +4329,7 @@
"version": "6.21.0", "version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true, "devOptional": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/use-callback-ref": { "node_modules/use-callback-ref": {
@@ -4218,7 +4423,6 @@
"version": "6.3.5", "version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.25.0",

View File

@@ -30,6 +30,7 @@
"@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-toggle-group": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8", "@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/postcss": "^4.1.13", "@tailwindcss/postcss": "^4.1.13",
"@tailwindcss/vite": "^4.1.14",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "*", "clsx": "*",
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
@@ -48,7 +49,7 @@
"recharts": "^2.15.2", "recharts": "^2.15.2",
"sonner": "^2.0.3", "sonner": "^2.0.3",
"tailwind-merge": "*", "tailwind-merge": "*",
"tailwindcss": "^4.1.13", "tailwindcss": "^4.1.14",
"vaul": "^1.1.2" "vaul": "^1.1.2"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,6 +1,5 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import Navbar from './components/Navbar'; import Navbar from './components/Navbar';
import { CitySubmenu } from './components/CitySubmenu';
import { Footer } from './components/Footer'; import { Footer } from './components/Footer';
interface User { interface User {
@@ -11,7 +10,6 @@ interface User {
interface LayoutProps { interface LayoutProps {
children: ReactNode; children: ReactNode;
activeCity?: string; activeCity?: string;
showCitySubmenu?: boolean;
onSignInClick?: () => void; // ✅ optional onSignInClick?: () => void; // ✅ optional
onSignOutClick?: () => void; onSignOutClick?: () => void;
user?: User | null; user?: User | null;
@@ -20,7 +18,6 @@ interface LayoutProps {
export function Layout({ export function Layout({
children, children,
activeCity = 'Melbourne', activeCity = 'Melbourne',
showCitySubmenu = false,
onSignInClick, onSignInClick,
onSignOutClick, onSignOutClick,
user user
@@ -37,9 +34,6 @@ export function Layout({
user={user} user={user}
/> />
{/* City Submenu */}
{showCitySubmenu && <CitySubmenu onClose={() => {}} />}
{/* Main Content */} {/* Main Content */}
<main className="flex-1">{children}</main> <main className="flex-1">{children}</main>
@@ -47,4 +41,4 @@ export function Layout({
<Footer /> <Footer />
</div> </div>
); );
} }

View File

@@ -282,7 +282,6 @@ export function AttractionsPage({
onSignInClick={onSignInClick} onSignInClick={onSignInClick}
onSignOutClick={onSignOutClick} onSignOutClick={onSignOutClick}
user={user} user={user}
showCitySubmenu={true}
> >
<div className="container mx-auto px-4 pt-56 pb-16"> <div className="container mx-auto px-4 pt-56 pb-16">
{/* Page Header */} {/* Page Header */}

View File

@@ -6,7 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/
import { Badge } from './ui/badge'; import { Badge } from './ui/badge';
import { Input } from './ui/input'; import { Input } from './ui/input';
import Navbar from './Navbar'; import Navbar from './Navbar';
import { CitySubmenu } from './CitySubmenu'; // import { CitySubmenu } from './CitySubmenu';
import { MobileAppSection } from './MobileAppSection'; import { MobileAppSection } from './MobileAppSection';
import { WhyChooseCityCards } from './WhyChooseCityCards'; import { WhyChooseCityCards } from './WhyChooseCityCards';
import { EnhancedTestimonials } from './EnhancedTestimonials'; import { EnhancedTestimonials } from './EnhancedTestimonials';
@@ -226,7 +226,7 @@ export function BlogsPage({
user={user} user={user}
/> />
<CitySubmenu {/* <CitySubmenu
currentPage={currentPage} currentPage={currentPage}
onClose={() => {}} onClose={() => {}}
onHomeClick={onHomeClick} onHomeClick={onHomeClick}
@@ -235,7 +235,7 @@ export function BlogsPage({
onPassesClick={onPassesClick} onPassesClick={onPassesClick}
onBlogsClick={onBlogsClick} onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick} onHowItWorksClick={onHowItWorksClick}
/> /> */}
<div className="container mx-auto px-4 pt-52 pb-12 relative z-10"> <div className="container mx-auto px-4 pt-52 pb-12 relative z-10">
{/* Page Header */} {/* Page Header */}

View File

@@ -15,6 +15,7 @@ import { Textarea } from './ui/textarea';
import Navbar from './Navbar'; import Navbar from './Navbar';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { ImageWithFallback } from './figma/ImageWithFallback'; import { ImageWithFallback } from './figma/ImageWithFallback';
import { Layout } from '../Layout';
interface CheckoutPageProps { interface CheckoutPageProps {
onBackClick: () => void; onBackClick: () => void;
@@ -179,33 +180,12 @@ export function CheckoutPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
{/* Navbar */} <Layout
<Navbar activeCity="Melbourne"
activeCity="Paris" onSignInClick={onSignInClick}
onCityChange={() => {}} onSignOutClick={onSignOutClick}
onHomeClick={onHomeClick} user={user}
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}
/>
{/* Header Section */} {/* Header Section */}
<section className="pt-32 pb-8 bg-gradient-to-br from-muted/30 to-background"> <section className="pt-32 pb-8 bg-gradient-to-br from-muted/30 to-background">
@@ -748,20 +728,7 @@ export function CheckoutPage({
</DialogContent> </DialogContent>
</Dialog> </Dialog>
{/* Footer */} </Layout>
<Footer
onHomeClick={onHomeClick}
onMelbourneClick={onMelbourneClick}
onPassesClick={onPassesClick}
onSignInClick={onSignInClick}
onAttractionsClick={onAttractionsClick}
onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick}
onFAQClick={onFAQClick}
onPrivacyPolicyClick={onPrivacyPolicyClick}
onContactUsClick={onContactUsClick}
currentPage={currentPage}
/>
</div> </div>
); );
} }

View File

@@ -5,7 +5,7 @@ import { Button } from './ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card';
import { Badge } from './ui/badge'; import { Badge } from './ui/badge';
import Navbar from './Navbar'; import Navbar from './Navbar';
import SubNavbar from './SubNavbar'; // import SubNavbar from './SubNavbar';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { MobileAppSection } from './MobileAppSection'; import { MobileAppSection } from './MobileAppSection';
import { EnhancedTestimonials } from './EnhancedTestimonials'; import { EnhancedTestimonials } from './EnhancedTestimonials';
@@ -13,6 +13,7 @@ import { FAQPage } from './FAQPage';
import { HowItWorks } from './HowItWorks'; import { HowItWorks } from './HowItWorks';
import { WhyChooseCityCards } from './WhyChooseCityCards'; import { WhyChooseCityCards } from './WhyChooseCityCards';
import { ImageWithFallback } from './figma/ImageWithFallback'; import { ImageWithFallback } from './figma/ImageWithFallback';
import { Layout } from '../Layout';
interface User { interface User {
email: string; email: string;
@@ -73,35 +74,15 @@ export function CityCardsPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
{/* Navbar */} {/* Navbar */}
<Navbar <Layout
activeCity="" activeCity="Landingpage"
onCityChange={() => {}}
onSignInClick={onSignInClick} onSignInClick={onSignInClick}
onSignOutClick={onSignOutClick} 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} user={user}
/> >
{/* Sub Navbar */} {/* Sub Navbar */}
<SubNavbar {/* <SubNavbar
activeTab="citycards" activeTab="citycards"
onCityCardsClick={onCityCardsClick} onCityCardsClick={onCityCardsClick}
onMagicItineraryClick={onMagicItineraryClick} onMagicItineraryClick={onMagicItineraryClick}
@@ -109,283 +90,270 @@ export function CityCardsPage({
onOffersClick={onOffersClick} onOffersClick={onOffersClick}
onEsimsClick={onEsimsClick} onEsimsClick={onEsimsClick}
onHotelDiscountsClick={onHotelDiscountsClick} onHotelDiscountsClick={onHotelDiscountsClick}
/> /> */}
{/* Hero Section */} {/* Hero Section */}
<section className="relative pt-52 pb-20 overflow-hidden"> <section className="relative pt-52 pb-20 overflow-hidden">
{/* Background gradient */} {/* Background gradient */}
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-secondary/5 to-background"></div> <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="container mx-auto px-4 relative z-10">
<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 */}
<motion.div <motion.div
className="max-w-4xl mx-auto text-center"
initial={{ opacity: 0, y: 30 }} initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }} transition={{ duration: 0.6 }}
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"> <h1 className="font-merchant text-4xl md:text-5xl lg:text-6xl leading-tight mb-6">
<CardHeader className="text-center pb-6 pt-8 flex-shrink-0"> <span className="font-light">What Are</span>{' '}
<CardTitle className="font-poppins text-2xl font-bold mb-2 text-gray-900"> <span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
SELECTIVE PASS City Cards?
</CardTitle> </span>
<CardDescription className="text-gray-600 mb-6 leading-relaxed font-poppins h-[48px] flex items-center justify-center"> </h1>
Perfect for travelers who want to explore selected attractions at their own pace with essential features. <p className="font-poppins text-xl leading-relaxed font-normal text-gray-600 mb-8 max-w-2xl mx-auto">
</CardDescription> 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.
{/* Pricing */} </p>
<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>
</motion.div> </motion.div>
</div> </div>
</div>
</section>
{/* How It Works Section */} {/* Decorative elements */}
<HowItWorks /> <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 */} {/* Get Your City Cards Section */}
<WhyChooseCityCards /> <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 */} <p className="text-xs text-gray-500 text-center mt-4 font-poppins h-[32px] flex items-center justify-center">
<section className="py-16 bg-gray-50"> Free cancellation up to 24 hours Instant delivery
<div className="container mx-auto px-4"> </p>
<motion.div </div>
initial={{ opacity: 0, y: 20 }} </CardContent>
animate={{ opacity: 1, y: 0 }} </Card>
transition={{ duration: 0.6, delay: 0.2 }} </motion.div>
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"> {/* Unlimited Pass */}
<div className="space-y-4"> <motion.div
{[ initial={{ opacity: 0, y: 30 }}
{ animate={{ opacity: 1, y: 0 }}
question: "How do CityCards work?", transition={{ duration: 0.6, delay: 0.4 }}
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." className="relative flex"
}, >
{ <Card className="relative transition-all duration-300 cursor-pointer flex flex-col w-full ring-2 ring-primary shadow-xl">
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." {/* 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">
question: "What's included in an Unlimited Pass?", Most Popular
answer: "The Unlimited Pass includes access to all participating attractions in your chosen city, plus additional perks like discounts at restaurants and shops." </Badge>
}, </div>
{
question: "Do I need to book attractions in advance?", <CardHeader className="text-center pb-6 pt-8 flex-shrink-0">
answer: "Most attractions allow walk-in access with your CityCard, but some popular attractions may require advance booking through our app to guarantee entry." <CardTitle className="font-poppins text-2xl font-bold mb-2 text-gray-900">
}, UNLIMITED CARD
{ </CardTitle>
question: "What if I don't use all my attractions?", <CardDescription className="text-gray-600 mb-6 leading-relaxed font-poppins h-[48px] flex items-center justify-center">
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." The ultimate experience for adventure seekers who want unlimited access to all attractions with premium features.
} </CardDescription>
].map((faq, index) => (
<motion.div {/* Pricing */}
key={index} <div className="mb-6">
initial={{ opacity: 0, y: 20 }} <div className="flex items-baseline justify-center gap-2 mb-2">
animate={{ opacity: 1, y: 0 }} <span className="text-4xl font-bold text-gray-900">$89.99</span>
transition={{ duration: 0.6, delay: 0.3 + index * 0.1 }} <span className="text-gray-500 font-poppins">/ per person</span>
> </div>
<Card className="hover:shadow-md transition-shadow duration-300"> <div className="text-sm text-gray-500 font-poppins h-[20px]">
<CardContent className="p-6"> <span className="line-through mr-2">$149.99</span>
<h3 className="font-merchant text-lg mb-3">{faq.question}</h3> <span className="text-green-600 font-medium">Save 40%</span>
<p className="text-gray-600 font-poppins">{faq.answer}</p> </div>
</CardContent> </div>
</Card> </CardHeader>
</motion.div>
))} <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> </div>
</div> </section>
</section>
{/* Mobile App Section */} {/* How It Works Section */}
<MobileAppSection /> <HowItWorks />
{/* Customer Reviews */} {/* Why Choose CityCards Section */}
<EnhancedTestimonials /> <WhyChooseCityCards />
{/* Footer */} {/* Benefits Section */}
<Footer
onHomeClick={onHomeClick}
onMelbourneClick={onMelbourneClick} {/* Ready to Explore Melbourne Section */}
onPassesClick={onPassesClick}
onSignInClick={onSignInClick}
onAttractionsClick={onAttractionsClick} {/* FAQ Section */}
onBlogsClick={onBlogsClick} <section className="py-16 bg-gray-50">
onHowItWorksClick={onHowItWorksClick} <div className="container mx-auto px-4">
onFAQClick={onFAQClick} <motion.div
onPrivacyPolicyClick={onPrivacyPolicyClick} initial={{ opacity: 0, y: 20 }}
onContactUsClick={onContactUsClick} animate={{ opacity: 1, y: 0 }}
currentPage={currentPage} 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> </div>
); );
} }

View File

@@ -1,223 +1,223 @@
import { useState, useEffect } from 'react'; // import { useState, useEffect } from 'react';
import { motion } from 'motion/react'; // import { motion } from 'motion/react';
import { useLocation, useNavigate } from 'react-router-dom'; // import { useLocation, useNavigate } from 'react-router-dom';
interface CitySubmenuProps { // interface CitySubmenuProps {
onClose: () => void; // onClose: () => void;
} // }
interface SubmenuItem { // interface SubmenuItem {
id: string; // id: string;
label: string; // label: string;
path?: string; // path?: string;
action?: () => void; // action?: () => void;
} // }
export function CitySubmenu({ onClose }: CitySubmenuProps) { // export function CitySubmenu({ onClose }: CitySubmenuProps) {
const [isScrolled, setIsScrolled] = useState(false); // const [isScrolled, setIsScrolled] = useState(false);
const [activeItem, setActiveItem] = useState<string | null>(null); // const [activeItem, setActiveItem] = useState<string | null>(null);
const location = useLocation(); // const location = useLocation();
const navigate = useNavigate(); // const navigate = useNavigate();
// Direct submenu items for Melbourne // // Direct submenu items for Melbourne
const submenuItems: SubmenuItem[] = [ // const submenuItems: SubmenuItem[] = [
{ // {
id: 'melbourne', // id: 'melbourne',
label: 'Melbourne', // label: 'Melbourne',
path: '/melbourne' // path: '/melbourne'
}, // },
{ // {
id: 'attractions', // id: 'attractions',
label: 'Attractions', // label: 'Attractions',
path: '/attractions' // path: '/attractions'
}, // },
{ // {
id: 'buy-now', // id: 'buy-now',
label: 'Buy Now', // label: 'Buy Now',
path: '/passes' // path: '/passes'
}, // },
{ // {
id: 'blogs', // id: 'blogs',
label: 'Blogs', // label: 'Blogs',
path: '/blogs' // path: '/blogs'
}, // },
{ // {
id: 'how-it-works', // id: 'how-it-works',
label: 'How It Works', // label: 'How It Works',
path: '/how-it-works' // path: '/how-it-works'
} // }
]; // ];
// Handle scroll effects // // Handle scroll effects
useEffect(() => { // useEffect(() => {
const handleScroll = () => { // const handleScroll = () => {
const scrolled = window.scrollY > 20; // const scrolled = window.scrollY > 20;
setIsScrolled(scrolled); // setIsScrolled(scrolled);
}; // };
window.addEventListener('scroll', handleScroll); // window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll); // return () => window.removeEventListener('scroll', handleScroll);
}, []); // }, []);
// Determine active item based on current route // // Determine active item based on current route
useEffect(() => { // useEffect(() => {
const currentItem = submenuItems.find(item => // const currentItem = submenuItems.find(item =>
item.path && location.pathname === item.path // item.path && location.pathname === item.path
); // );
setActiveItem(currentItem?.id || null); // setActiveItem(currentItem?.id || null);
}, [location.pathname]); // }, [location.pathname]);
const handleSubmenuItemClick = (item: SubmenuItem) => { // const handleSubmenuItemClick = (item: SubmenuItem) => {
if (item.path) { // if (item.path) {
navigate(item.path); // navigate(item.path);
} // }
setActiveItem(item.id); // setActiveItem(item.id);
item.action?.(); // item.action?.();
onClose(); // onClose();
}; // };
const isSubmenuItemActive = (itemId: string) => { // const isSubmenuItemActive = (itemId: string) => {
return activeItem === itemId; // return activeItem === itemId;
}; // };
// Render direct submenu items // // Render direct submenu items
const renderSubmenu = () => ( // const renderSubmenu = () => (
<div className="flex items-center gap-1"> // <div className="flex items-center gap-1">
{submenuItems.map((item) => ( // {submenuItems.map((item) => (
<motion.button // <motion.button
key={item.id} // key={item.id}
onClick={() => handleSubmenuItemClick(item)} // onClick={() => handleSubmenuItemClick(item)}
className={`font-poppins font-medium text-base relative px-4 py-2.5 transition-all duration-300 whitespace-nowrap rounded-full ${ // className={`font-poppins font-medium text-base relative px-4 py-2.5 transition-all duration-300 whitespace-nowrap rounded-full ${
isSubmenuItemActive(item.id) // isSubmenuItemActive(item.id)
? 'bg-primary text-white shadow-md' // ? 'bg-primary text-white shadow-md'
: 'text-gray-700 hover:text-white hover:bg-gray-800' // : 'text-gray-700 hover:text-white hover:bg-gray-800'
}`} // }`}
whileHover={{ scale: 1.02 }} // whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }} // whileTap={{ scale: 0.98 }}
> // >
{item.label} // {item.label}
{!isSubmenuItemActive(item.id) && ( // {!isSubmenuItemActive(item.id) && (
<motion.div // <motion.div
className="absolute inset-0 bg-gray-800 rounded-full -z-10" // className="absolute inset-0 bg-gray-800 rounded-full -z-10"
initial={{ opacity: 0, scale: 0.9 }} // initial={{ opacity: 0, scale: 0.9 }}
whileHover={{ opacity: 1, scale: 1 }} // whileHover={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.2 }} // transition={{ duration: 0.2 }}
/> // />
)} // )}
</motion.button> // </motion.button>
))} // ))}
</div> // </div>
); // );
return ( // return (
<> // <>
{/* Desktop Submenu */} // {/* Desktop Submenu */}
<motion.div // <motion.div
className="fixed top-[120px] left-1/2 transform -translate-x-1/2 z-30 hidden lg:block" // className="fixed top-[120px] left-1/2 transform -translate-x-1/2 z-30 hidden lg:block"
initial={{ y: -20, opacity: 0 }} // initial={{ y: -20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }} // animate={{ y: 0, opacity: 1 }}
transition={{ // transition={{
duration: 0.6, // duration: 0.6,
ease: [0.25, 0.1, 0.25, 1], // ease: [0.25, 0.1, 0.25, 1],
delay: 0.4 // delay: 0.4
}} // }}
> // >
<motion.div // <motion.div
className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200" // className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200"
initial={{ scale: 0.9 }} // initial={{ scale: 0.9 }}
animate={{ // animate={{
scale: isScrolled ? 0.95 : 1, // scale: isScrolled ? 0.95 : 1,
y: isScrolled ? 2 : 0, // y: isScrolled ? 2 : 0,
boxShadow: isScrolled // boxShadow: isScrolled
? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)" // ? "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)" // : "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] }} // transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
> // >
{renderSubmenu()} // {renderSubmenu()}
</motion.div> // </motion.div>
</motion.div> // </motion.div>
{/* Mobile Submenu */} // {/* Mobile Submenu */}
<motion.div // <motion.div
className="fixed top-[100px] left-4 right-4 z-30 md:hidden" // className="fixed top-[100px] left-4 right-4 z-30 md:hidden"
initial={{ y: -20, opacity: 0 }} // initial={{ y: -20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }} // animate={{ y: 0, opacity: 1 }}
transition={{ // transition={{
duration: 0.6, // duration: 0.6,
ease: [0.25, 0.1, 0.25, 1], // ease: [0.25, 0.1, 0.25, 1],
delay: 0.4 // delay: 0.4
}} // }}
> // >
<motion.div // <motion.div
className="bg-white rounded-2xl px-3 py-3 shadow-lg border border-gray-200" // className="bg-white rounded-2xl px-3 py-3 shadow-lg border border-gray-200"
initial={{ scale: 0.9 }} // initial={{ scale: 0.9 }}
animate={{ // animate={{
scale: isScrolled ? 0.95 : 1, // scale: isScrolled ? 0.95 : 1,
y: isScrolled ? 2 : 0, // y: isScrolled ? 2 : 0,
boxShadow: isScrolled // boxShadow: isScrolled
? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)" // ? "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)" // : "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] }} // transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
> // >
<div className="flex items-center gap-2 overflow-x-auto scrollbar-hide"> // <div className="flex items-center gap-2 overflow-x-auto scrollbar-hide">
{submenuItems.map((item) => ( // {submenuItems.map((item) => (
<motion.button // <motion.button
key={item.id} // key={item.id}
onClick={() => handleSubmenuItemClick(item)} // onClick={() => handleSubmenuItemClick(item)}
className={`relative px-3 py-2 text-sm font-medium transition-all duration-300 whitespace-nowrap rounded-xl flex-shrink-0 ${ // className={`relative px-3 py-2 text-sm font-medium transition-all duration-300 whitespace-nowrap rounded-xl flex-shrink-0 ${
isSubmenuItemActive(item.id) // isSubmenuItemActive(item.id)
? 'bg-primary text-white shadow-md' // ? 'bg-primary text-white shadow-md'
: 'text-gray-700 hover:text-white hover:bg-gray-800' // : 'text-gray-700 hover:text-white hover:bg-gray-800'
}`} // }`}
whileHover={{ scale: 1.02 }} // whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }} // whileTap={{ scale: 0.98 }}
> // >
{item.label} // {item.label}
{!isSubmenuItemActive(item.id) && ( // {!isSubmenuItemActive(item.id) && (
<motion.div // <motion.div
className="absolute inset-0 bg-gray-800 rounded-xl -z-10" // className="absolute inset-0 bg-gray-800 rounded-xl -z-10"
initial={{ opacity: 0, scale: 0.9 }} // initial={{ opacity: 0, scale: 0.9 }}
whileHover={{ opacity: 1, scale: 1 }} // whileHover={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.2 }} // transition={{ duration: 0.2 }}
/> // />
)} // )}
</motion.button> // </motion.button>
))} // ))}
</div> // </div>
</motion.div> // </motion.div>
</motion.div> // </motion.div>
{/* Medium Screen Submenu */} // {/* Medium Screen Submenu */}
<motion.div // <motion.div
className="fixed top-[110px] left-1/2 transform -translate-x-1/2 z-30 hidden md:block lg:hidden" // className="fixed top-[110px] left-1/2 transform -translate-x-1/2 z-30 hidden md:block lg:hidden"
initial={{ y: -20, opacity: 0 }} // initial={{ y: -20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }} // animate={{ y: 0, opacity: 1 }}
transition={{ // transition={{
duration: 0.6, // duration: 0.6,
ease: [0.25, 0.1, 0.25, 1], // ease: [0.25, 0.1, 0.25, 1],
delay: 0.4 // delay: 0.4
}} // }}
> // >
<motion.div // <motion.div
className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200" // className="bg-white rounded-full px-2 py-2 shadow-lg border border-gray-200"
initial={{ scale: 0.9 }} // initial={{ scale: 0.9 }}
animate={{ // animate={{
scale: isScrolled ? 0.95 : 1, // scale: isScrolled ? 0.95 : 1,
y: isScrolled ? 2 : 0, // y: isScrolled ? 2 : 0,
boxShadow: isScrolled // boxShadow: isScrolled
? "0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04)" // ? "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)" // : "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] }} // transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1] }}
> // >
{renderSubmenu()} // {renderSubmenu()}
</motion.div> // </motion.div>
</motion.div> // </motion.div>
</> // </>
); // );
} // }

View File

@@ -2,9 +2,10 @@ import { motion } from 'motion/react';
import { Wifi, MapPin, Camera, Users, Smartphone, QrCode, Check, ArrowRight } from 'lucide-react'; import { Wifi, MapPin, Camera, Users, Smartphone, QrCode, Check, ArrowRight } from 'lucide-react';
import { useState } from 'react'; import { useState } from 'react';
import Navbar from './Navbar'; import Navbar from './Navbar';
import { SubNavbar } from './SubNavbar'; // import { SubNavbar } from './SubNavbar';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { ImageWithFallback } from './figma/ImageWithFallback'; import { ImageWithFallback } from './figma/ImageWithFallback';
import { Layout } from '../Layout';
interface EsimsPageProps { interface EsimsPageProps {
onBackClick: () => void; onBackClick: () => void;
@@ -57,7 +58,7 @@ export function EsimsPage({
currentPage, currentPage,
user user
}: EsimsPageProps) { }: EsimsPageProps) {
const benefits = [ const benefits = [
{ {
icon: MapPin, icon: MapPin,
@@ -90,34 +91,15 @@ export function EsimsPage({
return ( return (
<div className="min-h-screen bg-white"> <div className="min-h-screen bg-white">
{/* Navbar */} {/* Navbar */}
<Navbar <Layout
activeCity="Paris" activeCity="Landingpage"
onCityChange={() => {}}
onHomeClick={onHomeClick}
onMelbourneClick={onMelbourneClick}
onPassesClick={onPassesClick}
onCheckoutClick={onCheckoutClick}
onSignInClick={onSignInClick} onSignInClick={onSignInClick}
onSignOutClick={onSignOutClick} 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} user={user}
/> >
{/* SubNavbar for Products */} {/* SubNavbar for Products */}
<SubNavbar {/* <SubNavbar
activeTab="esims" activeTab="esims"
onCityCardsClick={onCityCardsClick} onCityCardsClick={onCityCardsClick}
onMagicItineraryClick={onMagicItineraryClick} onMagicItineraryClick={onMagicItineraryClick}
@@ -125,190 +107,190 @@ export function EsimsPage({
onOffersClick={onOffersClick} onOffersClick={onOffersClick}
onEsimsClick={onEsimsClick} onEsimsClick={onEsimsClick}
onHotelDiscountsClick={onHotelDiscountsClick} onHotelDiscountsClick={onHotelDiscountsClick}
/> /> */}
{/* Hero Section - eSIM Focus */} {/* Hero Section - eSIM Focus */}
<section className="relative pt-52 pb-20 overflow-hidden" style={{ backgroundColor: '#FFF5F5' }}> <section className="relative pt-52 pb-20 overflow-hidden" style={{ backgroundColor: '#FFF5F5' }}>
<div className="container mx-auto px-4 relative z-10"> <div className="container mx-auto px-4 relative z-10">
<motion.div <motion.div
className="max-w-4xl mx-auto text-center" className="max-w-4xl mx-auto text-center"
initial={{ opacity: 0, y: 30 }} initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }} 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' }}
> >
Start Your Journey Today <h1 className="font-poppins text-5xl md:text-6xl lg:text-7xl leading-tight mb-6">
<ArrowRight className="w-6 h-6 group-hover:translate-x-1 transition-transform duration-300" /> <span className="font-normal" style={{ color: '#1F2937' }}>Stay Connected Instantly</span>
</button> <br />
</motion.div> <span className="font-normal" style={{ color: '#1F2937' }}>with Your</span>{' '}
</div> <span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
</section> 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> </div>
); );
} }

View File

@@ -5,7 +5,7 @@ import { Input } from './ui/input';
import { Badge } from './ui/badge'; import { Badge } from './ui/badge';
import { Card, CardContent } from './ui/card'; import { Card, CardContent } from './ui/card';
import Navbar from './Navbar'; import Navbar from './Navbar';
import { CitySubmenu } from './CitySubmenu'; // import { CitySubmenu } from './CitySubmenu';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { MobileAppSection } from './MobileAppSection'; import { MobileAppSection } from './MobileAppSection';
import { WhyChooseCityCards } from './WhyChooseCityCards'; import { WhyChooseCityCards } from './WhyChooseCityCards';
@@ -214,7 +214,7 @@ export function FAQPage({
user={user} user={user}
/> />
<CitySubmenu {/* <CitySubmenu
currentPage={currentPage} currentPage={currentPage}
onClose={() => {}} onClose={() => {}}
onHomeClick={onHomeClick} onHomeClick={onHomeClick}
@@ -223,7 +223,7 @@ export function FAQPage({
onPassesClick={onPassesClick} onPassesClick={onPassesClick}
onBlogsClick={onBlogsClick} onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick} onHowItWorksClick={onHowItWorksClick}
/> /> */}
<div className="container mx-auto px-4 pt-52 pb-12"> <div className="container mx-auto px-4 pt-52 pb-12">
{/* Page Header */} {/* Page Header */}

View File

@@ -2,11 +2,12 @@ import { motion } from 'motion/react';
import { BadgePercent, Clock, Crown, Check, ArrowRight } from 'lucide-react'; import { BadgePercent, Clock, Crown, Check, ArrowRight } from 'lucide-react';
import { Button } from './ui/button'; import { Button } from './ui/button';
import Navbar from './Navbar'; import Navbar from './Navbar';
import { SubNavbar } from './SubNavbar'; // import { SubNavbar } from './SubNavbar';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { ImageWithFallback } from './figma/ImageWithFallback'; import { ImageWithFallback } from './figma/ImageWithFallback';
import cityCardsLogo from '../assets/cityLogo.png'; import cityCardsLogo from '../assets/cityLogo.png';
import marriottHotelImage from '../assets/marriott-hotel.png'; import marriottHotelImage from '../assets/marriott-hotel.png';
import { Layout } from '../Layout';
interface HotelDiscountsPageProps { interface HotelDiscountsPageProps {
onBackClick: () => void; onBackClick: () => void;
@@ -80,35 +81,15 @@ export function HotelDiscountsPage({
return ( return (
<div className="min-h-screen bg-white"> <div className="min-h-screen bg-white">
{/* Navbar */} <Layout
<Navbar activeCity="Landingpage"
activeCity="Paris"
onCityChange={() => {}}
onHomeClick={onHomeClick}
onPassesClick={onPassesClick}
onCheckoutClick={onCheckoutClick}
onSignInClick={onSignInClick} onSignInClick={onSignInClick}
onSignOutClick={onSignOutClick} 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} user={user}
/> >
{/* Sub Navbar */} {/* Sub Navbar */}
<SubNavbar {/* <SubNavbar
activePage="hotel-discounts" activePage="hotel-discounts"
onCityCardsClick={onCityCardsClick} onCityCardsClick={onCityCardsClick}
onMagicItineraryClick={onMagicItineraryClick} onMagicItineraryClick={onMagicItineraryClick}
@@ -116,184 +97,184 @@ export function HotelDiscountsPage({
onOffersClick={onOffersClick} onOffersClick={onOffersClick}
onEsimsClick={onEsimsClick} onEsimsClick={onEsimsClick}
onHotelDiscountsClick={onHotelDiscountsClick} onHotelDiscountsClick={onHotelDiscountsClick}
/> /> */}
{/* Hero Section */} {/* Hero Section */}
<section className="relative pt-64 pb-20 overflow-hidden"> <section className="relative pt-64 pb-20 overflow-hidden">
{/* Background Image with Overlay */} {/* Background Image with Overlay */}
<div className="absolute inset-0 z-0"> <div className="absolute inset-0 z-0">
<ImageWithFallback <ImageWithFallback
src={marriottHotelImage} src={marriottHotelImage}
alt="Marriott Hotel" alt="Marriott Hotel"
className="w-full h-full object-cover" 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 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>
);
})}
</div> </div>
{/* Closing Statement */} <div className="container mx-auto px-4 relative z-10">
<motion.div <motion.div
initial={{ opacity: 0, y: 30 }} initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
viewport={{ once: true }} transition={{ duration: 0.6 }}
transition={{ duration: 0.8, delay: 0.4 }} className="text-center"
className="text-center" >
> {/* CityCard Logo */}
<div className="max-w-4xl mx-auto mb-8"> <motion.div
<p className="font-poppins text-2xl md:text-3xl leading-relaxed font-normal" style={{ color: '#1F2937' }}> initial={{ opacity: 0, scale: 0.9 }}
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>. 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> </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> </div>
<button {/* Closing Statement */}
onClick={onCheckoutClick} <motion.div
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" initial={{ opacity: 0, y: 30 }}
style={{ backgroundColor: '#F95F62' }} whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: 0.4 }}
className="text-center"
> >
Get Your CityCard Today <div className="max-w-4xl mx-auto mb-8">
<ArrowRight className="w-6 h-6 group-hover:translate-x-1 transition-transform duration-300" /> <p className="font-poppins text-2xl md:text-3xl leading-relaxed font-normal" style={{ color: '#1F2937' }}>
</button> 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>.
</motion.div> </p>
</div> </div>
</section>
{/* Trust Anchor Section with Logo */} <button
<section className="py-16 bg-white border-t border-gray-100"> onClick={onCheckoutClick}
<div className="container mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20"> 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"
<motion.div style={{ backgroundColor: '#F95F62' }}
initial={{ opacity: 0, y: 20 }} >
whileInView={{ opacity: 1, y: 0 }} Get Your CityCard Today
viewport={{ once: true }} <ArrowRight className="w-6 h-6 group-hover:translate-x-1 transition-transform duration-300" />
transition={{ duration: 0.6 }} </button>
className="flex flex-col items-center text-center" </motion.div>
> </div>
<img </section>
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>
{/* 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> </div>
); );
} }

View File

@@ -5,7 +5,7 @@ import { Button } from './ui/button';
import { Card, CardContent } from './ui/card'; import { Card, CardContent } from './ui/card';
import { Badge } from './ui/badge'; import { Badge } from './ui/badge';
import Navbar from './Navbar'; import Navbar from './Navbar';
import { CitySubmenu } from './CitySubmenu'; // import { CitySubmenu } from './CitySubmenu';
import { AttractionHassleFreeSection } from './AttractionHassleFreeSection'; import { AttractionHassleFreeSection } from './AttractionHassleFreeSection';
import { MobileAppSection } from './MobileAppSection'; import { MobileAppSection } from './MobileAppSection';
import { WhyChooseCityCards } from './WhyChooseCityCards'; import { WhyChooseCityCards } from './WhyChooseCityCards';
@@ -189,7 +189,7 @@ export function HowItWorksPage({
user={user} user={user}
/> />
<CitySubmenu {/* <CitySubmenu
currentPage={currentPage} currentPage={currentPage}
onClose={() => {}} onClose={() => {}}
onHomeClick={onHomeClick} onHomeClick={onHomeClick}
@@ -198,7 +198,7 @@ export function HowItWorksPage({
onPassesClick={onPassesClick} onPassesClick={onPassesClick}
onBlogsClick={onBlogsClick} onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick} onHowItWorksClick={onHowItWorksClick}
/> /> */}
<div className="container mx-auto px-4 pt-52 pb-12 relative z-10"> <div className="container mx-auto px-4 pt-52 pb-12 relative z-10">
{/* Page Header */} {/* Page Header */}

View File

@@ -5,12 +5,13 @@ import { Button } from './ui/button';
import { Card, CardContent } from './ui/card'; import { Card, CardContent } from './ui/card';
import { Badge } from './ui/badge'; import { Badge } from './ui/badge';
import Navbar from './Navbar'; import Navbar from './Navbar';
import SubNavbar from './SubNavbar'; // import SubNavbar from './SubNavbar';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { MobileAppSection } from './MobileAppSection'; import { MobileAppSection } from './MobileAppSection';
import { EnhancedTestimonials } from './EnhancedTestimonials'; import { EnhancedTestimonials } from './EnhancedTestimonials';
import { HowItWorks } from './HowItWorks'; import { HowItWorks } from './HowItWorks';
import { ImageWithFallback } from './figma/ImageWithFallback'; import { ImageWithFallback } from './figma/ImageWithFallback';
import { Layout } from '../Layout';
interface User { interface User {
email: string; email: string;
@@ -75,34 +76,15 @@ export function MagicItineraryPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
{/* Navbar */} {/* Navbar */}
<Navbar <Layout
activeCity="" activeCity="Melbourne"
onCityChange={() => {}} onSignInClick={onSignInClick}
onSignInClick={onSignInClick} onSignOutClick={onSignOutClick}
onSignOutClick={onSignOutClick} user={user}
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}
/>
{/* Sub Navbar */} {/* Sub Navbar */}
<SubNavbar {/* <SubNavbar
activeTab="magic-itinerary" activeTab="magic-itinerary"
onCityCardsClick={onCityCardsClick} onCityCardsClick={onCityCardsClick}
onMagicItineraryClick={onMagicItineraryClick} onMagicItineraryClick={onMagicItineraryClick}
@@ -110,7 +92,7 @@ export function MagicItineraryPage({
onOffersClick={onOffersClick} onOffersClick={onOffersClick}
onEsimsClick={onEsimsClick} onEsimsClick={onEsimsClick}
onHotelDiscountsClick={onHotelDiscountsClick} onHotelDiscountsClick={onHotelDiscountsClick}
/> /> */}
{/* Hero Section */} {/* Hero Section */}
<section className="relative pt-52 pb-20 overflow-hidden"> <section className="relative pt-52 pb-20 overflow-hidden">
@@ -379,20 +361,8 @@ export function MagicItineraryPage({
{/* Customer Reviews */} {/* Customer Reviews */}
<EnhancedTestimonials /> <EnhancedTestimonials />
{/* Footer */}
<Footer </Layout>
onHomeClick={onHomeClick}
onMelbourneClick={onMelbourneClick}
onPassesClick={onPassesClick}
onSignInClick={onSignInClick}
onAttractionsClick={onAttractionsClick}
onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick}
onFAQClick={onFAQClick}
onPrivacyPolicyClick={onPrivacyPolicyClick}
onContactUsClick={onContactUsClick}
currentPage={currentPage}
/>
</div> </div>
); );
} }

View File

@@ -379,22 +379,6 @@ export function MelbournePage({
{/* Melbourne FAQ Section */} {/* Melbourne FAQ Section */}
<MelbourneFAQ /> <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> </div>
</Layout> </Layout>
); );

View File

@@ -56,16 +56,50 @@ export default function Navbar({
const [activeLanguageDropdown, setActiveLanguageDropdown] = useState(false); const [activeLanguageDropdown, setActiveLanguageDropdown] = useState(false);
const [activeCartDropdown, setActiveCartDropdown] = useState(false); const [activeCartDropdown, setActiveCartDropdown] = useState(false);
const [activeUserDropdown, setActiveUserDropdown] = useState(false); const [activeUserDropdown, setActiveUserDropdown] = useState(false);
const [activeExploreCardDropdown, setActiveExploreCardDropdown] = useState(false); const [activeCityDropdown, setActiveCityDropdown] = useState(false);
const languageRef = useRef<HTMLDivElement>(null); const languageRef = useRef<HTMLDivElement>(null);
const cartRef = useRef<HTMLDivElement>(null); const cartRef = useRef<HTMLDivElement>(null);
const userRef = useRef<HTMLDivElement>(null); const userRef = useRef<HTMLDivElement>(null);
const exploreCardRef = useRef<HTMLDivElement>(null); const cityRef = useRef<HTMLDivElement>(null);
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); 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 // Languages available
const languages: DropdownItem[] = [ const languages: DropdownItem[] = [
{ id: 'en', label: 'English', icon: <span className="text-base">🇺🇸</span> }, { 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> }, { 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 // Mock cart items
const cartItems: CartItem[] = [ const cartItems: CartItem[] = [
{ id: '1', name: 'Sydney 2-Day Pass', price: '$89', quantity: 1 }, { id: '1', name: 'Sydney 2-Day Pass', price: '$89', quantity: 1 },
{ id: '2', name: 'Melbourne Premium Pass', price: '$129', 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 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 sectionId = sectionIds[index];
const element = document.getElementById(sectionId); const element = document.getElementById(sectionId);
if (element) { if (element) {
@@ -153,27 +152,27 @@ export default function Navbar({
}, []); }, []);
// Close dropdowns when clicking outside // Close dropdowns when clicking outside
useEffect(() => { // useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { // const handleClickOutside = (event: MouseEvent) => {
setTimeout(() => { // setTimeout(() => {
if (languageRef.current && !languageRef.current.contains(event.target as Node)) { // if (languageRef.current && !languageRef.current.contains(event.target as Node)) {
setActiveLanguageDropdown(false); // setActiveLanguageDropdown(false);
} // }
if (cartRef.current && !cartRef.current.contains(event.target as Node)) { // if (cartRef.current && !cartRef.current.contains(event.target as Node)) {
setActiveCartDropdown(false); // setActiveCartDropdown(false);
} // }
if (userRef.current && !userRef.current.contains(event.target as Node)) { // if (userRef.current && !userRef.current.contains(event.target as Node)) {
setActiveUserDropdown(false); // setActiveUserDropdown(false);
} // }
if (exploreCardRef.current && !exploreCardRef.current.contains(event.target as Node)) { // if (cityRef.current && !cityRef.current.contains(event.target as Node)) {
setActiveExploreCardDropdown(false); // setActiveCityDropdown(false);
} // }
}, 10); // }, 10);
}; // };
document.addEventListener('mousedown', handleClickOutside); // document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside); // return () => document.removeEventListener('mousedown', handleClickOutside);
}, []); // }, []);
const handleNavClick = (path: string) => { const handleNavClick = (path: string) => {
navigate(path); navigate(path);
@@ -184,10 +183,21 @@ export default function Navbar({
return location.pathname === path; return location.pathname === path;
}; };
// Handle Explore Card dropdown item click // Handle city change
const handleExploreCardItemClick = (path: string) => { // Handle city change
navigate(path); const handleCityChange = (city: string) => {
setActiveExploreCardDropdown(false); 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 // Calculate cart total
@@ -196,14 +206,7 @@ export default function Navbar({
return total + (price * item.quantity); return total + (price * item.quantity);
}, 0); }, 0);
// Navigation items with router paths // Simple Dropdown component without blinking
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
const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(({ const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(({
isOpen, isOpen,
onToggle, onToggle,
@@ -212,86 +215,70 @@ export default function Navbar({
title, title,
className = "" className = ""
}, ref) => ( }, ref) => (
<div ref={ref} className={`relative ${className}`} style={{ height: 'auto', minHeight: 'auto' }}> <div ref={ref} className={`relative ${className}`}>
<motion.button <div
onClick={onToggle} onClick={(e) => {
className="relative" e.stopPropagation();
whileHover={{ scale: 1.02 }} onToggle();
whileTap={{ scale: 0.98 }} }}
className="cursor-pointer"
> >
{trigger} {trigger}
</motion.button> </div>
<AnimatePresence> <AnimatePresence>
{isOpen && ( {isOpen && (
<motion.div <>
initial={{ opacity: 0, y: 10, scale: 0.95 }} {/* Backdrop to capture outside clicks */}
animate={{ opacity: 1, y: 0, scale: 1 }} <motion.div
exit={{ opacity: 0, y: 10, scale: 0.95 }} initial={{ opacity: 0 }}
transition={{ duration: 0.2, ease: [0.25, 0.1, 0.25, 1] }} animate={{ opacity: 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" exit={{ opacity: 0 }}
style={{ className="fixed inset-0 z-40"
position: 'absolute', onClick={(e) => {
top: '100%', e.stopPropagation();
right: '0', onToggle();
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>
)}
<div className="py-3 px-2"> {/* Dropdown content */}
{items.map((item, index) => ( <motion.div
<motion.button initial={{ opacity: 0, y: 10, scale: 0.95 }}
key={item.id} animate={{ opacity: 1, y: 0, scale: 1 }}
onClick={(e) => { exit={{ opacity: 0, y: 10, scale: 0.95 }}
e.preventDefault(); transition={{ duration: 0.2, ease: [0.25, 0.1, 0.25, 1] }}
e.stopPropagation(); 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 <div className="py-2">
if (item.path) { {items.map((item, index) => (
navigate(item.path); <div
} key={item.id}
onClick={(e) => {
e.stopPropagation();
console.log('City dropdown item clicked:', item.label);
// Handle action if provided if (item.action) {
if (item.action && item.id !== 'total') { item.action();
item.action(); }
} // Don't call onToggle here - let the backdrop handle closing
}}
// Only close dropdown for actionable items className="px-4 py-2.5 hover:bg-gray-50/80 cursor-pointer transition-colors duration-200"
if (item.id === 'checkout' || item.path || (item.id !== 'total' && !item.action)) { >
setTimeout(() => onToggle(), 100); <div className="flex items-center justify-between">
} <span className="text-sm font-medium text-gray-700">{item.label}</span>
}} </div>
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>
</div> </div>
{item.badge && ( ))}
<span className="bg-primary text-primary-foreground text-xs px-2 py-1 rounded-full"> </div>
{item.badge} </motion.div>
</span> </>
)}
</motion.button>
))}
</div>
</motion.div>
)} )}
</AnimatePresence> </AnimatePresence>
</div> </div>
@@ -304,14 +291,14 @@ export default function Navbar({
<> <>
{/* Desktop Navbar - Enhanced Glassmorphism */} {/* Desktop Navbar - Enhanced Glassmorphism */}
<motion.nav <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 }} initial={{ y: -100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }} animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.6, ease: [0.25, 0.1, 0.25, 1], delay: 0.2 }} 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 <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-[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' : 'shadow-lg shadow-black/5'
}`} }`}
@@ -340,20 +327,12 @@ export default function Navbar({
</motion.div> </motion.div>
<div className="absolute left-1/2 -translate-x-1/2 flex items-center gap-5"> <div className="absolute left-1/2 -translate-x-1/2 flex items-center gap-5">
{/* Explore Card - First Item - No Dropdown */} {/* Navigation Items based on page type */}
<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 */}
{navigationItems.map((item) => ( {navigationItems.map((item) => (
<Link <Link
key={item.path} key={item.path}
to={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-primary'
: 'text-gray-700 hover:text-gray-900' : 'text-gray-700 hover:text-gray-900'
}`} }`}
@@ -384,6 +363,40 @@ export default function Navbar({
/> />
</Link> </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> </div>
{/* Right Section */} {/* Right Section */}
@@ -512,6 +525,30 @@ export default function Navbar({
{/* Mobile Actions */} {/* Mobile Actions */}
<div className="flex items-center space-x-2"> <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 */} {/* Mobile Cart */}
<motion.button <motion.button
className="relative text-gray-700 hover:text-gray-900 p-2 transition-colors duration-200 rounded-lg hover:bg-gray-50/50" 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>
<div className="p-6 space-y-6"> <div className="p-6 space-y-6">
{/* Mobile Navigation Links */} {/* Navigation Links based on page type */}
<div className="space-y-4"> <div className="space-y-4">
{[ <h3 className="text-lg font-semibold text-gray-900 px-4">Navigation</h3>
{ label: 'How It Works', path: '/how-it-works' }, {navigationItems.map((item) => (
{ label: 'Cities', path: '/melbourne' },
{ label: 'Attractions', path: '/attractions' },
{ label: 'Your Card', path: '/passes' },
{ label: 'Deals', path: '/offers' }
].map((item) => (
<motion.button <motion.button
key={item.path} key={item.path}
onClick={() => handleNavClick(item.path)} onClick={() => handleNavClick(item.path)}
@@ -596,22 +628,21 @@ export default function Navbar({
))} ))}
</div> </div>
{/* Mobile Explore Card Section */} {/* City Selection in Mobile Menu */}
<div className="space-y-4"> <div className="space-y-4">
<h3 className="text-lg font-semibold text-gray-900 px-4">Explore Card</h3> <h3 className="text-lg font-semibold text-gray-900 px-4">Select City</h3>
{exploreCardItems.map((item) => ( {cities.map((city) => (
<motion.button <motion.button
key={item.id} key={city.id}
onClick={() => { onClick={() => handleCityChange(city.id)}
if (item.path) { className={`w-full flex items-center justify-between py-3 px-4 rounded-lg text-left transition-colors duration-200 ${activeCity === city.id
handleNavClick(item.path); ? 'bg-primary/10 text-primary font-medium'
} : 'text-gray-700 hover:bg-gray-100/70 hover:text-gray-900'
}} }`}
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"
whileHover={{ x: 4 }} whileHover={{ x: 4 }}
whileTap={{ scale: 0.98 }} whileTap={{ scale: 0.98 }}
> >
<span className="text-base">{item.label}</span> <span className="text-base">{city.label}</span>
</motion.button> </motion.button>
))} ))}
</div> </div>

View File

@@ -8,13 +8,14 @@ import { Badge } from './ui/badge';
import { Separator } from './ui/separator'; import { Separator } from './ui/separator';
import { Checkbox } from './ui/checkbox'; import { Checkbox } from './ui/checkbox';
import Navbar from './Navbar'; import Navbar from './Navbar';
import SubNavbar from './SubNavbar'; // import SubNavbar from './SubNavbar';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { ImageWithFallback } from './figma/ImageWithFallback'; import { ImageWithFallback } from './figma/ImageWithFallback';
import { TrustSection } from './TrustSection'; import { TrustSection } from './TrustSection';
import { MobileAppSection } from './MobileAppSection'; import { MobileAppSection } from './MobileAppSection';
import { ReviewsSection } from './ReviewsSection'; import { ReviewsSection } from './ReviewsSection';
import { TrustedCompanies } from './TrustedCompanies'; import { TrustedCompanies } from './TrustedCompanies';
import { Layout } from '../Layout';
interface OffersPageProps { interface OffersPageProps {
onBackClick: () => void; onBackClick: () => void;
@@ -280,35 +281,15 @@ export function OffersPage({
// Not logged in - show marketing/landing page // Not logged in - show marketing/landing page
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<Navbar <Layout
activeCity="Paris" activeCity="Landingpage"
onCityChange={() => {}} onSignInClick={onSignInClick}
onHomeClick={onHomeClick} onSignOutClick={onSignOutClick}
onMelbourneClick={onMelbourneClick} user={user}
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}
/>
{/* Sub Navbar */} {/* Sub Navbar */}
<SubNavbar {/* <SubNavbar
activeTab="offers" activeTab="offers"
onCityCardsClick={onCityCardsClick} onCityCardsClick={onCityCardsClick}
onMagicItineraryClick={onMagicItineraryClick} onMagicItineraryClick={onMagicItineraryClick}
@@ -316,7 +297,7 @@ export function OffersPage({
onOffersClick={onOffersClick} onOffersClick={onOffersClick}
onEsimsClick={onEsimsClick} onEsimsClick={onEsimsClick}
onHotelDiscountsClick={onHotelDiscountsClick} onHotelDiscountsClick={onHotelDiscountsClick}
/> /> */}
{/* Hero Section */} {/* Hero Section */}
<section className="relative pt-52 pb-20 overflow-hidden"> <section className="relative pt-52 pb-20 overflow-hidden">
@@ -592,24 +573,7 @@ export function OffersPage({
<MobileAppSection /> <MobileAppSection />
</section> </section>
<Footer </Layout>
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}
/>
</div> </div>
); );
} }

View File

@@ -5,13 +5,14 @@ import { Button } from './ui/button';
import { Card, CardContent } from './ui/card'; import { Card, CardContent } from './ui/card';
import { Badge } from './ui/badge'; import { Badge } from './ui/badge';
import Navbar from './Navbar'; import Navbar from './Navbar';
import SubNavbar from './SubNavbar'; // import SubNavbar from './SubNavbar';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { MobileAppSection } from './MobileAppSection'; import { MobileAppSection } from './MobileAppSection';
import { EnhancedTestimonials } from './EnhancedTestimonials'; import { EnhancedTestimonials } from './EnhancedTestimonials';
import { CustomPostcards } from './CustomPostcards'; import { CustomPostcards } from './CustomPostcards';
import { HowItWorks } from './HowItWorks'; import { HowItWorks } from './HowItWorks';
import { ImageWithFallback } from './figma/ImageWithFallback'; import { ImageWithFallback } from './figma/ImageWithFallback';
import { Layout } from '../Layout';
interface User { interface User {
email: string; email: string;
@@ -72,34 +73,15 @@ export function PostCardsPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
{/* Navbar */} {/* Navbar */}
<Navbar <Layout
activeCity="" activeCity="Landingpage"
onCityChange={() => {}} onSignInClick={onSignInClick}
onSignInClick={onSignInClick} onSignOutClick={onSignOutClick}
onPassesClick={onPassesClick} user={user}
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}
/>
{/* Sub Navbar */} {/* Sub Navbar */}
<SubNavbar {/* <SubNavbar
activeTab="postcards" activeTab="postcards"
onCityCardsClick={onCityCardsClick} onCityCardsClick={onCityCardsClick}
onMagicItineraryClick={onMagicItineraryClick} onMagicItineraryClick={onMagicItineraryClick}
@@ -107,7 +89,7 @@ export function PostCardsPage({
onOffersClick={onOffersClick} onOffersClick={onOffersClick}
onEsimsClick={onEsimsClick} onEsimsClick={onEsimsClick}
onHotelDiscountsClick={onHotelDiscountsClick} onHotelDiscountsClick={onHotelDiscountsClick}
/> /> */}
{/* Hero Section */} {/* Hero Section */}
<section className="relative pt-52 pb-20 overflow-hidden"> <section className="relative pt-52 pb-20 overflow-hidden">
@@ -249,20 +231,8 @@ export function PostCardsPage({
{/* Customer Reviews */} {/* Customer Reviews */}
<EnhancedTestimonials /> <EnhancedTestimonials />
{/* Footer */}
<Footer </Layout>
onHomeClick={onHomeClick}
onMelbourneClick={onMelbourneClick}
onPassesClick={onPassesClick}
onSignInClick={onSignInClick}
onAttractionsClick={onAttractionsClick}
onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick}
onFAQClick={onFAQClick}
onPrivacyPolicyClick={onPrivacyPolicyClick}
onContactUsClick={onContactUsClick}
currentPage={currentPage}
/>
</div> </div>
); );
} }

View File

@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { motion, useScroll, useTransform } from 'motion/react'; import { motion, useScroll, useTransform } from 'motion/react';
import { ArrowLeft } from 'lucide-react'; import { ArrowLeft } from 'lucide-react';
import Navbar from './Navbar'; import Navbar from './Navbar';
import { CitySubmenu } from './CitySubmenu'; // import { CitySubmenu } from './CitySubmenu';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { MobileAppSection } from './MobileAppSection'; import { MobileAppSection } from './MobileAppSection';
import { WhyChooseCityCards } from './WhyChooseCityCards'; import { WhyChooseCityCards } from './WhyChooseCityCards';
@@ -95,7 +95,7 @@ export function PrivacyPolicyPage({
user={user} user={user}
/> />
<CitySubmenu {/* <CitySubmenu
currentPage={currentPage} currentPage={currentPage}
onClose={() => {}} onClose={() => {}}
onHomeClick={onHomeClick} onHomeClick={onHomeClick}
@@ -104,7 +104,7 @@ export function PrivacyPolicyPage({
onPassesClick={onPassesClick} onPassesClick={onPassesClick}
onBlogsClick={onBlogsClick} onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick} onHowItWorksClick={onHowItWorksClick}
/> /> */}
<div className="container mx-auto px-4 pt-52 pb-12 relative z-10"> <div className="container mx-auto px-4 pt-52 pb-12 relative z-10">
{/* Page Header */} {/* Page Header */}

View File

@@ -1,107 +1,107 @@
import { motion } from 'motion/react'; // import { motion } from 'motion/react';
import { useNavigate } from 'react-router-dom'; // import { useNavigate } from 'react-router-dom';
interface SubNavbarProps { // interface SubNavbarProps {
activePage?: 'citycards' | 'magic-itinerary' | 'postcards' | 'offers' | 'esims' | 'hotel-discounts'; // activePage?: 'citycards' | 'magic-itinerary' | 'postcards' | 'offers' | 'esims' | 'hotel-discounts';
activeTab?: 'citycards' | 'magic-itinerary' | 'postcards' | 'offers' | 'esims' | 'hotel-discounts'; // activeTab?: 'citycards' | 'magic-itinerary' | 'postcards' | 'offers' | 'esims' | 'hotel-discounts';
} // }
export function SubNavbar({ // export function SubNavbar({
activeTab, // activeTab,
activePage, // activePage,
}: SubNavbarProps) { // }: SubNavbarProps) {
const navigate = useNavigate(); // const navigate = useNavigate();
const activeProduct = activePage || activeTab; // 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 handleProductClick = (path: string) => { // const products = [
navigate(path); // {
}; // 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'
// }
// ];
return ( // const handleProductClick = (path: string) => {
<motion.div // navigate(path);
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}
{/* 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; // 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>
// );
// }
// export default SubNavbar;

View File

@@ -1,3 +1,4 @@
@import "tailwindcss";
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"); @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 */ /*! tailwindcss v4.1.3 | MIT License | https://tailwindcss.com */
@layer properties { @layer properties {

View File

@@ -22,11 +22,10 @@ const ComingSoonPage: React.FC<ComingSoonPageProps> = ({
return ( return (
<Layout <Layout
activeCity="" activeCity="Melbourne"
onSignInClick={onSignInClick} onSignInClick={onSignInClick}
onSignOutClick={onSignOutClick} onSignOutClick={onSignOutClick}
user={user} user={user}
showCitySubmenu={false}
> >
<div <div
className="relative z-10 min-h-screen flex items-end justify-start pt-24 pb-16 bg-cover bg-center bg-no-repeat" className="relative z-10 min-h-screen flex items-end justify-start pt-24 pb-16 bg-cover bg-center bg-no-repeat"

View File

@@ -434,7 +434,7 @@ export function FAQPage({ onHomeClick,
onSignInClick={onSignInClick} onSignInClick={onSignInClick}
onSignOutClick={onSignOutClick} onSignOutClick={onSignOutClick}
// user={user} // user={user}
showCitySubmenu={false} // showCitySubmenu={false}
> >
{/* Main Content */} {/* Main Content */}

View File

@@ -4,7 +4,7 @@ import { Link } from 'react-router-dom';
import { ChevronDown, MapPin, Star, Shield, Clock, Smartphone } from 'lucide-react'; import { ChevronDown, MapPin, Star, Shield, Clock, Smartphone } from 'lucide-react';
import Navbar from '../components/Navbar'; import Navbar from '../components/Navbar';
import { Footer } from '../components/Footer'; import { Footer } from '../components/Footer';
import { CitySubmenu } from '../components/CitySubmenu'; // import { CitySubmenu } from '../components/CitySubmenu';
import heroBannerImage from '../assets/landing-hero.png'; import heroBannerImage from '../assets/landing-hero.png';
import { Button } from '../components/ui/button'; import { Button } from '../components/ui/button';
import { LandingWhyChooseCityCards } from '../components/LandingWhyChooseCityCards'; import { LandingWhyChooseCityCards } from '../components/LandingWhyChooseCityCards';
@@ -102,9 +102,9 @@ export function LandingPage({ onSignInClick,
/> />
{/* City Submenu */} {/* City Submenu */}
<CitySubmenu {/* <CitySubmenu
onClose={() => { }} onClose={() => { }}
/> /> */}
{/* Hero Section */} {/* Hero Section */}
<div <div
className="relative z-10 min-h-screen flex items-end justify-start pt-24 pb-16 bg-cover bg-center bg-no-repeat" className="relative z-10 min-h-screen flex items-end justify-start pt-24 pb-16 bg-cover bg-center bg-no-repeat"

View File

@@ -1,3 +1,4 @@
@import "tailwindcss";
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));