diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 41199fbc9..83ecac012 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -269,17 +269,6 @@ pre { animation: pulse-glow 2s ease-in-out infinite; } -.animate-shimmer { - background: linear-gradient( - 90deg, - rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0.1) 50%, - rgba(255, 255, 255, 0) 100% - ); - background-size: 200% 100%; - animation: shimmer 2s linear infinite; -} - .animate-gradient { background-size: 200% 200%; animation: gradient-shift 8s ease infinite; @@ -379,12 +368,17 @@ pre { rgb(var(--color-primary-dark)) 100% ); color: white; + box-shadow: 0 4px 14px -4px rgba(139, 92, 246, 0.4); } .btn-primary:hover { - opacity: 0.9; - transform: translateY(-1px); - box-shadow: 0 10px 20px -10px rgba(139, 92, 246, 0.5); + transform: translateY(-2px); + box-shadow: 0 12px 24px -8px rgba(139, 92, 246, 0.5); +} + +.btn-primary:active { + transform: translateY(0); + box-shadow: 0 4px 14px -4px rgba(139, 92, 246, 0.4); } .btn-secondary { @@ -550,3 +544,28 @@ pre { radial-gradient(at 0% 100%, rgba(139, 92, 246, 0.1) 0px, transparent 50%), radial-gradient(at 80% 100%, rgba(34, 211, 238, 0.08) 0px, transparent 50%); } + +/* ============================================ + Skeleton Loading (Used by loading states) + ============================================ */ + +.skeleton { + background: linear-gradient( + 90deg, + rgba(255, 255, 255, 0.03) 0%, + rgba(255, 255, 255, 0.08) 50%, + rgba(255, 255, 255, 0.03) 100% + ); + background-size: 200% 100%; + animation: skeleton-shimmer 1.5s ease-in-out infinite; + border-radius: 0.5rem; +} + +@keyframes skeleton-shimmer { + 0% { + background-position: -200% 0; + } + 100% { + background-position: 200% 0; + } +} diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 144f12289..3fdcb554a 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -3,6 +3,7 @@ import Link from 'next/link'; import { useState, useEffect, useRef } from 'react'; import { clsx } from 'clsx'; +import { SuggestedPrompts } from '@/components/ui'; // ============================================ // Animated Counter Component @@ -272,6 +273,165 @@ function TestimonialCard({ ); } +// ============================================ +// Loading Spinner Component +// ============================================ +function LoadingSpinner({ size = 20 }: { size?: number }) { + return ( + + + + + ); +} + +// ============================================ +// Mobile Menu Component +// ============================================ +function MobileMenu({ + isOpen, + onClose +}: { + isOpen: boolean; + onClose: () => void; +}) { + useEffect(() => { + if (isOpen) { + document.body.style.overflow = 'hidden'; + } else { + document.body.style.overflow = ''; + } + return () => { + document.body.style.overflow = ''; + }; + }, [isOpen]); + + return ( + <> + {/* Backdrop */} +
+ + {/* Menu Panel */} +
+ {/* Close Button */} + + + {/* Menu Links */} + +
+ + ); +} + +// ============================================ +// Scroll to Top Button +// ============================================ +function ScrollToTopButton() { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + const toggleVisibility = () => { + setIsVisible(window.scrollY > 500); + }; + + window.addEventListener('scroll', toggleVisibility); + return () => window.removeEventListener('scroll', toggleVisibility); + }, []); + + const scrollToTop = () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + return ( + + ); +} + // ============================================ // Floating Orbs Background // ============================================ @@ -292,6 +452,8 @@ function FloatingOrbs() { export default function HomePage() { const [videoUrl, setVideoUrl] = useState(''); const [isLoaded, setIsLoaded] = useState(false); + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + const [isAnalyzing, setIsAnalyzing] = useState(false); useEffect(() => { setIsLoaded(true); @@ -299,7 +461,10 @@ export default function HomePage() { const handleAnalyze = async (e: React.FormEvent) => { e.preventDefault(); - if (videoUrl.trim()) { + if (videoUrl.trim() && !isAnalyzing) { + setIsAnalyzing(true); + // Small delay to show loading state before navigation + await new Promise(resolve => setTimeout(resolve, 300)); window.location.href = `/dashboard?video=${encodeURIComponent(videoUrl)}`; } }; @@ -309,32 +474,51 @@ export default function HomePage() { {/* Animated background */} + {/* Mobile Menu */} + setIsMobileMenuOpen(false)} /> + + {/* Scroll to Top Button */} + + {/* Navigation */} -
{/* Main Headline */} -

- - Transform Video into +

+ + VIDEO TO - - Actionable Intelligence + + LEARNING + + + APP

{/* Subheadline */} -

- Stop watching. Start acting. UVAI extracts insights, generates action items, - and deploys live applications from any video in{' '} - 2.3 seconds. +

+ Generate interactive learning apps from +
+ YouTube content +

+ + {/* Attribution */} +

+ An experiment by Aaron Wade

{/* Main CTA Input */} -
-
- setVideoUrl(e.target.value)} - placeholder="Paste any YouTube URL or video link..." - className="flex-1 px-5 py-4 bg-transparent text-white placeholder:text-white/30 focus:outline-none text-lg" - /> - + +
+ {/* Glow effect */} +
+ +
+ setVideoUrl(e.target.value)} + placeholder="Paste a URL from YouTube..." + className="flex-1 px-6 py-4 bg-transparent text-white text-lg placeholder:text-white/40 focus:outline-none" + /> + +
+ {/* Suggested Topics */} +
+ { + const searchUrl = `https://www.youtube.com/results?search_query=${encodeURIComponent(query)}`; + if (typeof window !== 'undefined') { + window.open(searchUrl, '_blank', 'noopener,noreferrer'); + } + }} + /> +
+ + {/* Video Preview Card - Visual Example Only */} +
+
+ {/* Example label */} +
+ Example Preview +
+ + {/* Glow effect */} +
+ +
+ {/* Video thumbnail placeholder */} +
+
+
🎬
+ + {/* Play button overlay */} +
+
+ +
+
+ + {/* Video info overlay */} +
+

Sample: How to build a startup

+

12:34 • Ready to transform

+
+
+
+
+
+ {/* Stats */} -
+
- - - + +
@@ -629,20 +891,105 @@ console.log(result.deployedUrl); {/* Footer */} -