diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index a81600c2..88e1fc4a 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -1702,7 +1702,7 @@ "version": "19.2.13", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.13.tgz", "integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -1724,6 +1724,14 @@ "integrity": "sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==", "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@types/use-sync-external-store": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", @@ -2428,6 +2436,16 @@ "dev": true, "license": "MIT" }, + "node_modules/dompurify": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", @@ -3609,6 +3627,19 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -3689,6 +3720,17 @@ "node": "*" } }, + "node_modules/monaco-editor": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", + "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "license": "MIT", + "peer": true, + "dependencies": { + "dompurify": "3.2.7", + "marked": "14.0.0" + } + }, "node_modules/motion-dom": { "version": "12.33.0", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.33.0.tgz", diff --git a/Frontend/src/App.jsx b/Frontend/src/App.jsx index eedfc318..ef018804 100644 --- a/Frontend/src/App.jsx +++ b/Frontend/src/App.jsx @@ -38,6 +38,7 @@ import CookiePolicy from "./pages/CookiePolicy"; import ScrollToTopOnRouteChange from "./components/shared/ScrollToTopOnRouteChange"; import Navbar from "./components/Navbar"; import { useEffect } from "react"; +import Lenis from "@studio-freight/lenis"; function App() { const location = useLocation(); @@ -45,6 +46,31 @@ function App() { const hideFooterRoutes = ["/login", "/register"]; const hideFooter = hideFooterRoutes.includes(location.pathname); + // Initialize smooth scrolling with Lenis + useEffect(() => { + const lenis = new Lenis({ + duration: 1.2, + easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), + direction: "vertical", + gestureDirection: "vertical", + smooth: true, + smoothTouch: false, + touchMultiplier: 2, + }); + + function raf(time) { + lenis.raf(time); + requestAnimationFrame(raf); + } + + requestAnimationFrame(raf); + + return () => { + lenis.destroy(); + }; + }, []); + + useEffect(() => { const hideNavbarRoutes = ["/dashboard", "/settings", "/pricing", "/career", "/terms", "/privacy", "/cookie-policy", "/interview-setup", "/auth/callback"]; const hideNavbar = hideNavbarRoutes.includes(location.pathname) || diff --git a/Frontend/src/index.css b/Frontend/src/index.css index b830c02a..d1615f2b 100644 --- a/Frontend/src/index.css +++ b/Frontend/src/index.css @@ -2,6 +2,30 @@ @tailwind components; @tailwind utilities; +/* Smooth scrolling setup */ +html { + scroll-behavior: smooth; +} + +html.lenis { + height: auto; +} + +.lenis.lenis-smooth { + scroll-behavior: auto; +} + +.lenis.lenis-smooth [data-lenis-prevent] { + overscroll-behavior: contain; +} + +.lenis.lenis-stopped { + overflow: hidden; +} + +.lenis.lenis-scrolling iframe { + pointer-events: none; +} /* Hide scrollbar but keep scrolling */ ::-webkit-scrollbar { @@ -9,8 +33,6 @@ height: 0px; } - - /* Toast Animations */ @keyframes slide-in-right { 0% { @@ -41,7 +63,6 @@ border-radius: 10px; } - /* NEON GRADIENT TEXT */ .gradient-text { background: linear-gradient(135deg, #ff7043, #8b5cf6); @@ -87,7 +108,8 @@ } @keyframes shake { - 0%, 100% { + 0%, + 100% { transform: translateX(0); } 25% { @@ -99,7 +121,8 @@ } @keyframes bounce-slow { - 0%, 100% { + 0%, + 100% { transform: translateY(0); } 50% { @@ -141,6 +164,42 @@ } } +@keyframes float { + 0%, + 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-20px); + } +} + +@keyframes pulse-glow { + 0%, + 100% { + box-shadow: 0 0 20px rgba(139, 92, 246, 0.3); + } + 50% { + box-shadow: 0 0 30px rgba(139, 92, 246, 0.6); + } +} + +.animate-pulse-glow { + animation: pulse-glow 2s ease-in-out infinite; +} + +@keyframes gradient-shift { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + /* Apply animations */ .animate-slide-in-right { animation: slide-in-right 0.3s ease-out; @@ -181,8 +240,13 @@ /* Wave animation for sound bars */ @keyframes wave { - 0%, 100% { height: 10px; } - 50% { height: 30px; } + 0%, + 100% { + height: 10px; + } + 50% { + height: 30px; + } } .animate-wave { @@ -191,13 +255,13 @@ /* Slide down animation */ @keyframes slideDown { - from { - opacity: 0; - transform: translateY(-20px); + from { + opacity: 0; + transform: translateY(-20px); } - to { - opacity: 1; - transform: translateY(0); + to { + opacity: 1; + transform: translateY(0); } } @@ -226,13 +290,15 @@ background: white; border-radius: 20px; padding: 2rem; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: + 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); position: relative; overflow: hidden; } .score-card::before { - content: ''; + content: ""; position: absolute; top: 0; left: 0; @@ -557,7 +623,7 @@ } .sw-list li::before { - content: '•'; + content: "•"; position: absolute; left: 0.5rem; color: #9ca3af; @@ -742,7 +808,7 @@ } .position-marker::after { - content: ''; + content: ""; position: absolute; bottom: -8px; left: 50%; @@ -2082,7 +2148,6 @@ text-align: center; } - .certificate-section { max-width: 1000px; margin: 0 auto; @@ -2121,13 +2186,13 @@ background: white; border-radius: 20px; padding: 3rem 2rem; - box-shadow: + box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); position: relative; overflow: hidden; border: 8px solid transparent; - background-image: + background-image: linear-gradient(white, white), linear-gradient(135deg, #667eea, #764ba2, #f093fb, #4facfe); background-origin: border-box; @@ -2140,9 +2205,21 @@ left: 0; right: 0; bottom: 0; - background-image: - repeating-linear-gradient(45deg, transparent, transparent 35px, rgba(102, 126, 234, 0.03) 35px, rgba(102, 126, 234, 0.03) 70px), - repeating-linear-gradient(-45deg, transparent, transparent 35px, rgba(118, 75, 162, 0.03) 35px, rgba(118, 75, 162, 0.03) 70px); + background-image: + repeating-linear-gradient( + 45deg, + transparent, + transparent 35px, + rgba(102, 126, 234, 0.03) 35px, + rgba(102, 126, 234, 0.03) 70px + ), + repeating-linear-gradient( + -45deg, + transparent, + transparent 35px, + rgba(118, 75, 162, 0.03) 35px, + rgba(118, 75, 162, 0.03) 70px + ); pointer-events: none; } @@ -2161,20 +2238,21 @@ display: flex; align-items: center; justify-content: center; - box-shadow: + box-shadow: 0 10px 30px rgba(255, 215, 0, 0.3), inset 0 -3px 10px rgba(0, 0, 0, 0.1); animation: glow 2s ease-in-out infinite; } @keyframes glow { - 0%, 100% { - box-shadow: + 0%, + 100% { + box-shadow: 0 10px 30px rgba(255, 215, 0, 0.3), inset 0 -3px 10px rgba(0, 0, 0, 0.1); } 50% { - box-shadow: + box-shadow: 0 10px 40px rgba(255, 215, 0, 0.5), inset 0 -3px 10px rgba(0, 0, 0, 0.1); } @@ -2216,7 +2294,7 @@ font-size: 2rem; font-weight: 700; color: #1f2937; - font-family: 'Georgia', serif; + font-family: "Georgia", serif; letter-spacing: 1px; } @@ -2253,7 +2331,7 @@ } .score-circle::before { - content: ''; + content: ""; position: absolute; inset: 8px; border-radius: 50%; @@ -2371,7 +2449,7 @@ } .verification-code { - font-family: 'Courier New', monospace; + font-family: "Courier New", monospace; background: #f3f4f6; padding: 0.5rem 0.75rem; border-radius: 6px; @@ -2660,12 +2738,24 @@ animation: slideInUp 0.6s ease-out backwards; } -.certificate-section > *:nth-child(1) { animation-delay: 0.1s; } -.certificate-section > *:nth-child(2) { animation-delay: 0.2s; } -.certificate-section > *:nth-child(3) { animation-delay: 0.3s; } -.certificate-section > *:nth-child(4) { animation-delay: 0.4s; } -.certificate-section > *:nth-child(5) { animation-delay: 0.5s; } -.certificate-section > *:nth-child(6) { animation-delay: 0.6s; } +.certificate-section > *:nth-child(1) { + animation-delay: 0.1s; +} +.certificate-section > *:nth-child(2) { + animation-delay: 0.2s; +} +.certificate-section > *:nth-child(3) { + animation-delay: 0.3s; +} +.certificate-section > *:nth-child(4) { + animation-delay: 0.4s; +} +.certificate-section > *:nth-child(5) { + animation-delay: 0.5s; +} +.certificate-section > *:nth-child(6) { + animation-delay: 0.6s; +} :root { /* Light Theme */ @@ -2704,11 +2794,12 @@ body { background-color: var(--bg-primary); color: var(--text-primary); - transition: background-color 0.3s ease, color 0.3s ease; + transition: + background-color 0.3s ease, + color 0.3s ease; } ::selection { background: #ffcc00; color: #000000; } - diff --git a/Frontend/src/pages/FAQ.jsx b/Frontend/src/pages/FAQ.jsx index dffa5d8f..7098cdc3 100644 --- a/Frontend/src/pages/FAQ.jsx +++ b/Frontend/src/pages/FAQ.jsx @@ -1,72 +1,106 @@ import { Link } from "react-router-dom"; import { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { + ChevronDown, + Sparkles, + HelpCircle, + MessageCircle, + Zap, + Shield, + Rocket, + TrendingUp, + Users, +} from "lucide-react"; + +const categoryIcons = { + ai: Zap, + features: Rocket, + progress: TrendingUp, + security: Shield, + team: Users, + general: MessageCircle, +}; const faqs = [ { + category: "ai", question: "How does AI feedback work?", answer: - "Our AI analyzes your responses in real-time, evaluating clarity, technical accuracy, structure, and completeness. You'll receive instant, actionable feedback on how to improve your answers, just like a real interviewer would provide." + "Our AI analyzes your responses in real-time, evaluating clarity, technical accuracy, structure, and completeness. You'll receive instant, actionable feedback on how to improve your answers, just like a real interviewer would provide.", }, { + category: "features", question: "Can I practice for specific tech roles?", answer: - "Yes! We have role-specific question banks for 50+ tech positions including Frontend, Backend, Full Stack, DevOps, Data Science, ML Engineer, Product Manager, and more. Each role has curated questions that match real interview scenarios." + "Yes! We have role-specific question banks for 50+ tech positions including Frontend, Backend, Full Stack, DevOps, Data Science, ML Engineer, Product Manager, and more. Each role has curated questions that match real interview scenarios.", }, { + category: "progress", question: "How fast will I see improvement?", answer: - "Most users see significant improvement within 1-2 weeks of consistent practice. Our analytics dashboard tracks your progress over time, showing improvements in clarity, technical depth, and structure scores. Practice 3-5 interviews per week for best results." + "Most users see significant improvement within 1-2 weeks of consistent practice. Our analytics dashboard tracks your progress over time, showing improvements in clarity, technical depth, and structure scores. Practice 3-5 interviews per week for best results.", }, { + category: "features", question: "Is voice practice really necessary?", answer: - "Absolutely! Speaking your answers out loud helps you practice articulation, pacing, and confidence. Many candidates freeze during verbal interviews even when they know the answer. Our voice practice feature simulates real interview conditions so you're prepared." + "Absolutely! Speaking your answers out loud helps you practice articulation, pacing, and confidence. Many candidates freeze during verbal interviews even when they know the answer. Our voice practice feature simulates real interview conditions so you're prepared.", }, { + category: "team", question: "Can I use this to prepare my team for interviews?", answer: - "Yes! Our Enterprise plan includes team management features, custom branding, and dedicated support. Perfect for bootcamps, training programs, and companies preparing candidates for technical interviews. Contact our sales team for custom solutions." + "Yes! Our Enterprise plan includes team management features, custom branding, and dedicated support. Perfect for bootcamps, training programs, and companies preparing candidates for technical interviews. Contact our sales team for custom solutions.", }, { + category: "general", question: "What companies do your questions prepare me for?", answer: - "Our question banks are designed to prepare you for interviews at top tech companies including FAANG, Microsoft, startups, and mid-size tech companies. The questions cover common patterns and topics asked across the industry." + "Our question banks are designed to prepare you for interviews at top tech companies including FAANG, Microsoft, startups, and mid-size tech companies. The questions cover common patterns and topics asked across the industry.", }, { + category: "features", question: "Can I retake an interview session?", answer: - "Yes, you can retake interviews as many times as you want. Repeating sessions allows you to refine your answers, improve delivery, and compare performance across attempts using the analytics dashboard." + "Yes, you can retake interviews as many times as you want. Repeating sessions allows you to refine your answers, improve delivery, and compare performance across attempts using the analytics dashboard.", }, { + category: "general", question: "Do I need a webcam and microphone to use Intervyo?", answer: - "For the most realistic experience, we recommend using both a webcam and microphone. Voice input helps simulate real interview conditions. However, certain practice modes may still work without video input." + "For the most realistic experience, we recommend using both a webcam and microphone. Voice input helps simulate real interview conditions. However, certain practice modes may still work without video input.", }, { + category: "ai", question: "How accurate is the AI scoring system?", answer: - "The AI evaluates multiple parameters including structure, clarity, completeness, and technical depth. While it may not fully replace a human interviewer, it closely mirrors real-world technical interview evaluation patterns." + "The AI evaluates multiple parameters including structure, clarity, completeness, and technical depth. While it may not fully replace a human interviewer, it closely mirrors real-world technical interview evaluation patterns.", }, { + category: "progress", question: "Can I track my improvement over time?", answer: - "Yes! The analytics dashboard provides detailed performance tracking, highlighting strengths, weaknesses, and trends across multiple sessions. This helps you focus on areas that need improvement." + "Yes! The analytics dashboard provides detailed performance tracking, highlighting strengths, weaknesses, and trends across multiple sessions. This helps you focus on areas that need improvement.", }, { + category: "security", question: "Is my interview data secure?", answer: - "Yes. We prioritize user privacy and secure data handling. Your interview responses and personal information are stored securely and used only to enhance your practice experience." + "Yes. We prioritize user privacy and secure data handling. Your interview responses and personal information are stored securely and used only to enhance your practice experience.", }, { + category: "general", question: "Is Intervyo free to use?", answer: - "Intervyo offers both free and premium features. You can begin practicing with core functionality for free, while advanced analytics, extended question libraries, and enterprise tools may require a paid plan." - } + "Intervyo offers both free and premium features. You can begin practicing with core functionality for free, while advanced analytics, extended question libraries, and enterprise tools may require a paid plan.", + }, ]; export default function FAQ() { const [scrollY, setScrollY] = useState(0); const [activeIndex, setActiveIndex] = useState(null); + const [hoveredIndex, setHoveredIndex] = useState(null); useEffect(() => { const handleScroll = () => setScrollY(window.scrollY); @@ -78,72 +112,433 @@ export default function FAQ() { setActiveIndex(activeIndex === index ? null : index); }; + const getCategoryColor = (category) => { + const colors = { + ai: "from-violet-500 to-purple-600", + features: "from-blue-500 to-cyan-600", + progress: "from-emerald-500 to-teal-600", + security: "from-rose-500 to-pink-600", + team: "from-orange-500 to-amber-600", + general: "from-indigo-500 to-blue-600", + }; + return colors[category] || colors.general; + }; + + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.08, + delayChildren: 0.2, + }, + }, + }; + + const itemVariants = { + hidden: { opacity: 0, y: 20, scale: 0.95 }, + visible: { + opacity: 1, + y: 0, + scale: 1, + transition: { + type: "spring", + stiffness: 100, + damping: 15, + }, + }, + }; + return ( -