Spaces:
Running
Running
Upload 40 files
Browse files- .gitattributes +3 -0
- project 2/.bolt/config.json +3 -0
- project 2/.bolt/prompt +5 -0
- project 2/.env +3 -0
- project 2/.gitignore +25 -0
- project 2/README.md +1 -0
- project 2/dist/assets/WhatsApp Image 2025-06-28 at 12.51.41.jpeg +3 -0
- project 2/dist/assets/index-CiBv4vu0.css +1 -0
- project 2/dist/assets/index-zPcAIS4j.js +0 -0
- project 2/dist/assets/logo.png +3 -0
- project 2/dist/index.html +19 -0
- project 2/dist/logo.png +1 -0
- project 2/eslint.config.js +28 -0
- project 2/index.html +18 -0
- project 2/package-lock.json +0 -0
- project 2/package.json +38 -0
- project 2/postcss.config.js +6 -0
- project 2/public/assets/WhatsApp Image 2025-06-28 at 12.51.41.jpeg +3 -0
- project 2/public/logo.png +1 -0
- project 2/src/App.tsx +17 -0
- project 2/src/components/BackgroundEffects.tsx +86 -0
- project 2/src/components/ConsultationForm.tsx +240 -0
- project 2/src/components/Footer.tsx +91 -0
- project 2/src/components/Navbar.tsx +162 -0
- project 2/src/index.css +3 -0
- project 2/src/lib/supabase.ts +29 -0
- project 2/src/main.tsx +10 -0
- project 2/src/pages/BookingForm.tsx +429 -0
- project 2/src/pages/HomePage.tsx +26 -0
- project 2/src/sections/ContactSection.tsx +349 -0
- project 2/src/sections/FeaturesSection.tsx +196 -0
- project 2/src/sections/HeroSection.tsx +99 -0
- project 2/src/sections/ResultsSection.tsx +113 -0
- project 2/src/vite-env.d.ts +1 -0
- project 2/supabase/migrations/20250607101952_lucky_coral.sql +42 -0
- project 2/supabase/migrations/20250608090446_amber_boat.sql +44 -0
- project 2/tailwind.config.js +89 -0
- project 2/tsconfig.app.json +24 -0
- project 2/tsconfig.json +7 -0
- project 2/tsconfig.node.json +22 -0
- project 2/vite.config.ts +10 -0
.gitattributes
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
project[[:space:]]2/dist/assets/logo.png filter=lfs diff=lfs merge=lfs -text
|
2 |
+
project[[:space:]]2/dist/assets/WhatsApp[[:space:]]Image[[:space:]]2025-06-28[[:space:]]at[[:space:]]12.51.41.jpeg filter=lfs diff=lfs merge=lfs -text
|
3 |
+
project[[:space:]]2/public/assets/WhatsApp[[:space:]]Image[[:space:]]2025-06-28[[:space:]]at[[:space:]]12.51.41.jpeg filter=lfs diff=lfs merge=lfs -text
|
project 2/.bolt/config.json
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"template": "bolt-vite-react-ts"
|
3 |
+
}
|
project 2/.bolt/prompt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
For all designs I ask you to make, have them be beautiful, not cookie cutter. Make webpages that are fully featured and worthy for production.
|
2 |
+
|
3 |
+
By default, this template supports JSX syntax with Tailwind CSS classes, React hooks, and Lucide React for icons. Do not install other packages for UI themes, icons, etc unless absolutely necessary or I request them.
|
4 |
+
|
5 |
+
Use icons from lucide-react for logos.
|
project 2/.env
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Impmc2hwYXlkcXdkZW5uaXBkZWxhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDkyMjA3MTQsImV4cCI6MjA2NDc5NjcxNH0.YqxrHuJQLKUkk9fVPNSCaTmHjYb0rAyzNzu-pdd8f18
|
3 |
+
VITE_SUPABASE_URL=https://jfshpaydqwdennipdela.supabase.co
|
project 2/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Logs
|
2 |
+
logs
|
3 |
+
*.log
|
4 |
+
npm-debug.log*
|
5 |
+
yarn-debug.log*
|
6 |
+
yarn-error.log*
|
7 |
+
pnpm-debug.log*
|
8 |
+
lerna-debug.log*
|
9 |
+
|
10 |
+
node_modules
|
11 |
+
dist
|
12 |
+
dist-ssr
|
13 |
+
*.local
|
14 |
+
|
15 |
+
# Editor directories and files
|
16 |
+
.vscode/*
|
17 |
+
!.vscode/extensions.json
|
18 |
+
.idea
|
19 |
+
.DS_Store
|
20 |
+
*.suo
|
21 |
+
*.ntvs*
|
22 |
+
*.njsproj
|
23 |
+
*.sln
|
24 |
+
*.sw?
|
25 |
+
.env
|
project 2/README.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
new_github_neocyberacquisition
|
project 2/dist/assets/WhatsApp Image 2025-06-28 at 12.51.41.jpeg
ADDED
![]() |
Git LFS Details
|
project 2/dist/assets/index-CiBv4vu0.css
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Space Grotesk,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.-inset-1{top:-.25rem;right:-.25rem;bottom:-.25rem;left:-.25rem}.inset-0{top:0;right:0;bottom:0;left:0}.inset-8{top:2rem;right:2rem;bottom:2rem;left:2rem}.-bottom-1{bottom:-.25rem}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.bottom-8{bottom:2rem}.bottom-\[30\%\]{bottom:30%}.left-0{left:0}.left-1\/2{left:50%}.left-3{left:.75rem}.left-4{left:1rem}.left-8{left:2rem}.left-\[-10\%\]{left:-10%}.left-\[10\%\]{left:10%}.right-0{right:0}.right-4{right:1rem}.right-8{right:2rem}.right-\[-10\%\]{right:-10%}.right-\[15\%\]{right:15%}.top-0{top:0}.top-1\/2{top:50%}.top-8{top:2rem}.top-\[20\%\]{top:20%}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-span-1{grid-column:span 1 / span 1}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-6{margin-right:1.5rem}.mt-1{margin-top:.25rem}.mt-12{margin-top:3rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-0\.5{height:.125rem}.h-1{height:.25rem}.h-12{height:3rem}.h-3{height:.75rem}.h-5{height:1.25rem}.h-64{height:16rem}.h-8{height:2rem}.h-80{height:20rem}.h-\[300px\]{height:300px}.h-\[400px\]{height:400px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1{width:.25rem}.w-3{width:.75rem}.w-5{width:1.25rem}.w-8{width:2rem}.w-80{width:20rem}.w-\[300px\]{width:300px}.w-\[400px\]{width:400px}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-7xl{max-width:80rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-12{gap:3rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.75rem * var(--tw-space-x-reverse));margin-left:calc(.75rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(2rem * var(--tw-space-x-reverse));margin-left:calc(2rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-t{border-top-width:1px}.border-green-500\/30{border-color:#22c55e4d}.border-primary-900\/30{border-color:#0d47474d}.border-red-500\/30{border-color:#ef44444d}.border-secondary-700\/50{border-color:#0b666680}.border-secondary-800\/30{border-color:#0c4d4d4d}.border-secondary-900\/20{border-color:#0d3f3f33}.border-white\/10{border-color:#ffffff1a}.border-white\/30{border-color:#ffffff4d}.border-white\/\[0\.05\]{border-color:#ffffff0d}.border-white\/\[0\.08\]{border-color:#ffffff14}.border-t-white{--tw-border-opacity: 1;border-top-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.bg-accent-400\/60{background-color:#14fff999}.bg-accent-900\/10{background-color:#005e5d1a}.bg-background,.bg-background-dark,.bg-background-light{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-background\/80{background-color:#000c}.bg-background\/95{background-color:#000000f2}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\/10{background-color:#0000001a}.bg-green-900\/20{background-color:#14532d33}.bg-primary-900\/15{background-color:#0d474726}.bg-red-900\/20{background-color:#7f1d1d33}.bg-secondary-500{--tw-bg-opacity: 1;background-color:rgb(26 158 158 / var(--tw-bg-opacity, 1))}.bg-secondary-900\/10{background-color:#0d3f3f1a}.bg-transparent{background-color:transparent}.bg-white\/\[0\.02\]{background-color:#ffffff05}.bg-white\/\[0\.03\]{background-color:#ffffff08}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.bg-grain{background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.1'/%3E%3C/svg%3E")}.from-accent-500{--tw-gradient-from: #00e6e0 var(--tw-gradient-from-position);--tw-gradient-to: rgb(0 230 224 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-black\/20{--tw-gradient-from: rgb(0 0 0 / .2) var(--tw-gradient-from-position);--tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary-500{--tw-gradient-from: #14c7c7 var(--tw-gradient-from-position);--tw-gradient-to: rgb(20 199 199 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary-600\/0{--tw-gradient-from: rgb(10 163 163 / 0) var(--tw-gradient-from-position);--tw-gradient-to: rgb(10 163 163 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-secondary-400{--tw-gradient-from: #2cb9b9 var(--tw-gradient-from-position);--tw-gradient-to: rgb(44 185 185 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-secondary-500{--tw-gradient-from: #1a9e9e var(--tw-gradient-from-position);--tw-gradient-to: rgb(26 158 158 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-secondary-600{--tw-gradient-from: #0d7f7f var(--tw-gradient-from-position);--tw-gradient-to: rgb(13 127 127 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-secondary-900\/20{--tw-gradient-from: rgb(13 63 63 / .2) var(--tw-gradient-from-position);--tw-gradient-to: rgb(13 63 63 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-transparent{--tw-gradient-from: transparent var(--tw-gradient-from-position);--tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-accent-500{--tw-gradient-to: rgb(0 230 224 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), #00e6e0 var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-accent-900\/10{--tw-gradient-to: rgb(0 94 93 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), rgb(0 94 93 / .1) var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-primary-600\/20{--tw-gradient-to: rgb(10 163 163 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), rgb(10 163 163 / .2) var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-secondary-700\/50{--tw-gradient-to: rgb(11 102 102 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), rgb(11 102 102 / .5) var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-transparent{--tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), transparent var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-accent-400{--tw-gradient-to: #14fff9 var(--tw-gradient-to-position)}.to-accent-500{--tw-gradient-to: #00e6e0 var(--tw-gradient-to-position)}.to-accent-600{--tw-gradient-to: #00b8b4 var(--tw-gradient-to-position)}.to-accent-600\/0{--tw-gradient-to: rgb(0 184 180 / 0) var(--tw-gradient-to-position)}.to-accent-700{--tw-gradient-to: #009290 var(--tw-gradient-to-position)}.to-primary-500{--tw-gradient-to: #14c7c7 var(--tw-gradient-to-position)}.to-primary-900\/10{--tw-gradient-to: rgb(13 71 71 / .1) var(--tw-gradient-to-position)}.to-primary-900\/20{--tw-gradient-to: rgb(13 71 71 / .2) var(--tw-gradient-to-position)}.to-secondary-900{--tw-gradient-to: #0d3f3f var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to: transparent var(--tw-gradient-to-position)}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.object-cover{-o-object-fit:cover;object-fit:cover}.object-center{-o-object-position:center;object-position:center}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-24{padding-top:6rem;padding-bottom:6rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pl-10{padding-left:2.5rem}.pr-4{padding-right:1rem}.pt-6{padding-top:1.5rem}.text-center{text-align:center}.text-right{text-align:right}.font-sans{font-family:Space Grotesk,system-ui,sans-serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.text-accent-400{--tw-text-opacity: 1;color:rgb(20 255 249 / var(--tw-text-opacity, 1))}.text-green-300{--tw-text-opacity: 1;color:rgb(134 239 172 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-primary-400{--tw-text-opacity: 1;color:rgb(51 217 217 / var(--tw-text-opacity, 1))}.text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-secondary-300{--tw-text-opacity: 1;color:rgb(110 215 215 / var(--tw-text-opacity, 1))}.text-secondary-400{--tw-text-opacity: 1;color:rgb(44 185 185 / var(--tw-text-opacity, 1))}.text-text-primary{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-text-secondary{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\/50{color:#ffffff80}.text-white\/60{color:#fff9}.text-white\/70{color:#ffffffb3}.placeholder-text-secondary::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(163 163 163 / var(--tw-placeholder-opacity, 1))}.placeholder-text-secondary::placeholder{--tw-placeholder-opacity: 1;color:rgb(163 163 163 / var(--tw-placeholder-opacity, 1))}.opacity-0{opacity:0}.opacity-60{opacity:.6}.opacity-\[0\.015\]{opacity:.015}.opacity-\[0\.02\]{opacity:.02}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-primary-900\/5{--tw-shadow-color: rgb(13 71 71 / .05);--tw-shadow: var(--tw-shadow-colored)}.shadow-secondary-900\/30{--tw-shadow-color: rgb(13 63 63 / .3);--tw-shadow: var(--tw-shadow-colored)}.blur-\[100px\]{--tw-blur: blur(100px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-\[80px\]{--tw-blur: blur(80px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-sm{--tw-blur: blur(4px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-lg{--tw-backdrop-blur: blur(16px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:bg-secondary-900\/50:hover{background-color:#0d3f3f80}.hover\:bg-white\/\[0\.05\]:hover{background-color:#ffffff0d}.hover\:text-accent-400:hover{--tw-text-opacity: 1;color:rgb(20 255 249 / var(--tw-text-opacity, 1))}.hover\:text-secondary-400:hover{--tw-text-opacity: 1;color:rgb(44 185 185 / var(--tw-text-opacity, 1))}.hover\:text-text-primary:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:shadow-secondary-800\/50:hover{--tw-shadow-color: rgb(12 77 77 / .5);--tw-shadow: var(--tw-shadow-colored)}.hover\:grayscale-0:hover{--tw-grayscale: grayscale(0);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.focus\:border-transparent:focus{border-color:transparent}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-secondary-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(26 158 158 / var(--tw-ring-opacity, 1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:w-full{width:100%}.group:hover .group-hover\:translate-x-1{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:opacity-100{opacity:1}@media (min-width: 768px){.md\:col-span-1{grid-column:span 1 / span 1}.md\:flex{display:flex}.md\:hidden{display:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:p-12{padding:3rem}.md\:px-6{padding-left:1.5rem;padding-right:1.5rem}.md\:py-28{padding-top:7rem;padding-bottom:7rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}}@media (min-width: 1024px){.lg\:sticky{position:sticky}.lg\:top-24{top:6rem}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:gap-16{gap:4rem}.lg\:text-6xl{font-size:3.75rem;line-height:1}}
|
project 2/dist/assets/index-zPcAIS4j.js
ADDED
The diff for this file is too large to render.
See raw diff
|
|
project 2/dist/assets/logo.png
ADDED
![]() |
Git LFS Details
|
project 2/dist/index.html
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!doctype html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8" />
|
5 |
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7 |
+
<title>NeoCyberAcquisition | AI Automation Experts</title>
|
8 |
+
<meta name="description" content="AI and CRM integrations, AI automation, lead generation and marketing solutions for modern businesses.">
|
9 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
10 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
11 |
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
12 |
+
<script type="module" src="https://unpkg.com/@splinetool/[email protected]/build/spline-viewer.js"></script>
|
13 |
+
<script type="module" crossorigin src="/assets/index-zPcAIS4j.js"></script>
|
14 |
+
<link rel="stylesheet" crossorigin href="/assets/index-CiBv4vu0.css">
|
15 |
+
</head>
|
16 |
+
<body class="bg-background text-text-primary overflow-x-hidden">
|
17 |
+
<div id="root"></div>
|
18 |
+
</body>
|
19 |
+
</html>
|
project 2/dist/logo.png
ADDED
![]() |
project 2/eslint.config.js
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import js from '@eslint/js';
|
2 |
+
import globals from 'globals';
|
3 |
+
import reactHooks from 'eslint-plugin-react-hooks';
|
4 |
+
import reactRefresh from 'eslint-plugin-react-refresh';
|
5 |
+
import tseslint from 'typescript-eslint';
|
6 |
+
|
7 |
+
export default tseslint.config(
|
8 |
+
{ ignores: ['dist'] },
|
9 |
+
{
|
10 |
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
11 |
+
files: ['**/*.{ts,tsx}'],
|
12 |
+
languageOptions: {
|
13 |
+
ecmaVersion: 2020,
|
14 |
+
globals: globals.browser,
|
15 |
+
},
|
16 |
+
plugins: {
|
17 |
+
'react-hooks': reactHooks,
|
18 |
+
'react-refresh': reactRefresh,
|
19 |
+
},
|
20 |
+
rules: {
|
21 |
+
...reactHooks.configs.recommended.rules,
|
22 |
+
'react-refresh/only-export-components': [
|
23 |
+
'warn',
|
24 |
+
{ allowConstantExport: true },
|
25 |
+
],
|
26 |
+
},
|
27 |
+
}
|
28 |
+
);
|
project 2/index.html
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!doctype html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8" />
|
5 |
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7 |
+
<title>NeoCyberAcquisition | AI Automation Experts</title>
|
8 |
+
<meta name="description" content="AI and CRM integrations, AI automation, lead generation and marketing solutions for modern businesses.">
|
9 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
10 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
11 |
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
12 |
+
<script type="module" src="https://unpkg.com/@splinetool/[email protected]/build/spline-viewer.js"></script>
|
13 |
+
</head>
|
14 |
+
<body class="bg-background text-text-primary overflow-x-hidden">
|
15 |
+
<div id="root"></div>
|
16 |
+
<script type="module" src="/src/main.tsx"></script>
|
17 |
+
</body>
|
18 |
+
</html>
|
project 2/package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
project 2/package.json
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "neocyber-acquisition",
|
3 |
+
"private": true,
|
4 |
+
"version": "0.0.0",
|
5 |
+
"type": "module",
|
6 |
+
"scripts": {
|
7 |
+
"dev": "vite",
|
8 |
+
"build": "vite build",
|
9 |
+
"lint": "eslint .",
|
10 |
+
"preview": "vite preview"
|
11 |
+
},
|
12 |
+
"dependencies": {
|
13 |
+
"@supabase/supabase-js": "^2.39.0",
|
14 |
+
"framer-motion": "^10.18.0",
|
15 |
+
"lucide-react": "^0.344.0",
|
16 |
+
"react": "^18.3.1",
|
17 |
+
"react-countup": "^6.5.0",
|
18 |
+
"react-dom": "^18.3.1",
|
19 |
+
"react-intersection-observer": "^9.8.0",
|
20 |
+
"react-router-dom": "^6.20.1"
|
21 |
+
},
|
22 |
+
"devDependencies": {
|
23 |
+
"@eslint/js": "^9.9.1",
|
24 |
+
"@types/react": "^18.3.5",
|
25 |
+
"@types/react-dom": "^18.3.0",
|
26 |
+
"@vitejs/plugin-react": "^4.3.1",
|
27 |
+
"autoprefixer": "^10.4.18",
|
28 |
+
"eslint": "^9.9.1",
|
29 |
+
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
30 |
+
"eslint-plugin-react-refresh": "^0.4.11",
|
31 |
+
"globals": "^15.9.0",
|
32 |
+
"postcss": "^8.4.35",
|
33 |
+
"tailwindcss": "^3.4.1",
|
34 |
+
"typescript": "^5.5.3",
|
35 |
+
"typescript-eslint": "^8.3.0",
|
36 |
+
"vite": "^5.4.2"
|
37 |
+
}
|
38 |
+
}
|
project 2/postcss.config.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export default {
|
2 |
+
plugins: {
|
3 |
+
tailwindcss: {},
|
4 |
+
autoprefixer: {},
|
5 |
+
},
|
6 |
+
};
|
project 2/public/assets/WhatsApp Image 2025-06-28 at 12.51.41.jpeg
ADDED
![]() |
Git LFS Details
|
project 2/public/logo.png
ADDED
![]() |
project 2/src/App.tsx
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
3 |
+
import HomePage from './pages/HomePage';
|
4 |
+
import BookingForm from './pages/BookingForm';
|
5 |
+
|
6 |
+
function App() {
|
7 |
+
return (
|
8 |
+
<Router>
|
9 |
+
<Routes>
|
10 |
+
<Route path="/" element={<HomePage />} />
|
11 |
+
<Route path="/book-call" element={<BookingForm />} />
|
12 |
+
</Routes>
|
13 |
+
</Router>
|
14 |
+
);
|
15 |
+
}
|
16 |
+
|
17 |
+
export default App;
|
project 2/src/components/BackgroundEffects.tsx
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import { motion } from 'framer-motion';
|
3 |
+
|
4 |
+
const BackgroundEffects: React.FC = () => {
|
5 |
+
return (
|
6 |
+
<>
|
7 |
+
{/* Pure black background */}
|
8 |
+
<div className="fixed inset-0 bg-black"></div>
|
9 |
+
|
10 |
+
{/* Subtle grain texture overlay */}
|
11 |
+
<div className="fixed inset-0 bg-grain opacity-[0.015] pointer-events-none z-10"></div>
|
12 |
+
|
13 |
+
{/* Animated wave effect at the bottom */}
|
14 |
+
<div className="fixed bottom-0 left-0 right-0 h-64 pointer-events-none overflow-hidden">
|
15 |
+
<motion.div
|
16 |
+
className="absolute bottom-0 left-[-10%] right-[-10%] h-64"
|
17 |
+
style={{
|
18 |
+
backgroundImage: 'url("data:image/svg+xml,%3Csvg viewBox=\'0 0 1200 300\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath d=\'M 0 250 Q 300 150 600 200 T 1200 250 L 1200 300 L 0 300 Z\' fill=\'%23003534\' opacity=\'0.2\'/%3E%3C/svg%3E")',
|
19 |
+
backgroundRepeat: 'repeat-x',
|
20 |
+
backgroundSize: '100% 100%',
|
21 |
+
}}
|
22 |
+
animate={{
|
23 |
+
x: [0, -50],
|
24 |
+
}}
|
25 |
+
transition={{
|
26 |
+
duration: 20,
|
27 |
+
repeat: Infinity,
|
28 |
+
repeatType: "reverse",
|
29 |
+
ease: "linear",
|
30 |
+
}}
|
31 |
+
/>
|
32 |
+
<motion.div
|
33 |
+
className="absolute bottom-0 left-[-10%] right-[-10%] h-64"
|
34 |
+
style={{
|
35 |
+
backgroundImage: 'url("data:image/svg+xml,%3Csvg viewBox=\'0 0 1200 300\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath d=\'M 0 250 Q 300 200 600 250 T 1200 200 L 1200 300 L 0 300 Z\' fill=\'%23003534\' opacity=\'0.15\'/%3E%3C/svg%3E")',
|
36 |
+
backgroundRepeat: 'repeat-x',
|
37 |
+
backgroundSize: '120% 100%',
|
38 |
+
}}
|
39 |
+
animate={{
|
40 |
+
x: [-50, 0],
|
41 |
+
}}
|
42 |
+
transition={{
|
43 |
+
duration: 15,
|
44 |
+
repeat: Infinity,
|
45 |
+
repeatType: "reverse",
|
46 |
+
ease: "linear",
|
47 |
+
}}
|
48 |
+
/>
|
49 |
+
</div>
|
50 |
+
|
51 |
+
{/* Animated orbs/glows */}
|
52 |
+
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
53 |
+
{/* Subtle teal glow */}
|
54 |
+
<motion.div
|
55 |
+
className="absolute top-[20%] right-[15%] w-[400px] h-[400px] rounded-full bg-accent-900/10 filter blur-[100px]"
|
56 |
+
animate={{
|
57 |
+
opacity: [0.3, 0.5, 0.3],
|
58 |
+
scale: [1, 1.1, 1],
|
59 |
+
}}
|
60 |
+
transition={{
|
61 |
+
duration: 8,
|
62 |
+
repeat: Infinity,
|
63 |
+
repeatType: "reverse",
|
64 |
+
}}
|
65 |
+
/>
|
66 |
+
|
67 |
+
{/* Secondary teal glow */}
|
68 |
+
<motion.div
|
69 |
+
className="absolute bottom-[30%] left-[10%] w-[300px] h-[300px] rounded-full bg-primary-900/15 filter blur-[80px]"
|
70 |
+
animate={{
|
71 |
+
opacity: [0.2, 0.4, 0.2],
|
72 |
+
scale: [1, 1.15, 1],
|
73 |
+
}}
|
74 |
+
transition={{
|
75 |
+
duration: 7,
|
76 |
+
repeat: Infinity,
|
77 |
+
repeatType: "reverse",
|
78 |
+
delay: 2,
|
79 |
+
}}
|
80 |
+
/>
|
81 |
+
</div>
|
82 |
+
</>
|
83 |
+
);
|
84 |
+
};
|
85 |
+
|
86 |
+
export default BackgroundEffects;
|
project 2/src/components/ConsultationForm.tsx
ADDED
@@ -0,0 +1,240 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useState } from 'react';
|
2 |
+
import { motion } from 'framer-motion';
|
3 |
+
import { ArrowRight, CheckCircle, AlertCircle } from 'lucide-react';
|
4 |
+
import { supabase, type ConsultationForm } from '../lib/supabase';
|
5 |
+
|
6 |
+
interface FormData {
|
7 |
+
name: string;
|
8 |
+
email: string;
|
9 |
+
website: string;
|
10 |
+
company: string;
|
11 |
+
project_description: string;
|
12 |
+
}
|
13 |
+
|
14 |
+
interface FormStatus {
|
15 |
+
type: 'idle' | 'loading' | 'success' | 'error';
|
16 |
+
message?: string;
|
17 |
+
}
|
18 |
+
|
19 |
+
const ConsultationForm: React.FC = () => {
|
20 |
+
const [formData, setFormData] = useState<FormData>({
|
21 |
+
name: '',
|
22 |
+
email: '',
|
23 |
+
website: '',
|
24 |
+
company: '',
|
25 |
+
project_description: ''
|
26 |
+
});
|
27 |
+
|
28 |
+
const [status, setStatus] = useState<FormStatus>({ type: 'idle' });
|
29 |
+
|
30 |
+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
31 |
+
const { name, value } = e.target;
|
32 |
+
setFormData(prev => ({
|
33 |
+
...prev,
|
34 |
+
[name]: value
|
35 |
+
}));
|
36 |
+
};
|
37 |
+
|
38 |
+
const handleSubmit = async (e: React.FormEvent) => {
|
39 |
+
e.preventDefault();
|
40 |
+
|
41 |
+
// Validate required fields
|
42 |
+
if (!formData.name.trim() || !formData.email.trim()) {
|
43 |
+
setStatus({
|
44 |
+
type: 'error',
|
45 |
+
message: 'Please fill in all required fields.'
|
46 |
+
});
|
47 |
+
return;
|
48 |
+
}
|
49 |
+
|
50 |
+
// Validate email format
|
51 |
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
52 |
+
if (!emailRegex.test(formData.email)) {
|
53 |
+
setStatus({
|
54 |
+
type: 'error',
|
55 |
+
message: 'Please enter a valid email address.'
|
56 |
+
});
|
57 |
+
return;
|
58 |
+
}
|
59 |
+
|
60 |
+
setStatus({ type: 'loading' });
|
61 |
+
|
62 |
+
try {
|
63 |
+
const consultationData: Omit<ConsultationForm, 'id' | 'created_at'> = {
|
64 |
+
name: formData.name.trim(),
|
65 |
+
email: formData.email.trim(),
|
66 |
+
website: formData.website.trim() || null,
|
67 |
+
company: formData.company.trim() || null,
|
68 |
+
project_description: formData.project_description.trim() || null
|
69 |
+
};
|
70 |
+
|
71 |
+
const { error } = await supabase
|
72 |
+
.from('consultation_forms')
|
73 |
+
.insert([consultationData]);
|
74 |
+
|
75 |
+
if (error) {
|
76 |
+
throw error;
|
77 |
+
}
|
78 |
+
|
79 |
+
setStatus({
|
80 |
+
type: 'success',
|
81 |
+
message: 'Thank you! Your consultation request has been submitted successfully. We\'ll get back to you soon.'
|
82 |
+
});
|
83 |
+
|
84 |
+
// Reset form
|
85 |
+
setFormData({
|
86 |
+
name: '',
|
87 |
+
email: '',
|
88 |
+
website: '',
|
89 |
+
company: '',
|
90 |
+
project_description: ''
|
91 |
+
});
|
92 |
+
|
93 |
+
} catch (error) {
|
94 |
+
console.error('Error submitting consultation request:', error);
|
95 |
+
setStatus({
|
96 |
+
type: 'error',
|
97 |
+
message: 'Sorry, there was an error submitting your request. Please try again.'
|
98 |
+
});
|
99 |
+
}
|
100 |
+
};
|
101 |
+
|
102 |
+
return (
|
103 |
+
<div className="bg-background-light rounded-2xl p-8 md:p-12 border border-secondary-800/30 shadow-xl relative overflow-hidden">
|
104 |
+
{/* Animated gradient */}
|
105 |
+
<div className="absolute inset-0 bg-gradient-to-br from-secondary-900/20 via-accent-900/10 to-primary-900/20 opacity-60"></div>
|
106 |
+
|
107 |
+
<div className="relative z-10">
|
108 |
+
<h3 className="text-2xl font-semibold mb-6 text-center">Get Your Personalized AI Strategy Now</h3>
|
109 |
+
|
110 |
+
<p className="text-text-secondary mb-8 text-center">
|
111 |
+
Our team will analyze your business needs and create a custom AI implementation plan tailored to your goals.
|
112 |
+
</p>
|
113 |
+
|
114 |
+
{/* Status Messages */}
|
115 |
+
{status.type === 'success' && (
|
116 |
+
<motion.div
|
117 |
+
initial={{ opacity: 0, y: -10 }}
|
118 |
+
animate={{ opacity: 1, y: 0 }}
|
119 |
+
className="mb-6 p-4 bg-green-900/20 border border-green-500/30 rounded-lg flex items-center"
|
120 |
+
>
|
121 |
+
<CheckCircle className="text-green-400 mr-3 flex-shrink-0" size={20} />
|
122 |
+
<p className="text-green-300 text-sm">{status.message}</p>
|
123 |
+
</motion.div>
|
124 |
+
)}
|
125 |
+
|
126 |
+
{status.type === 'error' && (
|
127 |
+
<motion.div
|
128 |
+
initial={{ opacity: 0, y: -10 }}
|
129 |
+
animate={{ opacity: 1, y: 0 }}
|
130 |
+
className="mb-6 p-4 bg-red-900/20 border border-red-500/30 rounded-lg flex items-center"
|
131 |
+
>
|
132 |
+
<AlertCircle className="text-red-400 mr-3 flex-shrink-0" size={20} />
|
133 |
+
<p className="text-red-300 text-sm">{status.message}</p>
|
134 |
+
</motion.div>
|
135 |
+
)}
|
136 |
+
|
137 |
+
<form onSubmit={handleSubmit} className="space-y-6">
|
138 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
139 |
+
<div>
|
140 |
+
<label htmlFor="name" className="block text-sm font-medium text-text-primary mb-2">
|
141 |
+
Full Name *
|
142 |
+
</label>
|
143 |
+
<input
|
144 |
+
type="text"
|
145 |
+
id="name"
|
146 |
+
name="name"
|
147 |
+
value={formData.name}
|
148 |
+
onChange={handleInputChange}
|
149 |
+
required
|
150 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary"
|
151 |
+
placeholder="Enter your full name"
|
152 |
+
/>
|
153 |
+
</div>
|
154 |
+
|
155 |
+
<div>
|
156 |
+
<label htmlFor="email" className="block text-sm font-medium text-text-primary mb-2">
|
157 |
+
Email Address *
|
158 |
+
</label>
|
159 |
+
<input
|
160 |
+
type="email"
|
161 |
+
id="email"
|
162 |
+
name="email"
|
163 |
+
value={formData.email}
|
164 |
+
onChange={handleInputChange}
|
165 |
+
required
|
166 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary"
|
167 |
+
placeholder="Enter your email address"
|
168 |
+
/>
|
169 |
+
</div>
|
170 |
+
</div>
|
171 |
+
|
172 |
+
<div>
|
173 |
+
<label htmlFor="website" className="block text-sm font-medium text-text-primary mb-2">
|
174 |
+
Website
|
175 |
+
</label>
|
176 |
+
<input
|
177 |
+
type="url"
|
178 |
+
id="website"
|
179 |
+
name="website"
|
180 |
+
value={formData.website}
|
181 |
+
onChange={handleInputChange}
|
182 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary"
|
183 |
+
placeholder="Enter your website link"
|
184 |
+
/>
|
185 |
+
</div>
|
186 |
+
|
187 |
+
<div>
|
188 |
+
<label htmlFor="company" className="block text-sm font-medium text-text-primary mb-2">
|
189 |
+
Company Name
|
190 |
+
</label>
|
191 |
+
<input
|
192 |
+
type="text"
|
193 |
+
id="company"
|
194 |
+
name="company"
|
195 |
+
value={formData.company}
|
196 |
+
onChange={handleInputChange}
|
197 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary"
|
198 |
+
placeholder="Enter your company name (optional)"
|
199 |
+
/>
|
200 |
+
</div>
|
201 |
+
|
202 |
+
<div>
|
203 |
+
<label htmlFor="project_description" className="block text-sm font-medium text-text-primary mb-2">
|
204 |
+
Tell us about your project
|
205 |
+
</label>
|
206 |
+
<textarea
|
207 |
+
id="project_description"
|
208 |
+
name="project_description"
|
209 |
+
value={formData.project_description}
|
210 |
+
onChange={handleInputChange}
|
211 |
+
rows={4}
|
212 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary resize-vertical"
|
213 |
+
placeholder="Describe your business needs and roadblocks"
|
214 |
+
/>
|
215 |
+
</div>
|
216 |
+
|
217 |
+
<motion.button
|
218 |
+
type="submit"
|
219 |
+
disabled={status.type === 'loading'}
|
220 |
+
className="group relative w-full inline-flex items-center justify-center px-8 py-4 text-lg font-medium text-white bg-gradient-to-r from-secondary-600 to-accent-700 rounded-lg overflow-hidden transition-all duration-300 shadow-lg shadow-secondary-900/30 hover:shadow-secondary-800/50 disabled:opacity-50 disabled:cursor-not-allowed"
|
221 |
+
whileHover={{ scale: status.type === 'loading' ? 1 : 1.02 }}
|
222 |
+
whileTap={{ scale: status.type === 'loading' ? 1 : 0.98 }}
|
223 |
+
>
|
224 |
+
<span className="relative z-10 flex items-center">
|
225 |
+
<span>
|
226 |
+
{status.type === 'loading' ? 'Submitting...' : 'Get Your AI Roadmap Now '}
|
227 |
+
</span>
|
228 |
+
{status.type !== 'loading' && (
|
229 |
+
<ArrowRight className="ml-2 transition-transform duration-300 group-hover:translate-x-1" size={20} />
|
230 |
+
)}
|
231 |
+
</span>
|
232 |
+
<span className="absolute inset-0 bg-gradient-to-r from-secondary-500 to-accent-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
|
233 |
+
</motion.button>
|
234 |
+
</form>
|
235 |
+
</div>
|
236 |
+
</div>
|
237 |
+
);
|
238 |
+
};
|
239 |
+
|
240 |
+
export default ConsultationForm;
|
project 2/src/components/Footer.tsx
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import { Mail } from 'lucide-react';
|
3 |
+
|
4 |
+
const Footer: React.FC = () => {
|
5 |
+
return (
|
6 |
+
<footer className="bg-background-dark py-12 border-t border-secondary-900/20 relative">
|
7 |
+
<div className="container mx-auto px-4 md:px-6">
|
8 |
+
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
|
9 |
+
{/* Logo and company info */}
|
10 |
+
<div className="col-span-1 md:col-span-1">
|
11 |
+
<div className="flex items-center mb-4">
|
12 |
+
<img src="/assets/logo.png" alt="Logo" className="w-8 h-8 mr-2" />
|
13 |
+
<span className="text-xl font-semibold">
|
14 |
+
NeoCyber<span className="bg-gradient-to-r from-accent-500 to-secondary-900 bg-clip-text text-transparent">
|
15 |
+
Acquisition
|
16 |
+
</span>
|
17 |
+
</span>
|
18 |
+
</div>
|
19 |
+
<p className="text-text-secondary text-sm mb-6">
|
20 |
+
Transforming businesses with cutting-edge AI automation and integration solutions.
|
21 |
+
</p>
|
22 |
+
</div>
|
23 |
+
|
24 |
+
{/* Quick links */}
|
25 |
+
<div className="col-span-1">
|
26 |
+
<h3 className="text-text-primary font-medium mb-4">Quick Links</h3>
|
27 |
+
<ul className="space-y-2">
|
28 |
+
{['Home', 'Features', 'Results', 'Contact'].map((item) => (
|
29 |
+
<li key={item}>
|
30 |
+
<a
|
31 |
+
href={`#${item.toLowerCase()}`}
|
32 |
+
className="text-text-secondary hover:text-accent-400 transition-colors text-sm"
|
33 |
+
>
|
34 |
+
{item}
|
35 |
+
</a>
|
36 |
+
</li>
|
37 |
+
))}
|
38 |
+
</ul>
|
39 |
+
</div>
|
40 |
+
|
41 |
+
{/* Contact info */}
|
42 |
+
<div className="col-span-1">
|
43 |
+
<h3 className="text-text-primary font-medium mb-4">Contact</h3>
|
44 |
+
<ul className="space-y-3">
|
45 |
+
<li className="flex items-start">
|
46 |
+
<span className="text-text-secondary text-sm">
|
47 |
+
</span>
|
48 |
+
</li>
|
49 |
+
<li className="flex items-center">
|
50 |
+
<Mail size={18} className="text-secondary-400 mr-2 flex-shrink-0" />
|
51 |
+
<a href="mailto:[email protected]" className="text-text-secondary hover:text-accent-400 transition-colors text-sm">
|
52 | |
53 |
+
</a>
|
54 |
+
</li>
|
55 |
+
<li className="flex items-center">
|
56 |
+
<a href="tel:+1234567890" className="text-text-secondary hover:text-accent-400 transition-colors text-sm">
|
57 |
+
</a>
|
58 |
+
</li>
|
59 |
+
</ul>
|
60 |
+
</div>
|
61 |
+
|
62 |
+
{/* Social links */}
|
63 |
+
<div className="col-span-1">
|
64 |
+
<h3 className="text-text-primary font-medium mb-4">Connect</h3>
|
65 |
+
<div className="flex space-x-4">
|
66 |
+
{[
|
67 |
+
{ icon: <span className="text-lg">𝕏</span>, href: "https://x.com/Damian_Bobica" },
|
68 |
+
{ icon: "in", href: "https://www.linkedin.com/in/damian-bobica-a49653335/" },
|
69 |
+
{ icon: "IG", href: "https://www.instagram.com/damianbobica/" },
|
70 |
+
].map((social, index) => (
|
71 |
+
<a
|
72 |
+
key={index}
|
73 |
+
href={social.href}
|
74 |
+
className="bg-background-light hover:bg-secondary-900/50 transition-colors p-2 rounded-full text-text-secondary hover:text-secondary-400"
|
75 |
+
>
|
76 |
+
{social.icon}
|
77 |
+
</a>
|
78 |
+
))}
|
79 |
+
</div>
|
80 |
+
</div>
|
81 |
+
</div>
|
82 |
+
|
83 |
+
<div className="border-t border-secondary-900/20 mt-12 pt-6 text-center text-text-secondary text-sm">
|
84 |
+
<p>© {new Date().getFullYear()} NeoCyberAcquisition. All rights reserved.</p>
|
85 |
+
</div>
|
86 |
+
</div>
|
87 |
+
</footer>
|
88 |
+
);
|
89 |
+
};
|
90 |
+
|
91 |
+
export default Footer;
|
project 2/src/components/Navbar.tsx
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useEffect, useState } from 'react';
|
2 |
+
import { motion } from 'framer-motion';
|
3 |
+
import { Menu, X } from 'lucide-react';
|
4 |
+
import { useNavigate } from 'react-router-dom';
|
5 |
+
|
6 |
+
const Navbar: React.FC = () => {
|
7 |
+
const [isScrolled, setIsScrolled] = useState(false);
|
8 |
+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
9 |
+
const [gradientPos, setGradientPos] = useState({ x: '50%', y: '50%' });
|
10 |
+
const navigate = useNavigate();
|
11 |
+
|
12 |
+
useEffect(() => {
|
13 |
+
const handleScroll = () => {
|
14 |
+
setIsScrolled(window.scrollY > 20);
|
15 |
+
};
|
16 |
+
|
17 |
+
window.addEventListener('scroll', handleScroll);
|
18 |
+
return () => window.removeEventListener('scroll', handleScroll);
|
19 |
+
}, []);
|
20 |
+
|
21 |
+
const scrollToContact = () => {
|
22 |
+
const contactSection = document.getElementById('contact');
|
23 |
+
if (contactSection) {
|
24 |
+
contactSection.scrollIntoView({ behavior: 'smooth' });
|
25 |
+
}
|
26 |
+
};
|
27 |
+
|
28 |
+
const handleBookCall = () => {
|
29 |
+
navigate('/book-call');
|
30 |
+
};
|
31 |
+
|
32 |
+
// Handle both mouse and touch movement for button hover effect
|
33 |
+
const handleMove = (clientX: number, clientY: number, target: HTMLElement) => {
|
34 |
+
const rect = target.getBoundingClientRect();
|
35 |
+
const x = ((clientX - rect.left) / rect.width) * 100;
|
36 |
+
const y = ((clientY - rect.top) / rect.height) * 100;
|
37 |
+
setGradientPos({ x: `${x}%`, y: `${y}%` });
|
38 |
+
};
|
39 |
+
|
40 |
+
const navbarClasses = `fixed top-0 w-full z-50 transition-all duration-300 ${
|
41 |
+
isScrolled ? 'bg-background/80 backdrop-blur-lg py-3 shadow-lg' : 'bg-transparent py-5'
|
42 |
+
}`;
|
43 |
+
|
44 |
+
return (
|
45 |
+
<nav className={navbarClasses}>
|
46 |
+
<div className="container mx-auto px-4 md:px-6">
|
47 |
+
<div className="flex justify-between items-center">
|
48 |
+
{/* Logo */}
|
49 |
+
<motion.div
|
50 |
+
initial={{ opacity: 0, x: -20 }}
|
51 |
+
animate={{ opacity: 1, x: 0 }}
|
52 |
+
transition={{ duration: 0.5 }}
|
53 |
+
className="flex items-center cursor-pointer"
|
54 |
+
onClick={() => navigate('/')}
|
55 |
+
>
|
56 |
+
<img src="/assets/logo.png" alt="Logo" className="w-8 h-8 mr-2" />
|
57 |
+
<span className="text-xl font-semibold tracking-tight">
|
58 |
+
NeoCyber<span className="bg-gradient-to-r from-accent-500 to-secondary-900 bg-clip-text text-transparent">
|
59 |
+
Acquisition
|
60 |
+
</span>
|
61 |
+
</span>
|
62 |
+
</motion.div>
|
63 |
+
|
64 |
+
{/* Desktop Navigation */}
|
65 |
+
<motion.div
|
66 |
+
initial={{ opacity: 0, y: -10 }}
|
67 |
+
animate={{ opacity: 1, y: 0 }}
|
68 |
+
transition={{ duration: 0.5, delay: 0.1 }}
|
69 |
+
className="hidden md:flex items-center space-x-8"
|
70 |
+
>
|
71 |
+
{['Features', 'Results', 'Contact'].map((item, index) => (
|
72 |
+
<a
|
73 |
+
key={item}
|
74 |
+
href={`#${item.toLowerCase()}`}
|
75 |
+
className="text-text-secondary hover:text-text-primary transition-colors relative group"
|
76 |
+
>
|
77 |
+
{item}
|
78 |
+
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-secondary-500 transition-all duration-300 group-hover:w-full"></span>
|
79 |
+
</a>
|
80 |
+
))}
|
81 |
+
|
82 |
+
{/* Book a Call Button */}
|
83 |
+
<div
|
84 |
+
onMouseMove={(e) => handleMove(e.clientX, e.clientY, e.currentTarget as HTMLElement)}
|
85 |
+
onTouchMove={(e) => {
|
86 |
+
const touch = e.touches[0];
|
87 |
+
if (touch) handleMove(touch.clientX, touch.clientY, e.currentTarget as HTMLElement);
|
88 |
+
}}
|
89 |
+
>
|
90 |
+
<button
|
91 |
+
onClick={handleBookCall}
|
92 |
+
className="relative overflow-hidden text-white font-semibold py-2 px-6 rounded-md shadow-lg transition-all duration-300 ease-out ml-4"
|
93 |
+
style={{
|
94 |
+
background: `linear-gradient(135deg, #003234, #00AAAE)`,
|
95 |
+
}}
|
96 |
+
>
|
97 |
+
Book a Call
|
98 |
+
<span
|
99 |
+
className="absolute inset-0 pointer-events-none transition-all duration-300 ease-out"
|
100 |
+
style={{
|
101 |
+
background: `radial-gradient(circle at ${gradientPos.x} ${gradientPos.y}, rgba(32,201,151,0.5) 10%, transparent 40%)`,
|
102 |
+
opacity: 1,
|
103 |
+
}}
|
104 |
+
></span>
|
105 |
+
</button>
|
106 |
+
</div>
|
107 |
+
</motion.div>
|
108 |
+
|
109 |
+
{/* Mobile Menu Button */}
|
110 |
+
<div className="md:hidden">
|
111 |
+
<button
|
112 |
+
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
113 |
+
className="text-text-primary p-2"
|
114 |
+
>
|
115 |
+
{mobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
|
116 |
+
</button>
|
117 |
+
</div>
|
118 |
+
</div>
|
119 |
+
</div>
|
120 |
+
|
121 |
+
{/* Mobile Menu */}
|
122 |
+
{mobileMenuOpen && (
|
123 |
+
<motion.div
|
124 |
+
initial={{ opacity: 0, height: 0 }}
|
125 |
+
animate={{ opacity: 1, height: 'auto' }}
|
126 |
+
exit={{ opacity: 0, height: 0 }}
|
127 |
+
transition={{ duration: 0.3 }}
|
128 |
+
className="md:hidden bg-background/95 backdrop-blur-lg mt-2 p-4"
|
129 |
+
>
|
130 |
+
<div className="flex flex-col space-y-4">
|
131 |
+
{['Features', 'Results', 'Contact'].map((item) => (
|
132 |
+
<a
|
133 |
+
key={item}
|
134 |
+
href={`#${item.toLowerCase()}`}
|
135 |
+
className="text-text-secondary py-2 hover:text-text-primary transition-colors"
|
136 |
+
onClick={() => setMobileMenuOpen(false)}
|
137 |
+
>
|
138 |
+
{item}
|
139 |
+
</a>
|
140 |
+
))}
|
141 |
+
|
142 |
+
{/* Mobile Book a Call Button */}
|
143 |
+
<button
|
144 |
+
onClick={() => {
|
145 |
+
handleBookCall();
|
146 |
+
setMobileMenuOpen(false);
|
147 |
+
}}
|
148 |
+
className="relative overflow-hidden text-white font-semibold py-3 px-6 rounded-md shadow-lg transition-all duration-300 ease-out mt-4"
|
149 |
+
style={{
|
150 |
+
background: `linear-gradient(135deg, #003234, #00AAAE)`,
|
151 |
+
}}
|
152 |
+
>
|
153 |
+
Book a Call
|
154 |
+
</button>
|
155 |
+
</div>
|
156 |
+
</motion.div>
|
157 |
+
)}
|
158 |
+
</nav>
|
159 |
+
);
|
160 |
+
};
|
161 |
+
|
162 |
+
export default Navbar;
|
project 2/src/index.css
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
@tailwind base;
|
2 |
+
@tailwind components;
|
3 |
+
@tailwind utilities;
|
project 2/src/lib/supabase.ts
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { createClient } from '@supabase/supabase-js';
|
2 |
+
|
3 |
+
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
|
4 |
+
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
|
5 |
+
|
6 |
+
if (!supabaseUrl || !supabaseAnonKey) {
|
7 |
+
throw new Error('Missing Supabase environment variables');
|
8 |
+
}
|
9 |
+
|
10 |
+
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
|
11 |
+
|
12 |
+
export type ConsultationRequest = {
|
13 |
+
id?: string;
|
14 |
+
name: string;
|
15 |
+
email: string;
|
16 |
+
company?: string;
|
17 |
+
message?: string;
|
18 |
+
created_at?: string;
|
19 |
+
};
|
20 |
+
|
21 |
+
export type ConsultationForm = {
|
22 |
+
id?: string;
|
23 |
+
name: string;
|
24 |
+
email: string;
|
25 |
+
website?: string;
|
26 |
+
company?: string;
|
27 |
+
project_description?: string;
|
28 |
+
created_at?: string;
|
29 |
+
};
|
project 2/src/main.tsx
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { StrictMode } from 'react';
|
2 |
+
import { createRoot } from 'react-dom/client';
|
3 |
+
import App from './App.tsx';
|
4 |
+
import './index.css';
|
5 |
+
|
6 |
+
createRoot(document.getElementById('root')!).render(
|
7 |
+
<StrictMode>
|
8 |
+
<App />
|
9 |
+
</StrictMode>
|
10 |
+
);
|
project 2/src/pages/BookingForm.tsx
ADDED
@@ -0,0 +1,429 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useState } from 'react';
|
2 |
+
import { motion } from 'framer-motion';
|
3 |
+
import { ArrowLeft, CheckCircle, AlertCircle, Phone, Mail, Building, User, MessageSquare, FileText } from 'lucide-react';
|
4 |
+
import { supabase } from '../lib/supabase';
|
5 |
+
|
6 |
+
interface FormData {
|
7 |
+
name: string;
|
8 |
+
email: string;
|
9 |
+
phone: string;
|
10 |
+
company: string;
|
11 |
+
problems: string;
|
12 |
+
additionalInfo: string;
|
13 |
+
}
|
14 |
+
|
15 |
+
interface FormStatus {
|
16 |
+
type: 'idle' | 'loading' | 'success' | 'error';
|
17 |
+
message?: string;
|
18 |
+
}
|
19 |
+
|
20 |
+
const BookingForm: React.FC = () => {
|
21 |
+
const [formData, setFormData] = useState<FormData>({
|
22 |
+
name: '',
|
23 |
+
email: '',
|
24 |
+
phone: '',
|
25 |
+
company: '',
|
26 |
+
problems: '',
|
27 |
+
additionalInfo: ''
|
28 |
+
});
|
29 |
+
|
30 |
+
const [status, setStatus] = useState<FormStatus>({ type: 'idle' });
|
31 |
+
|
32 |
+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
33 |
+
const { name, value } = e.target;
|
34 |
+
setFormData(prev => ({
|
35 |
+
...prev,
|
36 |
+
[name]: value
|
37 |
+
}));
|
38 |
+
};
|
39 |
+
|
40 |
+
const handleSubmit = async (e: React.FormEvent) => {
|
41 |
+
e.preventDefault();
|
42 |
+
|
43 |
+
// Validate required fields
|
44 |
+
const requiredFields = ['name', 'email', 'phone', 'company', 'problems'];
|
45 |
+
const missingFields = requiredFields.filter(field => !formData[field as keyof FormData].trim());
|
46 |
+
|
47 |
+
if (missingFields.length > 0) {
|
48 |
+
setStatus({
|
49 |
+
type: 'error',
|
50 |
+
message: 'Please fill in all required fields.'
|
51 |
+
});
|
52 |
+
return;
|
53 |
+
}
|
54 |
+
|
55 |
+
// Validate email format
|
56 |
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
57 |
+
if (!emailRegex.test(formData.email)) {
|
58 |
+
setStatus({
|
59 |
+
type: 'error',
|
60 |
+
message: 'Please enter a valid email address.'
|
61 |
+
});
|
62 |
+
return;
|
63 |
+
}
|
64 |
+
|
65 |
+
// Validate phone format (basic validation)
|
66 |
+
const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/;
|
67 |
+
if (!phoneRegex.test(formData.phone.replace(/[\s\-\(\)]/g, ''))) {
|
68 |
+
setStatus({
|
69 |
+
type: 'error',
|
70 |
+
message: 'Please enter a valid phone number.'
|
71 |
+
});
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
|
75 |
+
setStatus({ type: 'loading' });
|
76 |
+
|
77 |
+
try {
|
78 |
+
// Create a comprehensive message for the consultation
|
79 |
+
const consultationMessage = `
|
80 |
+
BOOKING FORM SUBMISSION:
|
81 |
+
|
82 |
+
Phone: ${formData.phone}
|
83 |
+
Company: ${formData.company}
|
84 |
+
Problems to solve: ${formData.problems}
|
85 |
+
${formData.additionalInfo ? `Additional information: ${formData.additionalInfo}` : ''}
|
86 |
+
`.trim();
|
87 |
+
|
88 |
+
const consultationData = {
|
89 |
+
name: formData.name.trim(),
|
90 |
+
email: formData.email.trim(),
|
91 |
+
company: formData.company.trim(),
|
92 |
+
message: consultationMessage
|
93 |
+
};
|
94 |
+
|
95 |
+
const { error } = await supabase
|
96 |
+
.from('consultations')
|
97 |
+
.insert([consultationData]);
|
98 |
+
|
99 |
+
if (error) {
|
100 |
+
throw error;
|
101 |
+
}
|
102 |
+
|
103 |
+
setStatus({
|
104 |
+
type: 'success',
|
105 |
+
message: 'Thank you! Your booking request has been submitted successfully. We\'ll contact you within 24 hours to schedule your consultation.'
|
106 |
+
});
|
107 |
+
|
108 |
+
// Reset form
|
109 |
+
setFormData({
|
110 |
+
name: '',
|
111 |
+
email: '',
|
112 |
+
phone: '',
|
113 |
+
company: '',
|
114 |
+
problems: '',
|
115 |
+
additionalInfo: ''
|
116 |
+
});
|
117 |
+
|
118 |
+
} catch (error) {
|
119 |
+
console.error('Error submitting booking request:', error);
|
120 |
+
setStatus({
|
121 |
+
type: 'error',
|
122 |
+
message: 'Sorry, there was an error submitting your request. Please try again.'
|
123 |
+
});
|
124 |
+
}
|
125 |
+
};
|
126 |
+
|
127 |
+
const goBack = () => {
|
128 |
+
window.history.back();
|
129 |
+
};
|
130 |
+
|
131 |
+
return (
|
132 |
+
<div className="min-h-screen bg-background relative overflow-hidden">
|
133 |
+
{/* Background Effects */}
|
134 |
+
<div className="fixed inset-0 bg-black"></div>
|
135 |
+
<div className="fixed inset-0 bg-grain opacity-[0.015] pointer-events-none z-10"></div>
|
136 |
+
|
137 |
+
{/* Animated orbs */}
|
138 |
+
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
139 |
+
<motion.div
|
140 |
+
className="absolute top-[20%] right-[15%] w-[400px] h-[400px] rounded-full bg-accent-900/10 filter blur-[100px]"
|
141 |
+
animate={{
|
142 |
+
opacity: [0.3, 0.5, 0.3],
|
143 |
+
scale: [1, 1.1, 1],
|
144 |
+
}}
|
145 |
+
transition={{
|
146 |
+
duration: 8,
|
147 |
+
repeat: Infinity,
|
148 |
+
repeatType: "reverse",
|
149 |
+
}}
|
150 |
+
/>
|
151 |
+
<motion.div
|
152 |
+
className="absolute bottom-[30%] left-[10%] w-[300px] h-[300px] rounded-full bg-primary-900/15 filter blur-[80px]"
|
153 |
+
animate={{
|
154 |
+
opacity: [0.2, 0.4, 0.2],
|
155 |
+
scale: [1, 1.15, 1],
|
156 |
+
}}
|
157 |
+
transition={{
|
158 |
+
duration: 7,
|
159 |
+
repeat: Infinity,
|
160 |
+
repeatType: "reverse",
|
161 |
+
delay: 2,
|
162 |
+
}}
|
163 |
+
/>
|
164 |
+
</div>
|
165 |
+
|
166 |
+
<div className="relative z-20 container mx-auto px-4 py-8">
|
167 |
+
{/* Header */}
|
168 |
+
<motion.div
|
169 |
+
initial={{ opacity: 0, y: -20 }}
|
170 |
+
animate={{ opacity: 1, y: 0 }}
|
171 |
+
transition={{ duration: 0.6 }}
|
172 |
+
className="flex items-center mb-8"
|
173 |
+
>
|
174 |
+
<button
|
175 |
+
onClick={goBack}
|
176 |
+
className="flex items-center text-text-secondary hover:text-text-primary transition-colors mr-6"
|
177 |
+
>
|
178 |
+
<ArrowLeft size={20} className="mr-2" />
|
179 |
+
Back to Home
|
180 |
+
</button>
|
181 |
+
|
182 |
+
<div className="flex items-center">
|
183 |
+
<img src="/assets/logo.png" alt="Logo" className="w-8 h-8 mr-2" />
|
184 |
+
<span className="text-xl font-semibold tracking-tight">
|
185 |
+
NeoCyber<span className="bg-gradient-to-r from-accent-500 to-secondary-900 bg-clip-text text-transparent">
|
186 |
+
Acquisition
|
187 |
+
</span>
|
188 |
+
</span>
|
189 |
+
</div>
|
190 |
+
</motion.div>
|
191 |
+
|
192 |
+
{/* Main Form */}
|
193 |
+
<div className="max-w-4xl mx-auto">
|
194 |
+
<motion.div
|
195 |
+
initial={{ opacity: 0, y: 30 }}
|
196 |
+
animate={{ opacity: 1, y: 0 }}
|
197 |
+
transition={{ duration: 0.6, delay: 0.2 }}
|
198 |
+
className="text-center mb-12"
|
199 |
+
>
|
200 |
+
<h1 className="text-4xl md:text-5xl font-bold mb-4">Book Your AI Strategy Call</h1>
|
201 |
+
<p className="text-text-secondary text-lg max-w-2xl mx-auto">
|
202 |
+
Let's discuss how AI automation can transform your business. Fill out the form below and we'll schedule a personalized consultation.
|
203 |
+
</p>
|
204 |
+
</motion.div>
|
205 |
+
|
206 |
+
<motion.div
|
207 |
+
initial={{ opacity: 0, y: 40 }}
|
208 |
+
animate={{ opacity: 1, y: 0 }}
|
209 |
+
transition={{ duration: 0.6, delay: 0.4 }}
|
210 |
+
className="bg-background-light rounded-2xl p-8 md:p-12 border border-secondary-800/30 shadow-xl relative overflow-hidden"
|
211 |
+
>
|
212 |
+
{/* Animated gradient */}
|
213 |
+
<div className="absolute inset-0 bg-gradient-to-br from-secondary-900/20 via-accent-900/10 to-primary-900/20 opacity-60"></div>
|
214 |
+
|
215 |
+
<div className="relative z-10">
|
216 |
+
{/* Status Messages */}
|
217 |
+
{status.type === 'success' && (
|
218 |
+
<motion.div
|
219 |
+
initial={{ opacity: 0, y: -10 }}
|
220 |
+
animate={{ opacity: 1, y: 0 }}
|
221 |
+
className="mb-8 p-6 bg-green-900/20 border border-green-500/30 rounded-lg flex items-start"
|
222 |
+
>
|
223 |
+
<CheckCircle className="text-green-400 mr-3 flex-shrink-0 mt-1" size={24} />
|
224 |
+
<div>
|
225 |
+
<h3 className="text-green-300 font-semibold mb-2">Booking Request Submitted!</h3>
|
226 |
+
<p className="text-green-300 text-sm">{status.message}</p>
|
227 |
+
</div>
|
228 |
+
</motion.div>
|
229 |
+
)}
|
230 |
+
|
231 |
+
{status.type === 'error' && (
|
232 |
+
<motion.div
|
233 |
+
initial={{ opacity: 0, y: -10 }}
|
234 |
+
animate={{ opacity: 1, y: 0 }}
|
235 |
+
className="mb-8 p-6 bg-red-900/20 border border-red-500/30 rounded-lg flex items-start"
|
236 |
+
>
|
237 |
+
<AlertCircle className="text-red-400 mr-3 flex-shrink-0 mt-1" size={24} />
|
238 |
+
<div>
|
239 |
+
<h3 className="text-red-300 font-semibold mb-2">Error</h3>
|
240 |
+
<p className="text-red-300 text-sm">{status.message}</p>
|
241 |
+
</div>
|
242 |
+
</motion.div>
|
243 |
+
)}
|
244 |
+
|
245 |
+
<form onSubmit={handleSubmit} className="space-y-8">
|
246 |
+
{/* Personal Information */}
|
247 |
+
<div>
|
248 |
+
<h3 className="text-xl font-semibold mb-6 flex items-center">
|
249 |
+
<User className="mr-3 text-secondary-400" size={24} />
|
250 |
+
Personal Information
|
251 |
+
</h3>
|
252 |
+
|
253 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
254 |
+
<div>
|
255 |
+
<label htmlFor="name" className="block text-sm font-medium text-text-primary mb-2">
|
256 |
+
Full Name *
|
257 |
+
</label>
|
258 |
+
<input
|
259 |
+
type="text"
|
260 |
+
id="name"
|
261 |
+
name="name"
|
262 |
+
value={formData.name}
|
263 |
+
onChange={handleInputChange}
|
264 |
+
required
|
265 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary"
|
266 |
+
placeholder="Enter your full name"
|
267 |
+
/>
|
268 |
+
</div>
|
269 |
+
|
270 |
+
<div>
|
271 |
+
<label htmlFor="email" className="block text-sm font-medium text-text-primary mb-2">
|
272 |
+
Email Address *
|
273 |
+
</label>
|
274 |
+
<div className="relative">
|
275 |
+
<Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 text-text-secondary" size={18} />
|
276 |
+
<input
|
277 |
+
type="email"
|
278 |
+
id="email"
|
279 |
+
name="email"
|
280 |
+
value={formData.email}
|
281 |
+
onChange={handleInputChange}
|
282 |
+
required
|
283 |
+
className="w-full pl-10 pr-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary"
|
284 |
+
placeholder="Enter your email address"
|
285 |
+
/>
|
286 |
+
</div>
|
287 |
+
</div>
|
288 |
+
</div>
|
289 |
+
</div>
|
290 |
+
|
291 |
+
{/* Contact & Company Information */}
|
292 |
+
<div>
|
293 |
+
<h3 className="text-xl font-semibold mb-6 flex items-center">
|
294 |
+
<Building className="mr-3 text-secondary-400" size={24} />
|
295 |
+
Contact & Company Information
|
296 |
+
</h3>
|
297 |
+
|
298 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
299 |
+
<div>
|
300 |
+
<label htmlFor="phone" className="block text-sm font-medium text-text-primary mb-2">
|
301 |
+
Phone Number *
|
302 |
+
</label>
|
303 |
+
<div className="relative">
|
304 |
+
<Phone className="absolute left-3 top-1/2 transform -translate-y-1/2 text-text-secondary" size={18} />
|
305 |
+
<input
|
306 |
+
type="tel"
|
307 |
+
id="phone"
|
308 |
+
name="phone"
|
309 |
+
value={formData.phone}
|
310 |
+
onChange={handleInputChange}
|
311 |
+
required
|
312 |
+
className="w-full pl-10 pr-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary"
|
313 |
+
placeholder="Enter your phone number"
|
314 |
+
/>
|
315 |
+
</div>
|
316 |
+
</div>
|
317 |
+
|
318 |
+
<div>
|
319 |
+
<label htmlFor="company" className="block text-sm font-medium text-text-primary mb-2">
|
320 |
+
Company Name *
|
321 |
+
</label>
|
322 |
+
<input
|
323 |
+
type="text"
|
324 |
+
id="company"
|
325 |
+
name="company"
|
326 |
+
value={formData.company}
|
327 |
+
onChange={handleInputChange}
|
328 |
+
required
|
329 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary"
|
330 |
+
placeholder="Enter your company name"
|
331 |
+
/>
|
332 |
+
</div>
|
333 |
+
</div>
|
334 |
+
</div>
|
335 |
+
|
336 |
+
{/* Project Information */}
|
337 |
+
<div>
|
338 |
+
<h3 className="text-xl font-semibold mb-6 flex items-center">
|
339 |
+
<MessageSquare className="mr-3 text-secondary-400" size={24} />
|
340 |
+
Project Information
|
341 |
+
</h3>
|
342 |
+
|
343 |
+
<div className="space-y-6">
|
344 |
+
<div>
|
345 |
+
<label htmlFor="problems" className="block text-sm font-medium text-text-primary mb-2">
|
346 |
+
What problems are you looking to solve? *
|
347 |
+
</label>
|
348 |
+
<textarea
|
349 |
+
id="problems"
|
350 |
+
name="problems"
|
351 |
+
value={formData.problems}
|
352 |
+
onChange={handleInputChange}
|
353 |
+
required
|
354 |
+
rows={4}
|
355 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary resize-vertical"
|
356 |
+
placeholder="Describe the specific challenges or inefficiencies you're facing that AI automation could help solve..."
|
357 |
+
/>
|
358 |
+
</div>
|
359 |
+
|
360 |
+
<div>
|
361 |
+
<label htmlFor="additionalInfo" className="block text-sm font-medium text-text-primary mb-2 flex items-center">
|
362 |
+
<FileText className="mr-2" size={18} />
|
363 |
+
Additional Information
|
364 |
+
<span className="text-text-secondary text-xs ml-2">(Optional)</span>
|
365 |
+
</label>
|
366 |
+
<textarea
|
367 |
+
id="additionalInfo"
|
368 |
+
name="additionalInfo"
|
369 |
+
value={formData.additionalInfo}
|
370 |
+
onChange={handleInputChange}
|
371 |
+
rows={3}
|
372 |
+
className="w-full px-4 py-3 bg-background border border-secondary-700/50 rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary-500 focus:border-transparent text-text-primary placeholder-text-secondary resize-vertical"
|
373 |
+
placeholder="Any additional details about your business, timeline, budget considerations, or specific requirements..."
|
374 |
+
/>
|
375 |
+
</div>
|
376 |
+
</div>
|
377 |
+
</div>
|
378 |
+
|
379 |
+
{/* Submit Button */}
|
380 |
+
<motion.button
|
381 |
+
type="submit"
|
382 |
+
disabled={status.type === 'loading'}
|
383 |
+
className="group relative w-full inline-flex items-center justify-center px-8 py-4 text-lg font-medium text-white bg-gradient-to-r from-secondary-600 to-accent-700 rounded-lg overflow-hidden transition-all duration-300 shadow-lg shadow-secondary-900/30 hover:shadow-secondary-800/50 disabled:opacity-50 disabled:cursor-not-allowed"
|
384 |
+
whileHover={{ scale: status.type === 'loading' ? 1 : 1.02 }}
|
385 |
+
whileTap={{ scale: status.type === 'loading' ? 1 : 0.98 }}
|
386 |
+
>
|
387 |
+
<span className="relative z-10 flex items-center">
|
388 |
+
<span>
|
389 |
+
{status.type === 'loading' ? 'Submitting Your Request...' : 'Submit Booking Request'}
|
390 |
+
</span>
|
391 |
+
{status.type === 'loading' && (
|
392 |
+
<div className="ml-3 w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"></div>
|
393 |
+
)}
|
394 |
+
</span>
|
395 |
+
<span className="absolute inset-0 bg-gradient-to-r from-secondary-500 to-accent-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
|
396 |
+
</motion.button>
|
397 |
+
</form>
|
398 |
+
|
399 |
+
{/* Additional Information */}
|
400 |
+
<div className="mt-8 p-6 bg-secondary-900/10 rounded-lg border border-secondary-800/30">
|
401 |
+
<h4 className="text-lg font-semibold mb-3 text-secondary-300">What happens next?</h4>
|
402 |
+
<ul className="space-y-2 text-text-secondary text-sm">
|
403 |
+
<li className="flex items-start">
|
404 |
+
<span className="text-secondary-400 mr-2">1.</span>
|
405 |
+
We'll review your submission within 24 hours
|
406 |
+
</li>
|
407 |
+
<li className="flex items-start">
|
408 |
+
<span className="text-secondary-400 mr-2">2.</span>
|
409 |
+
Our team will contact you to schedule a convenient time for your consultation
|
410 |
+
</li>
|
411 |
+
<li className="flex items-start">
|
412 |
+
<span className="text-secondary-400 mr-2">3.</span>
|
413 |
+
During the call, we'll discuss your specific needs and create a custom AI strategy
|
414 |
+
</li>
|
415 |
+
<li className="flex items-start">
|
416 |
+
<span className="text-secondary-400 mr-2">4.</span>
|
417 |
+
You'll receive a detailed proposal with timeline and next steps
|
418 |
+
</li>
|
419 |
+
</ul>
|
420 |
+
</div>
|
421 |
+
</div>
|
422 |
+
</motion.div>
|
423 |
+
</div>
|
424 |
+
</div>
|
425 |
+
</div>
|
426 |
+
);
|
427 |
+
};
|
428 |
+
|
429 |
+
export default BookingForm;
|
project 2/src/pages/HomePage.tsx
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import Navbar from '../components/Navbar';
|
3 |
+
import HeroSection from '../sections/HeroSection';
|
4 |
+
import FeaturesSection from '../sections/FeaturesSection';
|
5 |
+
import ResultsSection from '../sections/ResultsSection';
|
6 |
+
import ContactSection from '../sections/ContactSection';
|
7 |
+
import Footer from '../components/Footer';
|
8 |
+
import BackgroundEffects from '../components/BackgroundEffects';
|
9 |
+
|
10 |
+
const HomePage: React.FC = () => {
|
11 |
+
return (
|
12 |
+
<div className="relative min-h-screen bg-background font-sans">
|
13 |
+
<BackgroundEffects />
|
14 |
+
<Navbar />
|
15 |
+
<main>
|
16 |
+
<HeroSection />
|
17 |
+
<FeaturesSection />
|
18 |
+
<ResultsSection />
|
19 |
+
<ContactSection />
|
20 |
+
</main>
|
21 |
+
<Footer />
|
22 |
+
</div>
|
23 |
+
);
|
24 |
+
};
|
25 |
+
|
26 |
+
export default HomePage;
|
project 2/src/sections/ContactSection.tsx
ADDED
@@ -0,0 +1,349 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import { motion } from 'framer-motion';
|
3 |
+
import { useInView } from 'react-intersection-observer';
|
4 |
+
import { Clock, DollarSign, Users, TrendingUp } from 'lucide-react';
|
5 |
+
|
6 |
+
const ContactSection: React.FC = () => {
|
7 |
+
const [ref, inView] = useInView({
|
8 |
+
triggerOnce: true,
|
9 |
+
threshold: 0.1,
|
10 |
+
});
|
11 |
+
|
12 |
+
// Professional smooth curve with revenue spike matching the uploaded style
|
13 |
+
const combinedPath = "M 5 80 Q 15 75 25 70 Q 35 68 45 65 Q 55 63 65 45 Q 75 25 85 20 Q 95 15 100 12";
|
14 |
+
|
15 |
+
const metrics = [
|
16 |
+
{
|
17 |
+
icon: <Clock size={20} className="text-secondary-400" />,
|
18 |
+
title: "Time Efficiency",
|
19 |
+
value: "85%",
|
20 |
+
subtitle: "Faster Processing",
|
21 |
+
color: "#14c7c7",
|
22 |
+
barData: [20, 35, 45, 60, 75, 85, 90, 85, 88, 92, 95, 98]
|
23 |
+
},
|
24 |
+
{
|
25 |
+
icon: <DollarSign size={20} className="text-accent-400" />,
|
26 |
+
title: "Revenue Impact",
|
27 |
+
value: "240%",
|
28 |
+
subtitle: "Growth Increase",
|
29 |
+
color: "#00e6e0",
|
30 |
+
barData: [15, 25, 30, 40, 55, 70, 85, 95, 100, 110, 125, 140]
|
31 |
+
},
|
32 |
+
{
|
33 |
+
icon: <Users size={20} className="text-primary-400" />,
|
34 |
+
title: "Client Success",
|
35 |
+
value: "96%",
|
36 |
+
subtitle: "Satisfaction Rate",
|
37 |
+
color: "#33d9d9",
|
38 |
+
barData: [60, 65, 70, 75, 80, 85, 88, 90, 92, 94, 95, 96]
|
39 |
+
}
|
40 |
+
];
|
41 |
+
|
42 |
+
return (
|
43 |
+
<section className="py-24 relative" id="contact">
|
44 |
+
{/* Decorative elements */}
|
45 |
+
<div className="absolute left-0 right-0 top-0 h-px bg-gradient-to-r from-transparent via-secondary-700/50 to-transparent"></div>
|
46 |
+
|
47 |
+
<div className="container mx-auto px-4 md:px-6">
|
48 |
+
<motion.div
|
49 |
+
ref={ref}
|
50 |
+
initial={{ opacity: 0, y: 30 }}
|
51 |
+
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
|
52 |
+
transition={{ duration: 0.6 }}
|
53 |
+
className="text-center mb-16"
|
54 |
+
>
|
55 |
+
<h2 className="text-3xl md:text-4xl font-bold mb-6">Performance Dashboard</h2>
|
56 |
+
<p className="text-text-secondary text-lg max-w-2xl mx-auto leading-relaxed">
|
57 |
+
Real-time insights into the transformative impact of our AI automation solutions.
|
58 |
+
</p>
|
59 |
+
</motion.div>
|
60 |
+
|
61 |
+
{/* Dashboard Container */}
|
62 |
+
<motion.div
|
63 |
+
initial={{ opacity: 0, y: 40 }}
|
64 |
+
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 40 }}
|
65 |
+
transition={{ duration: 0.8, delay: 0.2 }}
|
66 |
+
className="max-w-7xl mx-auto"
|
67 |
+
>
|
68 |
+
<div className="bg-white/[0.02] backdrop-blur-sm border border-white/[0.05] rounded-3xl p-8 md:p-12 shadow-2xl relative overflow-hidden">
|
69 |
+
{/* Subtle background grid */}
|
70 |
+
<div className="absolute inset-0 opacity-[0.02]">
|
71 |
+
<div className="absolute inset-0" style={{
|
72 |
+
backgroundImage: `linear-gradient(rgba(255,255,255,0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.1) 1px, transparent 1px)`,
|
73 |
+
backgroundSize: '20px 20px'
|
74 |
+
}}></div>
|
75 |
+
</div>
|
76 |
+
|
77 |
+
<div className="relative z-10">
|
78 |
+
{/* Top Metrics Row */}
|
79 |
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 mb-12">
|
80 |
+
{metrics.map((metric, index) => (
|
81 |
+
<motion.div
|
82 |
+
key={index}
|
83 |
+
initial={{ opacity: 0, y: 20 }}
|
84 |
+
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
85 |
+
transition={{ duration: 0.6, delay: 0.4 + index * 0.1 }}
|
86 |
+
className="bg-white/[0.03] rounded-2xl p-6 border border-white/[0.08] hover:bg-white/[0.05] transition-all duration-300"
|
87 |
+
>
|
88 |
+
{/* Header */}
|
89 |
+
<div className="flex items-center justify-between mb-4">
|
90 |
+
<div className="flex items-center space-x-3">
|
91 |
+
{metric.icon}
|
92 |
+
<span className="text-white/70 text-sm font-medium">{metric.title}</span>
|
93 |
+
</div>
|
94 |
+
</div>
|
95 |
+
|
96 |
+
{/* Main Value */}
|
97 |
+
<div className="mb-4">
|
98 |
+
<div className="text-3xl font-bold text-white mb-1">{metric.value}</div>
|
99 |
+
<div className="text-white/60 text-sm">{metric.subtitle}</div>
|
100 |
+
</div>
|
101 |
+
|
102 |
+
{/* Mini Bar Chart */}
|
103 |
+
<div className="flex items-end space-x-1 h-12">
|
104 |
+
{metric.barData.map((height, barIndex) => (
|
105 |
+
<motion.div
|
106 |
+
key={barIndex}
|
107 |
+
className="flex-1 rounded-sm"
|
108 |
+
style={{ backgroundColor: metric.color }}
|
109 |
+
initial={{ height: 0, opacity: 0.6 }}
|
110 |
+
animate={inView ? {
|
111 |
+
height: `${(height / Math.max(...metric.barData)) * 100}%`,
|
112 |
+
opacity: barIndex === metric.barData.length - 1 ? 1 : 0.6
|
113 |
+
} : { height: 0, opacity: 0.6 }}
|
114 |
+
transition={{
|
115 |
+
duration: 1.2,
|
116 |
+
delay: 0.8 + index * 0.2 + barIndex * 0.05,
|
117 |
+
ease: "easeOut"
|
118 |
+
}}
|
119 |
+
/>
|
120 |
+
))}
|
121 |
+
</div>
|
122 |
+
</motion.div>
|
123 |
+
))}
|
124 |
+
</div>
|
125 |
+
|
126 |
+
{/* Main Chart Section */}
|
127 |
+
<div className="bg-white/[0.02] rounded-2xl p-8 border border-white/[0.05]">
|
128 |
+
<div className="flex items-center justify-between mb-8">
|
129 |
+
<div>
|
130 |
+
<h3 className="text-xl font-semibold text-white mb-2">Monthly Performance Trajectory</h3>
|
131 |
+
<p className="text-white/60 text-sm">Cumulative impact across all business metrics</p>
|
132 |
+
</div>
|
133 |
+
<div className="text-right">
|
134 |
+
<div className="text-3xl font-bold" style={{ color: '#00e6e0' }}>92</div>
|
135 |
+
<div className="text-white/60 text-sm">Performance Score</div>
|
136 |
+
</div>
|
137 |
+
</div>
|
138 |
+
|
139 |
+
{/* Main Chart */}
|
140 |
+
<div className="relative h-80 rounded-xl overflow-hidden">
|
141 |
+
{/* Chart background */}
|
142 |
+
<div className="absolute inset-0 bg-black/10 rounded-xl"></div>
|
143 |
+
|
144 |
+
{/* Grid lines */}
|
145 |
+
<div className="absolute inset-0">
|
146 |
+
<svg className="w-full h-full">
|
147 |
+
<defs>
|
148 |
+
<pattern id="chartGrid" width="60" height="40" patternUnits="userSpaceOnUse">
|
149 |
+
<path d="M 60 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.05)" strokeWidth="1"/>
|
150 |
+
</pattern>
|
151 |
+
</defs>
|
152 |
+
<rect width="100%" height="100%" fill="url(#chartGrid)" />
|
153 |
+
</svg>
|
154 |
+
</div>
|
155 |
+
|
156 |
+
{/* Chart content */}
|
157 |
+
<div className="absolute inset-8">
|
158 |
+
<svg
|
159 |
+
viewBox="0 0 100 100"
|
160 |
+
className="w-full h-full"
|
161 |
+
preserveAspectRatio="none"
|
162 |
+
>
|
163 |
+
<defs>
|
164 |
+
{/* Gradient for the line */}
|
165 |
+
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
166 |
+
<stop offset="0%" stopColor="#14c7c7" />
|
167 |
+
<stop offset="50%" stopColor="#00e6e0" />
|
168 |
+
<stop offset="100%" stopColor="#33d9d9" />
|
169 |
+
</linearGradient>
|
170 |
+
|
171 |
+
{/* Area fill gradient */}
|
172 |
+
<linearGradient id="areaFill" x1="0%" y1="0%" x2="0%" y2="100%">
|
173 |
+
<stop offset="0%" stopColor="#00e6e0" stopOpacity="0.2"/>
|
174 |
+
<stop offset="100%" stopColor="#00e6e0" stopOpacity="0"/>
|
175 |
+
</linearGradient>
|
176 |
+
|
177 |
+
{/* Glow filter */}
|
178 |
+
<filter id="glow">
|
179 |
+
<feGaussianBlur stdDeviation="3" result="coloredBlur"/>
|
180 |
+
<feMerge>
|
181 |
+
<feMergeNode in="coloredBlur"/>
|
182 |
+
<feMergeNode in="SourceGraphic"/>
|
183 |
+
</feMerge>
|
184 |
+
</filter>
|
185 |
+
</defs>
|
186 |
+
|
187 |
+
{/* Area under curve */}
|
188 |
+
<motion.path
|
189 |
+
d={`${combinedPath} L 100 100 L 5 100 Z`}
|
190 |
+
fill="url(#areaFill)"
|
191 |
+
initial={{ opacity: 0 }}
|
192 |
+
animate={inView ? { opacity: 1 } : { opacity: 0 }}
|
193 |
+
transition={{ duration: 1.5, delay: 1.2 }}
|
194 |
+
/>
|
195 |
+
|
196 |
+
{/* Main performance line */}
|
197 |
+
<motion.path
|
198 |
+
d={combinedPath}
|
199 |
+
fill="none"
|
200 |
+
stroke="url(#lineGradient)"
|
201 |
+
strokeWidth="3"
|
202 |
+
strokeLinecap="round"
|
203 |
+
strokeLinejoin="round"
|
204 |
+
filter="url(#glow)"
|
205 |
+
initial={{ pathLength: 0, opacity: 0 }}
|
206 |
+
animate={inView ? { pathLength: 1, opacity: 1 } : { pathLength: 0, opacity: 0 }}
|
207 |
+
transition={{
|
208 |
+
duration: 2.5,
|
209 |
+
delay: 0.8,
|
210 |
+
ease: "easeInOut"
|
211 |
+
}}
|
212 |
+
/>
|
213 |
+
|
214 |
+
{/* Data points */}
|
215 |
+
{[
|
216 |
+
{ x: 5, y: 80, label: "Q1" },
|
217 |
+
{ x: 25, y: 70, label: "Q2" },
|
218 |
+
{ x: 45, y: 65, label: "Q3" },
|
219 |
+
{ x: 65, y: 45, label: "Q4" },
|
220 |
+
{ x: 85, y: 20, label: "Q5" },
|
221 |
+
{ x: 100, y: 12, label: "Q6" }
|
222 |
+
].map((point, index) => (
|
223 |
+
<g key={index}>
|
224 |
+
<motion.circle
|
225 |
+
cx={point.x}
|
226 |
+
cy={point.y}
|
227 |
+
r="4"
|
228 |
+
fill="#00e6e0"
|
229 |
+
stroke="white"
|
230 |
+
strokeWidth="2"
|
231 |
+
initial={{ scale: 0, opacity: 0 }}
|
232 |
+
animate={inView ? { scale: 1, opacity: 1 } : { scale: 0, opacity: 0 }}
|
233 |
+
transition={{
|
234 |
+
duration: 0.4,
|
235 |
+
delay: 1.5 + index * 0.1,
|
236 |
+
type: "spring",
|
237 |
+
stiffness: 200
|
238 |
+
}}
|
239 |
+
/>
|
240 |
+
{/* Pulse effect */}
|
241 |
+
<motion.circle
|
242 |
+
cx={point.x}
|
243 |
+
cy={point.y}
|
244 |
+
r="4"
|
245 |
+
fill="none"
|
246 |
+
stroke="#00e6e0"
|
247 |
+
strokeWidth="1"
|
248 |
+
initial={{ scale: 0, opacity: 0 }}
|
249 |
+
animate={inView ? {
|
250 |
+
scale: [1, 2, 1],
|
251 |
+
opacity: [0.8, 0, 0.8]
|
252 |
+
} : { scale: 0, opacity: 0 }}
|
253 |
+
transition={{
|
254 |
+
duration: 2,
|
255 |
+
delay: 2 + index * 0.1,
|
256 |
+
repeat: Infinity,
|
257 |
+
repeatDelay: 3
|
258 |
+
}}
|
259 |
+
/>
|
260 |
+
</g>
|
261 |
+
))}
|
262 |
+
</svg>
|
263 |
+
</div>
|
264 |
+
|
265 |
+
{/* Axis labels */}
|
266 |
+
<div className="absolute bottom-4 left-8 right-8 flex justify-between">
|
267 |
+
{['Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov'].map((month, index) => (
|
268 |
+
<span key={index} className="text-xs font-medium text-white/50">{month}</span>
|
269 |
+
))}
|
270 |
+
</div>
|
271 |
+
|
272 |
+
<div className="absolute left-4 top-8 bottom-8 flex flex-col justify-between">
|
273 |
+
<span className="text-xs font-medium text-white/50">100</span>
|
274 |
+
<span className="text-xs font-medium text-white/50">75</span>
|
275 |
+
<span className="text-xs font-medium text-white/50">50</span>
|
276 |
+
<span className="text-xs font-medium text-white/50">25</span>
|
277 |
+
<span className="text-xs font-medium text-white/50">0</span>
|
278 |
+
</div>
|
279 |
+
</div>
|
280 |
+
</div>
|
281 |
+
|
282 |
+
{/* Legend */}
|
283 |
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
|
284 |
+
{[
|
285 |
+
{
|
286 |
+
color: "#14c7c7",
|
287 |
+
title: "Foundation Phase",
|
288 |
+
description: "Initial setup and system integration with immediate efficiency gains"
|
289 |
+
},
|
290 |
+
{
|
291 |
+
color: "#00e6e0",
|
292 |
+
title: "Optimization Phase",
|
293 |
+
description: "AI learning and process refinement leading to exponential improvements"
|
294 |
+
},
|
295 |
+
{
|
296 |
+
color: "#33d9d9",
|
297 |
+
title: "Scale Phase",
|
298 |
+
description: "Full automation deployment with sustained high-performance results"
|
299 |
+
}
|
300 |
+
].map((phase, index) => (
|
301 |
+
<motion.div
|
302 |
+
key={index}
|
303 |
+
initial={{ opacity: 0, y: 20 }}
|
304 |
+
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
305 |
+
transition={{ duration: 0.6, delay: 2.2 + index * 0.1 }}
|
306 |
+
className="flex items-start space-x-4"
|
307 |
+
>
|
308 |
+
<div
|
309 |
+
className="w-3 h-3 rounded-full mt-1 flex-shrink-0"
|
310 |
+
style={{ backgroundColor: phase.color }}
|
311 |
+
></div>
|
312 |
+
<div>
|
313 |
+
<h4 className="text-white font-medium text-sm mb-1">{phase.title}</h4>
|
314 |
+
<p className="text-white/60 text-xs leading-relaxed">{phase.description}</p>
|
315 |
+
</div>
|
316 |
+
</motion.div>
|
317 |
+
))}
|
318 |
+
</div>
|
319 |
+
</div>
|
320 |
+
</div>
|
321 |
+
</motion.div>
|
322 |
+
|
323 |
+
{/* CTA Section */}
|
324 |
+
<motion.div
|
325 |
+
initial={{ opacity: 0, y: 30 }}
|
326 |
+
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
|
327 |
+
transition={{ duration: 0.6, delay: 2.8 }}
|
328 |
+
className="text-center mt-16"
|
329 |
+
>
|
330 |
+
<h3 className="text-2xl font-semibold mb-6 text-white">Ready to See These Results?</h3>
|
331 |
+
<p className="text-white/70 mb-10 max-w-2xl mx-auto text-lg leading-relaxed">
|
332 |
+
Join forward-thinking companies that have transformed their operations with our proven AI methodology.
|
333 |
+
</p>
|
334 |
+
<motion.button
|
335 |
+
onClick={() => window.location.href = '/book-call'}
|
336 |
+
className="inline-flex items-center px-10 py-4 text-lg font-semibold text-white bg-gradient-to-r from-secondary-600 to-accent-700 rounded-xl shadow-2xl shadow-secondary-900/30 hover:shadow-secondary-800/50 transition-all duration-300 border border-white/10"
|
337 |
+
whileHover={{ scale: 1.02, y: -2 }}
|
338 |
+
whileTap={{ scale: 0.98 }}
|
339 |
+
>
|
340 |
+
Schedule Strategy Session
|
341 |
+
<TrendingUp className="ml-3" size={20} />
|
342 |
+
</motion.button>
|
343 |
+
</motion.div>
|
344 |
+
</div>
|
345 |
+
</section>
|
346 |
+
);
|
347 |
+
};
|
348 |
+
|
349 |
+
export default ContactSection;
|
project 2/src/sections/FeaturesSection.tsx
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import { motion } from 'framer-motion';
|
3 |
+
import { useInView } from 'react-intersection-observer';
|
4 |
+
import {
|
5 |
+
BrainCircuit,
|
6 |
+
Users,
|
7 |
+
Database,
|
8 |
+
Zap
|
9 |
+
} from 'lucide-react';
|
10 |
+
|
11 |
+
interface FeatureCardProps {
|
12 |
+
icon: React.ReactNode;
|
13 |
+
title: string;
|
14 |
+
description: string;
|
15 |
+
index: number;
|
16 |
+
}
|
17 |
+
|
18 |
+
const FeatureCard: React.FC<FeatureCardProps> = ({ icon, title, description, index }) => {
|
19 |
+
const [ref, inView] = useInView({
|
20 |
+
triggerOnce: true,
|
21 |
+
threshold: 0.1,
|
22 |
+
});
|
23 |
+
|
24 |
+
return (
|
25 |
+
<motion.div
|
26 |
+
ref={ref}
|
27 |
+
initial={{ opacity: 0, y: 50 }}
|
28 |
+
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 50 }}
|
29 |
+
transition={{ duration: 0.6, delay: index * 0.1 }}
|
30 |
+
className="bg-background-light border border-primary-900/30 rounded-xl p-6 shadow-lg shadow-primary-900/5 relative overflow-hidden group"
|
31 |
+
>
|
32 |
+
{/* Glowing border effect */}
|
33 |
+
<div className="absolute inset-0 bg-gradient-to-r from-primary-600/0 via-primary-600/20 to-accent-600/0 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
34 |
+
|
35 |
+
<div className="relative z-10">
|
36 |
+
<div className="bg-gradient-to-br from-primary-500 to-accent-500 rounded-lg p-3 inline-block mb-4">
|
37 |
+
{icon}
|
38 |
+
</div>
|
39 |
+
<h3 className="text-xl font-semibold mb-3 text-text-primary">{title}</h3>
|
40 |
+
<p className="text-text-secondary text-base">{description}</p>
|
41 |
+
</div>
|
42 |
+
</motion.div>
|
43 |
+
);
|
44 |
+
};
|
45 |
+
|
46 |
+
const FeaturesSection: React.FC = () => {
|
47 |
+
const [ref, inView] = useInView({
|
48 |
+
triggerOnce: true,
|
49 |
+
threshold: 0.1,
|
50 |
+
});
|
51 |
+
|
52 |
+
const [founderRef, founderInView] = useInView({
|
53 |
+
triggerOnce: true,
|
54 |
+
threshold: 0.1,
|
55 |
+
});
|
56 |
+
|
57 |
+
const features = [
|
58 |
+
{
|
59 |
+
icon: <BrainCircuit size={24} className="text-white" />,
|
60 |
+
title: "AI-Powered Automation",
|
61 |
+
description: "Implement intelligent automation solutions that adapt to your business needs and scale with your growth."
|
62 |
+
},
|
63 |
+
{
|
64 |
+
icon: <Database size={24} className="text-white" />,
|
65 |
+
title: "CRM Integration",
|
66 |
+
description: "Seamlessly connect your AI tools with existing CRM systems for enhanced workflow and customer insights."
|
67 |
+
},
|
68 |
+
{
|
69 |
+
icon: <Users size={24} className="text-white" />,
|
70 |
+
title: "Lead Generation",
|
71 |
+
description: "Generate qualified leads through AI-driven targeting and personalized outreach campaigns."
|
72 |
+
},
|
73 |
+
{
|
74 |
+
icon: <Zap size={24} className="text-white" />,
|
75 |
+
title: "Rapid Implementation",
|
76 |
+
description: "Quick deployment of AI solutions with minimal disruption to your existing operations."
|
77 |
+
}
|
78 |
+
];
|
79 |
+
|
80 |
+
return (
|
81 |
+
<section className="py-20 md:py-28 relative" id="features">
|
82 |
+
<div className="container mx-auto px-4 md:px-6">
|
83 |
+
<motion.div
|
84 |
+
ref={ref}
|
85 |
+
initial={{ opacity: 0, y: 20 }}
|
86 |
+
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
87 |
+
transition={{ duration: 0.6 }}
|
88 |
+
className="text-center mb-16"
|
89 |
+
>
|
90 |
+
<h2 className="text-4xl md:text-5xl font-bold mb-4">Cutting-Edge AI Solutions</h2>
|
91 |
+
<p className="text-text-secondary max-w-2xl mx-auto text-xl">
|
92 |
+
Our innovative technology stack delivers powerful automation and integration capabilities to transform your business operations.
|
93 |
+
</p>
|
94 |
+
</motion.div>
|
95 |
+
|
96 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-start">
|
97 |
+
{/* Left Side - AI Solutions */}
|
98 |
+
<div className="space-y-6">
|
99 |
+
{features.map((feature, index) => (
|
100 |
+
<FeatureCard
|
101 |
+
key={index}
|
102 |
+
icon={feature.icon}
|
103 |
+
title={feature.title}
|
104 |
+
description={feature.description}
|
105 |
+
index={index}
|
106 |
+
/>
|
107 |
+
))}
|
108 |
+
</div>
|
109 |
+
|
110 |
+
{/* Right Side - Founder Section */}
|
111 |
+
<motion.div
|
112 |
+
ref={founderRef}
|
113 |
+
initial={{ opacity: 0, x: 50 }}
|
114 |
+
animate={founderInView ? { opacity: 1, x: 0 } : { opacity: 0, x: 50 }}
|
115 |
+
transition={{ duration: 0.8, delay: 0.2 }}
|
116 |
+
className="flex flex-col items-center lg:sticky lg:top-24"
|
117 |
+
>
|
118 |
+
{/* Founder Label */}
|
119 |
+
<motion.div
|
120 |
+
initial={{ opacity: 0, y: -20 }}
|
121 |
+
animate={founderInView ? { opacity: 1, y: 0 } : { opacity: 0, y: -20 }}
|
122 |
+
transition={{ duration: 0.6, delay: 0.4 }}
|
123 |
+
className="mb-6"
|
124 |
+
>
|
125 |
+
<h3 className="text-2xl font-bold text-center bg-gradient-to-r from-secondary-400 to-accent-400 bg-clip-text text-transparent">
|
126 |
+
Founder
|
127 |
+
</h3>
|
128 |
+
</motion.div>
|
129 |
+
|
130 |
+
{/* Founder Image Container */}
|
131 |
+
<motion.div
|
132 |
+
initial={{ opacity: 0, scale: 0.9 }}
|
133 |
+
animate={founderInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.9 }}
|
134 |
+
transition={{ duration: 0.8, delay: 0.6 }}
|
135 |
+
className="relative group"
|
136 |
+
>
|
137 |
+
{/* Animated border glow */}
|
138 |
+
<div className="absolute -inset-1 bg-gradient-to-r from-secondary-500 via-accent-500 to-primary-500 rounded-2xl blur-sm opacity-60 group-hover:opacity-100 transition-opacity duration-500 animate-pulse"></div>
|
139 |
+
|
140 |
+
{/* Image container */}
|
141 |
+
<div className="relative bg-background-light rounded-2xl p-2 border border-secondary-800/30 overflow-hidden">
|
142 |
+
<div className="relative w-80 h-80 rounded-xl overflow-hidden">
|
143 |
+
<img
|
144 |
+
src="/assets/WhatsApp Image 2025-06-28 at 12.51.41.jpeg"
|
145 |
+
alt="Founder"
|
146 |
+
className="w-full h-full object-cover object-center grayscale hover:grayscale-0 transition-all duration-500"
|
147 |
+
/>
|
148 |
+
|
149 |
+
{/* Subtle overlay gradient */}
|
150 |
+
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
151 |
+
</div>
|
152 |
+
</div>
|
153 |
+
|
154 |
+
{/* Floating particles effect */}
|
155 |
+
<div className="absolute inset-0 pointer-events-none">
|
156 |
+
{[...Array(6)].map((_, i) => (
|
157 |
+
<motion.div
|
158 |
+
key={i}
|
159 |
+
className="absolute w-1 h-1 bg-accent-400/60 rounded-full"
|
160 |
+
style={{
|
161 |
+
left: `${20 + i * 15}%`,
|
162 |
+
top: `${10 + i * 12}%`,
|
163 |
+
}}
|
164 |
+
animate={{
|
165 |
+
y: [-10, 10, -10],
|
166 |
+
opacity: [0.3, 0.8, 0.3],
|
167 |
+
}}
|
168 |
+
transition={{
|
169 |
+
duration: 3 + i * 0.5,
|
170 |
+
repeat: Infinity,
|
171 |
+
delay: i * 0.3,
|
172 |
+
}}
|
173 |
+
/>
|
174 |
+
))}
|
175 |
+
</div>
|
176 |
+
</motion.div>
|
177 |
+
|
178 |
+
{/* Optional founder info */}
|
179 |
+
<motion.div
|
180 |
+
initial={{ opacity: 0, y: 20 }}
|
181 |
+
animate={founderInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
182 |
+
transition={{ duration: 0.6, delay: 0.8 }}
|
183 |
+
className="mt-6 text-center"
|
184 |
+
>
|
185 |
+
<p className="text-text-secondary text-sm max-w-xs">
|
186 |
+
Leading the future of AI automation with innovative solutions that transform businesses worldwide.
|
187 |
+
</p>
|
188 |
+
</motion.div>
|
189 |
+
</motion.div>
|
190 |
+
</div>
|
191 |
+
</div>
|
192 |
+
</section>
|
193 |
+
);
|
194 |
+
};
|
195 |
+
|
196 |
+
export default FeaturesSection;
|
project 2/src/sections/HeroSection.tsx
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useEffect, useRef, useState } from 'react';
|
2 |
+
import { motion } from 'framer-motion';
|
3 |
+
import { ChevronDown } from 'lucide-react';
|
4 |
+
import { useNavigate } from 'react-router-dom';
|
5 |
+
|
6 |
+
const HeroSection: React.FC = () => {
|
7 |
+
const splineWrapperRef = useRef<HTMLDivElement>(null);
|
8 |
+
const [gradientPos, setGradientPos] = useState({ x: '50%', y: '50%' });
|
9 |
+
const navigate = useNavigate();
|
10 |
+
|
11 |
+
useEffect(() => {
|
12 |
+
const wrapper = splineWrapperRef.current;
|
13 |
+
const handleWheel = (e: WheelEvent) => {
|
14 |
+
window.scrollBy({ top: e.deltaY, behavior: 'auto' });
|
15 |
+
};
|
16 |
+
if (wrapper) {
|
17 |
+
wrapper.addEventListener('wheel', handleWheel, { passive: false });
|
18 |
+
}
|
19 |
+
return () => {
|
20 |
+
if (wrapper) wrapper.removeEventListener('wheel', handleWheel);
|
21 |
+
};
|
22 |
+
}, []);
|
23 |
+
|
24 |
+
useEffect(() => {
|
25 |
+
const scriptId = 'spline-viewer-script';
|
26 |
+
if (!document.getElementById(scriptId)) {
|
27 |
+
const script = document.createElement('script');
|
28 |
+
script.type = 'module';
|
29 |
+
script.src = 'https://unpkg.com/@splinetool/[email protected]/build/spline-viewer.js';
|
30 |
+
script.id = scriptId;
|
31 |
+
document.body.appendChild(script);
|
32 |
+
}
|
33 |
+
}, []);
|
34 |
+
|
35 |
+
// Handle both mouse and touch movement
|
36 |
+
const handleMove = (clientX: number, clientY: number, target: HTMLDivElement) => {
|
37 |
+
const rect = target.getBoundingClientRect();
|
38 |
+
const x = ((clientX - rect.left) / rect.width) * 100;
|
39 |
+
const y = ((clientY - rect.top) / rect.height) * 100;
|
40 |
+
setGradientPos({ x: `${x}%`, y: `${y}%` });
|
41 |
+
};
|
42 |
+
|
43 |
+
const handleBookCall = () => {
|
44 |
+
navigate('/book-call');
|
45 |
+
};
|
46 |
+
|
47 |
+
return (
|
48 |
+
<section className="relative h-screen w-full overflow-hidden" id="home">
|
49 |
+
<div className="absolute inset-0 z-0" ref={splineWrapperRef}>
|
50 |
+
<spline-viewer
|
51 |
+
url="https://prod.spline.design/odVPsg6TTzs-Etco/scene.splinecode"
|
52 |
+
className="w-full h-full"
|
53 |
+
/>
|
54 |
+
</div>
|
55 |
+
|
56 |
+
<div
|
57 |
+
className="absolute bottom-4 right-4 z-10"
|
58 |
+
onMouseMove={(e) => handleMove(e.clientX, e.clientY, e.currentTarget as HTMLDivElement)}
|
59 |
+
onTouchMove={(e) => {
|
60 |
+
const touch = e.touches[0];
|
61 |
+
if (touch) handleMove(touch.clientX, touch.clientY, e.currentTarget as HTMLDivElement);
|
62 |
+
}}
|
63 |
+
>
|
64 |
+
<button
|
65 |
+
onClick={handleBookCall}
|
66 |
+
className="relative overflow-hidden text-white font-semibold py-3 px-8 rounded-md shadow-lg transition-all duration-300 ease-out"
|
67 |
+
style={{
|
68 |
+
background: `linear-gradient(135deg, #003234, #00AAAE)`,
|
69 |
+
}}
|
70 |
+
>
|
71 |
+
Book a Call
|
72 |
+
<span
|
73 |
+
className="absolute inset-0 pointer-events-none transition-all duration-300 ease-out"
|
74 |
+
style={{
|
75 |
+
background: `radial-gradient(circle at ${gradientPos.x} ${gradientPos.y}, rgba(32,201,151,0.5) 10%, transparent 40%)`,
|
76 |
+
opacity: 1,
|
77 |
+
}}
|
78 |
+
></span>
|
79 |
+
</button>
|
80 |
+
</div>
|
81 |
+
|
82 |
+
<motion.div
|
83 |
+
className="absolute bottom-8 left-1/2 transform -translate-x-1/2 z-10"
|
84 |
+
initial={{ opacity: 0, y: -10 }}
|
85 |
+
animate={{ opacity: 1, y: 0 }}
|
86 |
+
transition={{
|
87 |
+
duration: 0.5,
|
88 |
+
delay: 1.5,
|
89 |
+
repeat: Infinity,
|
90 |
+
repeatType: 'reverse',
|
91 |
+
}}
|
92 |
+
>
|
93 |
+
<ChevronDown size={32} className="text-white animate-bounce" />
|
94 |
+
</motion.div>
|
95 |
+
</section>
|
96 |
+
);
|
97 |
+
};
|
98 |
+
|
99 |
+
export default HeroSection;
|
project 2/src/sections/ResultsSection.tsx
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import { motion } from 'framer-motion';
|
3 |
+
import { useInView } from 'react-intersection-observer';
|
4 |
+
import CountUp from 'react-countup';
|
5 |
+
|
6 |
+
interface StatCardProps {
|
7 |
+
count: number;
|
8 |
+
label: string;
|
9 |
+
icon: string;
|
10 |
+
delay: number;
|
11 |
+
}
|
12 |
+
|
13 |
+
const StatCard: React.FC<StatCardProps> = ({ count, label, icon, delay }) => {
|
14 |
+
const [ref, inView] = useInView({
|
15 |
+
triggerOnce: true,
|
16 |
+
threshold: 0.1,
|
17 |
+
});
|
18 |
+
|
19 |
+
return (
|
20 |
+
<motion.div
|
21 |
+
ref={ref}
|
22 |
+
initial={{ opacity: 0, scale: 0.9 }}
|
23 |
+
animate={inView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.9 }}
|
24 |
+
transition={{ duration: 0.6, delay }}
|
25 |
+
className="text-center p-6 relative"
|
26 |
+
>
|
27 |
+
{/* Animated gradient background */}
|
28 |
+
<motion.div
|
29 |
+
className="absolute inset-0 bg-gradient-to-br from-secondary-900/20 to-primary-900/10 rounded-xl"
|
30 |
+
animate={{ opacity: [0.5, 0.7, 0.5] }}
|
31 |
+
transition={{ duration: 3, repeat: Infinity }}
|
32 |
+
/>
|
33 |
+
|
34 |
+
<div className="relative z-10">
|
35 |
+
<div className="text-4xl md:text-5xl lg:text-6xl font-bold mb-3 bg-clip-text text-transparent bg-gradient-to-r from-secondary-400 to-accent-400">
|
36 |
+
{inView ? (
|
37 |
+
<>
|
38 |
+
<CountUp end={count} duration={2.5} separator="," />
|
39 |
+
{icon}
|
40 |
+
</>
|
41 |
+
) : (
|
42 |
+
"0"
|
43 |
+
)}
|
44 |
+
</div>
|
45 |
+
<p className="text-text-secondary text-lg">{label}</p>
|
46 |
+
</div>
|
47 |
+
</motion.div>
|
48 |
+
);
|
49 |
+
};
|
50 |
+
|
51 |
+
const ResultsSection: React.FC = () => {
|
52 |
+
const [ref, inView] = useInView({
|
53 |
+
triggerOnce: true,
|
54 |
+
threshold: 0.1,
|
55 |
+
});
|
56 |
+
|
57 |
+
const stats = [
|
58 |
+
{
|
59 |
+
count: 150,
|
60 |
+
label: "Bespoke AI solutions developed",
|
61 |
+
icon: "+",
|
62 |
+
delay: 0,
|
63 |
+
},
|
64 |
+
{
|
65 |
+
count: 500,
|
66 |
+
label: "AI Opportunities identified for businesses",
|
67 |
+
icon: "+",
|
68 |
+
delay: 0.2,
|
69 |
+
},
|
70 |
+
{
|
71 |
+
count: 2500,
|
72 |
+
label: "Professionals upskilled in AI via our platforms",
|
73 |
+
icon: "+",
|
74 |
+
delay: 0.4,
|
75 |
+
},
|
76 |
+
];
|
77 |
+
|
78 |
+
return (
|
79 |
+
<section className="py-24 relative" id="results">
|
80 |
+
{/* Background decorative element */}
|
81 |
+
<div className="absolute left-0 right-0 top-0 h-px bg-gradient-to-r from-transparent via-secondary-700/50 to-transparent"></div>
|
82 |
+
|
83 |
+
<div className="container mx-auto px-4 md:px-6">
|
84 |
+
<motion.div
|
85 |
+
ref={ref}
|
86 |
+
initial={{ opacity: 0, y: 20 }}
|
87 |
+
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
88 |
+
transition={{ duration: 0.6 }}
|
89 |
+
className="text-center mb-16"
|
90 |
+
>
|
91 |
+
<h2 className="text-3xl md:text-4xl font-bold mb-4">Transforming Businesses with AI</h2>
|
92 |
+
<p className="text-text-secondary max-w-2xl mx-auto text-lg">
|
93 |
+
Our track record speaks for itself. See how we've helped businesses achieve remarkable results.
|
94 |
+
</p>
|
95 |
+
</motion.div>
|
96 |
+
|
97 |
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
98 |
+
{stats.map((stat, index) => (
|
99 |
+
<StatCard
|
100 |
+
key={index}
|
101 |
+
count={stat.count}
|
102 |
+
label={stat.label}
|
103 |
+
icon={stat.icon}
|
104 |
+
delay={stat.delay}
|
105 |
+
/>
|
106 |
+
))}
|
107 |
+
</div>
|
108 |
+
</div>
|
109 |
+
</section>
|
110 |
+
);
|
111 |
+
};
|
112 |
+
|
113 |
+
export default ResultsSection;
|
project 2/src/vite-env.d.ts
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
/// <reference types="vite/client" />
|
project 2/supabase/migrations/20250607101952_lucky_coral.sql
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
# Create consultations table
|
3 |
+
|
4 |
+
1. New Tables
|
5 |
+
- `consultations`
|
6 |
+
- `id` (uuid, primary key)
|
7 |
+
- `name` (text, required)
|
8 |
+
- `email` (text, required)
|
9 |
+
- `company` (text, optional)
|
10 |
+
- `message` (text, optional)
|
11 |
+
- `created_at` (timestamp)
|
12 |
+
|
13 |
+
2. Security
|
14 |
+
- Enable RLS on `consultations` table
|
15 |
+
- Add policy for authenticated users to insert their own data
|
16 |
+
- Add policy for service role to read all data
|
17 |
+
*/
|
18 |
+
|
19 |
+
CREATE TABLE IF NOT EXISTS consultations (
|
20 |
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
21 |
+
name text NOT NULL,
|
22 |
+
email text NOT NULL,
|
23 |
+
company text,
|
24 |
+
message text,
|
25 |
+
created_at timestamptz DEFAULT now()
|
26 |
+
);
|
27 |
+
|
28 |
+
ALTER TABLE consultations ENABLE ROW LEVEL SECURITY;
|
29 |
+
|
30 |
+
-- Allow anyone to insert consultation requests
|
31 |
+
CREATE POLICY "Anyone can submit consultation requests"
|
32 |
+
ON consultations
|
33 |
+
FOR INSERT
|
34 |
+
TO anon, authenticated
|
35 |
+
WITH CHECK (true);
|
36 |
+
|
37 |
+
-- Allow service role to read all consultations (for admin purposes)
|
38 |
+
CREATE POLICY "Service role can read all consultations"
|
39 |
+
ON consultations
|
40 |
+
FOR SELECT
|
41 |
+
TO service_role
|
42 |
+
USING (true);
|
project 2/supabase/migrations/20250608090446_amber_boat.sql
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
# Create consultation form table
|
3 |
+
|
4 |
+
1. New Tables
|
5 |
+
- `consultation_forms`
|
6 |
+
- `id` (uuid, primary key)
|
7 |
+
- `name` (text, required)
|
8 |
+
- `email` (text, required)
|
9 |
+
- `website` (text, optional)
|
10 |
+
- `company` (text, optional)
|
11 |
+
- `project_description` (text, optional)
|
12 |
+
- `created_at` (timestamp)
|
13 |
+
|
14 |
+
2. Security
|
15 |
+
- Enable RLS on `consultation_forms` table
|
16 |
+
- Add policy for anonymous and authenticated users to insert data
|
17 |
+
- Add policy for service role to read all data
|
18 |
+
*/
|
19 |
+
|
20 |
+
CREATE TABLE IF NOT EXISTS consultation_forms (
|
21 |
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
22 |
+
name text NOT NULL,
|
23 |
+
email text NOT NULL,
|
24 |
+
website text,
|
25 |
+
company text,
|
26 |
+
project_description text,
|
27 |
+
created_at timestamptz DEFAULT now()
|
28 |
+
);
|
29 |
+
|
30 |
+
ALTER TABLE consultation_forms ENABLE ROW LEVEL SECURITY;
|
31 |
+
|
32 |
+
-- Allow anyone to submit consultation form requests
|
33 |
+
CREATE POLICY "Anyone can submit consultation form requests"
|
34 |
+
ON consultation_forms
|
35 |
+
FOR INSERT
|
36 |
+
TO anon, authenticated
|
37 |
+
WITH CHECK (true);
|
38 |
+
|
39 |
+
-- Allow service role to read all consultation forms (for admin purposes)
|
40 |
+
CREATE POLICY "Service role can read all consultation forms"
|
41 |
+
ON consultation_forms
|
42 |
+
FOR SELECT
|
43 |
+
TO service_role
|
44 |
+
USING (true);
|
project 2/tailwind.config.js
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/** @type {import('tailwindcss').Config} */
|
2 |
+
export default {
|
3 |
+
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
4 |
+
theme: {
|
5 |
+
extend: {
|
6 |
+
colors: {
|
7 |
+
// Primary colors (teal/cyan)
|
8 |
+
primary: {
|
9 |
+
50: '#f0fcfc',
|
10 |
+
100: '#e6fafa',
|
11 |
+
200: '#baf1f1',
|
12 |
+
300: '#7ee6e6',
|
13 |
+
400: '#33d9d9',
|
14 |
+
500: '#14c7c7',
|
15 |
+
600: '#0aa3a3',
|
16 |
+
700: '#087878',
|
17 |
+
800: '#0a5c5c',
|
18 |
+
900: '#0d4747',
|
19 |
+
950: '#032929',
|
20 |
+
},
|
21 |
+
// Secondary colors (darker teal)
|
22 |
+
secondary: {
|
23 |
+
50: '#edfafa',
|
24 |
+
100: '#d5f5f5',
|
25 |
+
200: '#aae9e9',
|
26 |
+
300: '#6ed7d7',
|
27 |
+
400: '#2cb9b9',
|
28 |
+
500: '#1a9e9e',
|
29 |
+
600: '#0d7f7f',
|
30 |
+
700: '#0b6666',
|
31 |
+
800: '#0c4d4d',
|
32 |
+
900: '#0d3f3f',
|
33 |
+
950: '#012424',
|
34 |
+
},
|
35 |
+
// Accent colors (brighter teal)
|
36 |
+
accent: {
|
37 |
+
50: '#ebfffe',
|
38 |
+
100: '#cefffd',
|
39 |
+
200: '#9fffff',
|
40 |
+
300: '#58fffd',
|
41 |
+
400: '#14fff9',
|
42 |
+
500: '#00e6e0',
|
43 |
+
600: '#00b8b4',
|
44 |
+
700: '#009290',
|
45 |
+
800: '#007271',
|
46 |
+
900: '#005e5d',
|
47 |
+
950: '#003534',
|
48 |
+
},
|
49 |
+
// Background colors
|
50 |
+
background: {
|
51 |
+
dark: '#000000',
|
52 |
+
DEFAULT: '#000000',
|
53 |
+
light: '#000000',
|
54 |
+
},
|
55 |
+
// Text colors
|
56 |
+
text: {
|
57 |
+
primary: '#ffffff',
|
58 |
+
secondary: '#a3a3a3',
|
59 |
+
muted: '#525252',
|
60 |
+
},
|
61 |
+
},
|
62 |
+
fontFamily: {
|
63 |
+
sans: ['Space Grotesk', 'system-ui', 'sans-serif'],
|
64 |
+
},
|
65 |
+
animation: {
|
66 |
+
'glow-pulse': 'glow-pulse 3s ease-in-out infinite',
|
67 |
+
'float-slow': 'float 8s ease-in-out infinite',
|
68 |
+
'float-medium': 'float 6s ease-in-out infinite',
|
69 |
+
'float-fast': 'float 4s ease-in-out infinite',
|
70 |
+
},
|
71 |
+
keyframes: {
|
72 |
+
'glow-pulse': {
|
73 |
+
'0%, 100%': { opacity: 0.7, filter: 'blur(8px)' },
|
74 |
+
'50%': { opacity: 1, filter: 'blur(12px)' },
|
75 |
+
},
|
76 |
+
float: {
|
77 |
+
'0%, 100%': { transform: 'translateY(0px)' },
|
78 |
+
'50%': { transform: 'translateY(-20px)' },
|
79 |
+
},
|
80 |
+
},
|
81 |
+
backgroundImage: {
|
82 |
+
'radial-gradient': 'radial-gradient(circle at center, var(--tw-gradient-stops))',
|
83 |
+
'conic-gradient': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
|
84 |
+
'grain': "url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.1'/%3E%3C/svg%3E\")",
|
85 |
+
},
|
86 |
+
},
|
87 |
+
},
|
88 |
+
plugins: [],
|
89 |
+
};
|
project 2/tsconfig.app.json
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"compilerOptions": {
|
3 |
+
"target": "ES2020",
|
4 |
+
"useDefineForClassFields": true,
|
5 |
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
6 |
+
"module": "ESNext",
|
7 |
+
"skipLibCheck": true,
|
8 |
+
|
9 |
+
/* Bundler mode */
|
10 |
+
"moduleResolution": "bundler",
|
11 |
+
"allowImportingTsExtensions": true,
|
12 |
+
"isolatedModules": true,
|
13 |
+
"moduleDetection": "force",
|
14 |
+
"noEmit": true,
|
15 |
+
"jsx": "react-jsx",
|
16 |
+
|
17 |
+
/* Linting */
|
18 |
+
"strict": true,
|
19 |
+
"noUnusedLocals": true,
|
20 |
+
"noUnusedParameters": true,
|
21 |
+
"noFallthroughCasesInSwitch": true
|
22 |
+
},
|
23 |
+
"include": ["src"]
|
24 |
+
}
|
project 2/tsconfig.json
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"files": [],
|
3 |
+
"references": [
|
4 |
+
{ "path": "./tsconfig.app.json" },
|
5 |
+
{ "path": "./tsconfig.node.json" }
|
6 |
+
]
|
7 |
+
}
|
project 2/tsconfig.node.json
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"compilerOptions": {
|
3 |
+
"target": "ES2022",
|
4 |
+
"lib": ["ES2023"],
|
5 |
+
"module": "ESNext",
|
6 |
+
"skipLibCheck": true,
|
7 |
+
|
8 |
+
/* Bundler mode */
|
9 |
+
"moduleResolution": "bundler",
|
10 |
+
"allowImportingTsExtensions": true,
|
11 |
+
"isolatedModules": true,
|
12 |
+
"moduleDetection": "force",
|
13 |
+
"noEmit": true,
|
14 |
+
|
15 |
+
/* Linting */
|
16 |
+
"strict": true,
|
17 |
+
"noUnusedLocals": true,
|
18 |
+
"noUnusedParameters": true,
|
19 |
+
"noFallthroughCasesInSwitch": true
|
20 |
+
},
|
21 |
+
"include": ["vite.config.ts"]
|
22 |
+
}
|
project 2/vite.config.ts
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { defineConfig } from 'vite';
|
2 |
+
import react from '@vitejs/plugin-react';
|
3 |
+
|
4 |
+
// https://vitejs.dev/config/
|
5 |
+
export default defineConfig({
|
6 |
+
plugins: [react()],
|
7 |
+
optimizeDeps: {
|
8 |
+
exclude: ['lucide-react'],
|
9 |
+
},
|
10 |
+
});
|