Skip to content

Commit 182fcb1

Browse files
feat(ui): enhance footer, login modal, add contact button, privacy & terms
1 parent b026b32 commit 182fcb1

11 files changed

Lines changed: 607 additions & 157 deletions

src/app/globals.css

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ body {
194194
animation: float 3s ease-in-out infinite;
195195
}
196196

197+
/* Slow spin animation for decorative elements */
198+
.animate-spin-slow {
199+
animation: spin-slow 20s linear infinite;
200+
}
201+
197202
@keyframes float {
198203
0%,
199204
100% {
@@ -204,6 +209,15 @@ body {
204209
}
205210
}
206211

212+
@keyframes spin-slow {
213+
from {
214+
transform: translate(-50%, -50%) rotate(0deg);
215+
}
216+
to {
217+
transform: translate(-50%, -50%) rotate(360deg);
218+
}
219+
}
220+
207221
/* Hover lift effect - elements rise on hover */
208222
.hover-lift {
209223
@apply transition-all duration-300 hover:-translate-y-1 hover:shadow-lg;
@@ -312,7 +326,20 @@ body {
312326
animation: shake 0.3s ease-in-out;
313327
}
314328

315-
/* Grid slide animation using background-position for CSS gradients */
329+
/* Enhanced close button styling for dialogs */
330+
[data-slot="dialog-close"] {
331+
cursor: pointer !important;
332+
border-radius: 0.375rem !important;
333+
transition: all 0.2s ease !important;
334+
}
335+
336+
[data-slot="dialog-close"]:hover {
337+
border-radius: 50% !important;
338+
background-color: hsl(var(--muted)) !important;
339+
transform: scale(1.1) !important;
340+
}
341+
342+
/* Grid slide animation using background-position for CSS gradients */
316343
@keyframes grid-slide {
317344
from {
318345
background-position: 0 0;

src/components/ClientLayoutShell.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import { usePathname } from "next/navigation";
33
import { ProjectStackDock } from "@/components/ProjectStackNavbar";
44
import { CreateProjectModal } from "@/components/CreateProjectModal";
55
import { LoginModal } from "@/components/LoginModal";
6+
import { FloatingContactButton } from "@/components/FloatingContactButton";
67
import { useState, useEffect } from "react";
78
import { useSession } from "next-auth/react";
89
import { Toaster } from "sonner";
9-
import DemoOne from "@/components/ShaderBackground";
1010
import { Shader } from "./Shader";
1111

1212
type ClientLayoutShellProps = {
@@ -44,7 +44,6 @@ export function ClientLayoutShell({ children }: ClientLayoutShellProps) {
4444

4545
const handleCreateClick = () => {
4646
if (session) {
47-
// Check if user is onboarded (profileId is set)
4847
if (!profileId) {
4948
window.location.href = "/onboarding";
5049
return;
@@ -71,6 +70,7 @@ export function ClientLayoutShell({ children }: ClientLayoutShellProps) {
7170
userImage={session?.user?.image}
7271
/>
7372
)}
73+
<FloatingContactButton />
7474
<CreateProjectModal
7575
open={isCreateModalOpen}
7676
onClose={() => setIsCreateModalOpen(false)}

src/components/FAQSection.tsx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, { useState } from 'react';
22
import { ChevronDown } from 'lucide-react';
3-
import Link from 'next/link';
43

54
const FAQSection: React.FC = () => {
65
const [openIndex, setOpenIndex] = useState<number | null>(null);
@@ -42,11 +41,9 @@ const FAQSection: React.FC = () => {
4241

4342
return (
4443
<section className="py-20 px-4 pt-38 relative ">
45-
{/* Background gradient */}
4644
<div className="absolute inset-0 from-background via-muted to-background opacity-50"></div>
4745

4846
<div className="max-w-4xl mx-auto relative z-10">
49-
{/* Section Header */}
5047
<div className="text-center mb-12 space-y-4">
5148
<h2 className="text-4xl md:text-5xl font-bold text-foreground">
5249
Frequently Asked{' '}
@@ -59,7 +56,6 @@ const FAQSection: React.FC = () => {
5956
</p>
6057
</div>
6158

62-
{/* FAQ Items */}
6359
<div className="space-y-4">
6460
{faqs.map((faq, index) => (
6561
<div
@@ -69,7 +65,6 @@ const FAQSection: React.FC = () => {
6965
: 'bg-card/50 border-border'
7066
}`}
7167
>
72-
{/* Question */}
7368
<button
7469
onClick={() => toggleFAQ(index)}
7570
className="w-full px-6 py-5 flex items-center cursor-pointer justify-between text-left transition-all duration-300 group"
@@ -86,7 +81,6 @@ const FAQSection: React.FC = () => {
8681
/>
8782
</button>
8883

89-
{/* Answer */}
9084
<div
9185
className={`overflow-hidden transition-all duration-300 ${openIndex === index ? 'max-h-96' : 'max-h-0'
9286
}`}
@@ -98,23 +92,13 @@ const FAQSection: React.FC = () => {
9892
</div>
9993
</div>
10094

101-
{/* Accent line */}
10295
{openIndex === index && (
10396
<div className="h-1 animate-pulse bg-gradient-to-r from-primary to-secondary"></div>
10497
)}
10598
</div>
10699
))}
107100
</div>
108101

109-
{/* Call to action */}
110-
<div className="mt-12 text-center">
111-
<p className="text-muted-foreground mb-4">
112-
Still have questions?
113-
</p>
114-
<button className="px-8 py-3 rounded-full font-semibold transition-all duration-300 hover:scale-105 bg-secondary text-secondary-foreground shadow-lg shadow-secondary/30 cursor-pointer">
115-
<Link href="/contact">Contact Us</Link>
116-
</button>
117-
</div>
118102
</div>
119103
</section>
120104
);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"use client";
2+
3+
import { Phone } from "lucide-react";
4+
import { cn } from "@/lib/utils";
5+
6+
export function FloatingContactButton() {
7+
return (
8+
<a
9+
href="/contact"
10+
className={cn(
11+
"fixed bottom-8 right-8 z-50",
12+
"w-12 h-12 bg-primary hover:bg-primary/90",
13+
"rounded-full shadow-lg hover:shadow-xl",
14+
"flex items-center justify-center",
15+
"transition-all duration-300 ease-out",
16+
"hover:scale-110 active:scale-95",
17+
"group"
18+
)}
19+
>
20+
<Phone
21+
className={cn(
22+
"w-4 h-4 text-primary-foreground",
23+
"transition-transform duration-300",
24+
"group-hover:rotate-12"
25+
)}
26+
/>
27+
<span className="sr-only">Contact</span>
28+
</a>
29+
);
30+
}

src/components/Footer.tsx

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import React, { useState } from "react";
2+
import { Github, Linkedin, Instagram } from "lucide-react";
3+
import { LegalModal } from "./LegalModal";
4+
import PrivacyPolicyContent from "./legal/PrivacyPolicyContent";
5+
import TermsOfUseContent from "./legal/TermsOfUseContent";
6+
7+
export default function Footer() {
8+
const [activeModal, setActiveModal] = useState<"privacy" | "terms" | null>(null);
9+
10+
const openModal = (type: "privacy" | "terms") => {
11+
setActiveModal(type);
12+
};
13+
14+
const closeModal = () => {
15+
setActiveModal(null);
16+
};
17+
18+
return (
19+
<>
20+
<footer className="relative pointer-events-auto" style={{ zIndex: 2 }}>
21+
<div className="w-full h-px bg-gradient-to-r from-transparent via-border/60 to-transparent" />
22+
23+
<div className="bg-background/30 backdrop-blur-2xl">
24+
<div className="max-w-6xl mx-auto px-6 pt-16 pb-10">
25+
26+
<div className="flex flex-col lg:flex-row justify-between gap-12 pb-12 border-b border-border/20">
27+
28+
<div className="flex flex-col gap-4 max-w-xs">
29+
<span className="text-xl font-bold tracking-tight text-foreground">
30+
Project<span className="text-primary">Stack</span>
31+
</span>
32+
<p className="text-sm text-muted-foreground/60 leading-relaxed">
33+
Where students and creators come together to build the next big thing.
34+
</p>
35+
<div className="flex items-center gap-3">
36+
<a
37+
href="https://github.com/Ajiet-DevNation/project_stack"
38+
target="_blank"
39+
rel="noopener noreferrer"
40+
className="group inline-flex items-center justify-center w-10 h-10 rounded-full border border-border/40 hover:border-primary/40 bg-card/40 hover:bg-card/70 backdrop-blur transition-all duration-300 text-muted-foreground/70 hover:text-foreground"
41+
aria-label="GitHub"
42+
>
43+
<Github className="w-4 h-4 group-hover:text-primary transition-colors duration-300" />
44+
</a>
45+
<a
46+
href="https://www.linkedin.com/company/project-stack"
47+
target="_blank"
48+
rel="noopener noreferrer"
49+
className="group inline-flex items-center justify-center w-10 h-10 rounded-full border border-border/40 hover:border-primary/40 bg-card/40 hover:bg-card/70 backdrop-blur transition-all duration-300 text-muted-foreground/70 hover:text-foreground"
50+
aria-label="LinkedIn"
51+
>
52+
<Linkedin className="w-4 h-4 group-hover:text-primary transition-colors duration-300" />
53+
</a>
54+
<a
55+
href="https://instagram.com/projectstack"
56+
target="_blank"
57+
rel="noopener noreferrer"
58+
className="group inline-flex items-center justify-center w-10 h-10 rounded-full border border-border/40 hover:border-primary/40 bg-card/40 hover:bg-card/70 backdrop-blur transition-all duration-300 text-muted-foreground/70 hover:text-foreground"
59+
aria-label="Instagram"
60+
>
61+
<Instagram className="w-4 h-4 group-hover:text-primary transition-colors duration-300" />
62+
</a>
63+
</div>
64+
</div>
65+
66+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-10 text-sm">
67+
{[
68+
{
69+
heading: "Community",
70+
links: ["DevNation", "Discord"],
71+
},
72+
{
73+
heading: "Legal",
74+
links: ["Privacy Policy", "Terms of Use"],
75+
},
76+
].map(({ heading, links }) => (
77+
<div key={heading} className="flex flex-col gap-4">
78+
<span className="text-xs font-semibold uppercase tracking-widest text-muted-foreground/40">
79+
{heading}
80+
</span>
81+
<ul className="flex flex-col gap-3">
82+
{links.map((item) => {
83+
const handleClick = (e: React.MouseEvent) => {
84+
e.preventDefault();
85+
if (item === "Privacy Policy") {
86+
openModal("privacy");
87+
} else if (item === "Terms of Use") {
88+
openModal("terms");
89+
} else if (item === "Discord") {
90+
window.open("https://discord.gg/nzC2kaRf", "_blank");
91+
} else if (item === "DevNation") {
92+
window.open("https://github.com/Ajiet-DevNation", "_blank");
93+
} else {
94+
console.log(`Navigate to: ${item}`);
95+
}
96+
};
97+
98+
return (
99+
<li key={item}>
100+
<button
101+
onClick={handleClick}
102+
className="text-muted-foreground/60 hover:text-foreground transition-colors duration-200 hover:translate-x-0.5 inline-block text-left w-full cursor-pointer"
103+
>
104+
{item}
105+
</button>
106+
</li>
107+
);
108+
})}
109+
</ul>
110+
</div>
111+
))}
112+
</div>
113+
</div>
114+
115+
<div className="flex flex-col sm:flex-row items-center justify-between gap-2 pt-8">
116+
<p className="text-xs text-muted-foreground/35 tracking-wide">
117+
© {new Date().getFullYear()} ProjectStack. All rights reserved.
118+
</p>
119+
<p className="text-xs text-muted-foreground/35 tracking-wide">
120+
A proud initiative under{" "}
121+
<span className="text-primary/60 font-medium">DevNation</span>
122+
</p>
123+
</div>
124+
125+
</div>
126+
</div>
127+
</footer>
128+
129+
<LegalModal
130+
isOpen={activeModal === "privacy"}
131+
onClose={closeModal}
132+
title="Privacy Policy"
133+
>
134+
<PrivacyPolicyContent />
135+
</LegalModal>
136+
137+
<LegalModal
138+
isOpen={activeModal === "terms"}
139+
onClose={closeModal}
140+
title="Terms of Use"
141+
>
142+
<TermsOfUseContent />
143+
</LegalModal>
144+
</>
145+
);
146+
}

0 commit comments

Comments
 (0)