Skip to content

Commit fedb1bb

Browse files
committed
feat: enhance HeroSection and CTA components with project estimator link, update login page styles, and improve contact form prefill functionality
1 parent 4ea2954 commit fedb1bb

15 files changed

Lines changed: 1171 additions & 92 deletions

File tree

src/app/(public)/HeroSection.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Link from "next/link";
12
import { Heading, ScrollDownButton } from "@/components";
23
import { SlideUp } from "@/components/animations/SlideUp";
34
import { FadeIn } from "@/components/animations/FadeIn";
@@ -52,18 +53,27 @@ export function HeroSection() {
5253
We design and build high-performance custom websites to grow your
5354
business online.
5455
</p>
55-
<SmoothScrollLink
56-
href="#cta"
57-
className="group text-black-1 hover:text-accent inline-flex items-center gap-x-2 text-sm font-medium transition-colors duration-300"
58-
>
59-
<span className="relative">
60-
Get in touch
61-
<span className="bg-accent absolute bottom-0 left-0 h-[1px] w-full origin-left scale-x-0 transition-transform duration-500 ease-[cubic-bezier(0.16,1,0.3,1)] group-hover:scale-x-100" />
62-
</span>
63-
<span className="text-lg"></span>
64-
</SmoothScrollLink>
56+
<div className="flex flex-wrap items-center gap-6">
57+
<Link
58+
href="/estimator"
59+
className="hover:text-white inline-flex items-center border border-black-1/20 px-8 py-3 text-sm font-medium tracking-[0.15em] text-black uppercase transition-all duration-300 hover:bg-black-1"
60+
>
61+
Estimate Project
62+
</Link>
63+
<SmoothScrollLink
64+
href="#cta"
65+
className="group text-zinc-500 hover:text-black-1 inline-flex items-center gap-x-2 text-sm font-medium transition-colors duration-300"
66+
>
67+
<span className="relative">
68+
Get in touch
69+
<span className="bg-accent absolute bottom-0 left-0 h-[1px] w-full origin-left scale-x-0 transition-transform duration-500 ease-[cubic-bezier(0.16,1,0.3,1)] group-hover:scale-x-100" />
70+
</span>
71+
<span className="text-lg"></span>
72+
</SmoothScrollLink>
73+
</div>
6574
</SlideUp>
6675

76+
6777
{/* Scroll indicator */}
6878
<FadeIn
6979
delay={1.5}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import ProjectEstimator from "@/components/organisms/estimator/ProjectEstimator";
2+
import { Metadata } from "next";
3+
4+
export const metadata: Metadata = {
5+
title: "Interactive Project Estimator | Devix",
6+
description:
7+
"Answer a few questions to get an instant cost estimation for your E-Commerce, Web App, or Company Profile project.",
8+
alternates: {
9+
canonical: "/estimator",
10+
},
11+
};
12+
13+
export default function EstimatorPage() {
14+
return (
15+
<div className="grain-overlay relative min-h-screen bg-white text-black-1">
16+
{/* Decorative Glows */}
17+
<div className="pointer-events-none absolute inset-0 z-0 overflow-hidden">
18+
<div className="absolute -top-[10%] left-[10%] h-[600px] w-[600px] rounded-full bg-accent/10 blur-[150px]" />
19+
<div className="absolute top-[30%] right-[5%] h-[500px] w-[500px] rounded-full bg-blue-500/5 blur-[120px]" />
20+
</div>
21+
22+
<div className="relative z-10 flex flex-col pt-28 pb-16 md:pt-36 md:pb-24">
23+
<ProjectEstimator />
24+
</div>
25+
</div>
26+
);
27+
}

src/app/admin/login/page.tsx

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { Suspense, useState, useTransition, useEffect } from "react";
44
import { useRouter, useSearchParams } from "next/navigation";
5+
import Link from "next/link";
56
import { loginAdmin } from "@/actions/admin/auth";
67
function LoginContent() {
78
const router = useRouter();
@@ -53,20 +54,29 @@ function LoginContent() {
5354
};
5455

5556
return (
56-
<div className="relative w-full max-w-md border border-zinc-800 bg-[#0F0F0F] p-8 transition-all duration-300 md:p-12">
57+
<div className="relative w-full max-w-md border border-zinc-200 bg-white p-8 pt-16 transition-all duration-300 md:p-12 md:pt-16 shadow-sm">
58+
{/* Back to Home Button */}
59+
<Link
60+
href="/"
61+
className="group absolute top-6 left-6 inline-flex items-center gap-x-1.5 text-xs text-zinc-500 hover:text-black-1 transition-colors duration-300"
62+
>
63+
<span className="text-[14px] font-medium transition-transform duration-300 group-hover:-translate-x-0.5"></span>
64+
<span>Back to Site</span>
65+
</Link>
66+
5767
{/* Header */}
5868
<div className="mb-8 text-center">
5969
<span className="mb-3 block text-[11px] font-medium tracking-[0.25em] text-zinc-500 uppercase">
6070
Devix Operations
6171
</span>
62-
<h1 className="font-display text-2xl font-light tracking-wide text-zinc-100 md:text-3xl">
72+
<h1 className="font-display text-2xl font-light tracking-wide text-zinc-900 md:text-3xl">
6373
Control Panel Login
6474
</h1>
6575
</div>
6676

6777
{/* Error Alert */}
6878
{errorMessage && (
69-
<div className="mb-6 border-l border-red-500 bg-red-950/20 p-4 font-sans text-xs leading-relaxed text-red-400">
79+
<div className="mb-6 border-l border-red-500 bg-red-50 p-4 font-sans text-xs leading-relaxed text-red-600">
7080
{errorMessage}
7181
</div>
7282
)}
@@ -79,7 +89,7 @@ function LoginContent() {
7989
<div className="space-y-2">
8090
<label
8191
htmlFor="email"
82-
className="block text-[11px] font-medium tracking-wider text-zinc-400 uppercase"
92+
className="block text-[11px] font-medium tracking-wider text-zinc-500 uppercase"
8393
>
8494
Email Address
8595
</label>
@@ -91,14 +101,14 @@ function LoginContent() {
91101
disabled={isPending}
92102
placeholder="name@company.com"
93103
required
94-
className="w-full rounded-none border border-zinc-800 bg-[#141414] px-4 py-3 text-sm text-white placeholder-zinc-600 transition-colors duration-300 focus:border-[#C8A96E] focus:outline-none"
104+
className="w-full rounded-none border border-zinc-200 bg-zinc-50 px-4 py-3 text-sm text-zinc-900 placeholder-zinc-400 transition-all duration-300 focus:border-[#C8A96E] focus:bg-white focus:outline-none"
95105
/>
96106
</div>
97107

98108
<div className="space-y-2">
99109
<label
100110
htmlFor="password"
101-
className="block text-[11px] font-medium tracking-wider text-zinc-400 uppercase"
111+
className="block text-[11px] font-medium tracking-wider text-zinc-500 uppercase"
102112
>
103113
Password
104114
</label>
@@ -110,14 +120,14 @@ function LoginContent() {
110120
disabled={isPending}
111121
placeholder="••••••••"
112122
required
113-
className="w-full rounded-none border border-zinc-800 bg-[#141414] px-4 py-3 text-sm text-white placeholder-zinc-600 transition-colors duration-300 focus:border-[#C8A96E] focus:outline-none"
123+
className="w-full rounded-none border border-zinc-200 bg-zinc-50 px-4 py-3 text-sm text-zinc-900 placeholder-zinc-400 transition-all duration-300 focus:border-[#C8A96E] focus:bg-white focus:outline-none"
114124
/>
115125
</div>
116126

117127
<button
118128
type="submit"
119129
disabled={isPending}
120-
className="flex w-full items-center justify-center gap-2 bg-[#C8A96E] py-4 font-sans text-xs font-medium tracking-[0.2em] text-black uppercase transition-colors duration-300 hover:bg-[#B6965C] disabled:bg-zinc-800 disabled:text-zinc-500"
130+
className="flex w-full items-center justify-center gap-2 bg-[#C8A96E] py-4 font-sans text-xs font-medium tracking-[0.2em] text-black uppercase transition-colors duration-300 hover:bg-[#B6965C] disabled:bg-zinc-100 disabled:text-zinc-400"
121131
>
122132
{isPending ? "Verifying..." : "Authenticate"}
123133
</button>
@@ -128,12 +138,12 @@ function LoginContent() {
128138

129139
export default function AdminLoginPage() {
130140
return (
131-
<div className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-[#0A0A0A] px-6 text-white selection:bg-[#C8A96E]/30 selection:text-white">
141+
<div className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-zinc-50 px-6 text-zinc-900 selection:bg-[#C8A96E]/30 selection:text-zinc-900">
132142
{/* Background Decorative Grain/Gradient */}
133-
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-zinc-700 via-zinc-900 to-black opacity-20" />
143+
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-zinc-200 via-zinc-100 to-white opacity-40" />
134144
<Suspense
135145
fallback={
136-
<div className="text-xs tracking-widest text-zinc-500 uppercase">
146+
<div className="text-xs tracking-widest text-zinc-400 uppercase">
137147
Loading interface...
138148
</div>
139149
}
@@ -143,3 +153,4 @@ export default function AdminLoginPage() {
143153
</div>
144154
);
145155
}
156+

src/components/molecules/CTA.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Link from "next/link";
12
import { Heading } from "@/components/atoms";
23
import { SlideUp } from "@/components/animations/SlideUp";
34
import { FadeIn } from "@/components/animations/FadeIn";
@@ -57,14 +58,27 @@ export default function CTA() {
5758
delay={0.3}
5859
duration={0.6}
5960
>
60-
<SmoothScrollLink
61-
href="#contact"
62-
className="hover:text-black-1 inline-flex items-center border border-white/30 px-10 py-4 text-sm font-medium tracking-[0.15em] text-white uppercase transition-all duration-400 hover:bg-white"
63-
>
64-
Contact us
65-
</SmoothScrollLink>
61+
<div className="flex flex-wrap items-center justify-center gap-6">
62+
<Link
63+
href="/estimator"
64+
className="hover:text-black-1 inline-flex items-center border border-white/30 px-10 py-4 text-sm font-medium tracking-[0.15em] text-white uppercase transition-all duration-400 hover:bg-white"
65+
>
66+
Estimate Project
67+
</Link>
68+
<SmoothScrollLink
69+
href="#contact"
70+
className="group inline-flex items-center gap-x-2 text-sm font-medium text-zinc-400 transition-colors duration-300 hover:text-white"
71+
>
72+
<span className="relative">
73+
Contact us
74+
<span className="bg-accent absolute bottom-0 left-0 h-[1px] w-full origin-left scale-x-0 transition-transform duration-500 ease-[cubic-bezier(0.16,1,0.3,1)] group-hover:scale-x-100" />
75+
</span>
76+
<span className="text-lg"></span>
77+
</SmoothScrollLink>
78+
</div>
6679
</FadeIn>
6780
</div>
6881
</section>
6982
);
7083
}
84+

src/components/molecules/ContactForm.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { useState, useTransition } from "react";
3+
import { useState, useTransition, useEffect } from "react";
44
import { submitContactForm } from "@/actions/contact";
55
import { m, AnimatePresence } from "framer-motion";
66
import { Loader2, Check } from "lucide-react";
@@ -13,6 +13,23 @@ export function ContactForm() {
1313
const [success, setSuccess] = useState(false);
1414
const [isPending, startTransition] = useTransition();
1515

16+
useEffect(() => {
17+
// Safely parse URL params on client mount to prefill form from estimator
18+
if (typeof window !== "undefined") {
19+
const params = new URLSearchParams(window.location.search);
20+
const type = params.get("type") || "Not specified";
21+
const scope = params.get("scope") || "Not specified";
22+
const complexity = params.get("complexity") || "Not specified";
23+
const timeline = params.get("timeline") || "Not specified";
24+
const budget = params.get("budget");
25+
26+
if (type !== "Not specified" || budget) {
27+
const prefilledMessage = `Hi Devix Team,\n\nI would like to inquire about a new project based on my estimator results:\n\n- Project Type: ${type}\n- Scope: ${scope}\n- Complexity: ${complexity}\n- Timeline: ${timeline}\n- Estimated Budget: ${budget || "Not specified"}\n\nHere are some additional details about my project: `;
28+
setMessage(prefilledMessage);
29+
}
30+
}
31+
}, []);
32+
1633
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
1734
e.preventDefault();
1835
setErrorMsg("");
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import type { EstimatorState, ProjectComplexity } from "@/types/estimator";
2+
import { LayoutTemplate, Sparkles, Gem } from "lucide-react";
3+
import type { ReactNode } from "react";
4+
5+
interface StepComplexityProps {
6+
state: EstimatorState;
7+
updateState: (updates: Partial<EstimatorState>) => void;
8+
onNext: () => void;
9+
onBack: () => void;
10+
}
11+
12+
const COMPLEXITY_OPTIONS: { id: ProjectComplexity; label: string; icon: ReactNode; description: string }[] = [
13+
{
14+
id: "basic",
15+
label: "Basic",
16+
icon: <LayoutTemplate className="h-8 w-8" />,
17+
description: "Clean, minimal design with standard components and fast loading times.",
18+
},
19+
{
20+
id: "standard",
21+
label: "Standard",
22+
icon: <Sparkles className="h-8 w-8" />,
23+
description: "Modern design with smooth transitions and engaging micro-interactions.",
24+
},
25+
{
26+
id: "premium",
27+
label: "Premium",
28+
icon: <Gem className="h-8 w-8" />,
29+
description: "Award-winning level design, complex 3D animations, and bespoke UI.",
30+
},
31+
];
32+
33+
export function StepComplexity({ state, updateState, onNext, onBack }: StepComplexityProps) {
34+
return (
35+
<div className="flex flex-col h-full">
36+
<div className="mb-8">
37+
<h2 className="text-2xl font-light text-zinc-900">What level of design & animation?</h2>
38+
<p className="mt-2 text-zinc-500">Choose the complexity of the user interface and animations.</p>
39+
</div>
40+
41+
<div className="grid gap-4 sm:grid-cols-1 md:grid-cols-3 mb-8">
42+
{COMPLEXITY_OPTIONS.map((option) => {
43+
const isSelected = state.complexity === option.id;
44+
return (
45+
<button
46+
key={option.id}
47+
onClick={() => updateState({ complexity: option.id })}
48+
className={`group relative flex flex-col items-start rounded-xl border p-6 text-left transition-all duration-300 ${
49+
isSelected
50+
? "border-accent bg-accent/10 shadow-[0_0_20px_rgba(var(--color-accent),0.05)]"
51+
: "border-zinc-200 bg-white hover:border-zinc-300 hover:bg-zinc-50"
52+
}`}
53+
>
54+
<div className={`mb-4 rounded-lg p-3 transition-colors ${isSelected ? "bg-accent text-white" : "bg-zinc-100 text-zinc-500 group-hover:text-zinc-700"}`}>
55+
{option.icon}
56+
</div>
57+
<h3 className={`text-lg font-medium ${isSelected ? "text-accent" : "text-zinc-900"}`}>
58+
{option.label}
59+
</h3>
60+
<p className="mt-2 text-sm text-zinc-500 leading-relaxed">
61+
{option.description}
62+
</p>
63+
64+
{isSelected && (
65+
<div className="absolute top-4 right-4 h-3 w-3 rounded-full bg-accent animate-pulse" />
66+
)}
67+
</button>
68+
);
69+
})}
70+
</div>
71+
72+
<div className="mt-auto flex justify-between">
73+
<button
74+
onClick={onBack}
75+
className="group relative inline-flex items-center gap-x-2 rounded-full border border-zinc-200 bg-transparent px-8 py-3 text-sm font-medium text-zinc-600 transition-colors hover:bg-zinc-50 hover:text-black"
76+
>
77+
<span className="transition-transform duration-300 group-hover:-translate-x-1"></span>
78+
<span>Back</span>
79+
</button>
80+
<button
81+
onClick={onNext}
82+
disabled={!state.complexity}
83+
className="group relative inline-flex items-center gap-x-2 rounded-full bg-black px-8 py-3 text-sm font-medium text-white transition-transform disabled:opacity-50 disabled:cursor-not-allowed hover:scale-105 active:scale-95 hover:bg-zinc-800"
84+
>
85+
<span>Continue</span>
86+
<span className="transition-transform duration-300 group-hover:translate-x-1"></span>
87+
</button>
88+
</div>
89+
</div>
90+
);
91+
}

0 commit comments

Comments
 (0)