From 43f011e519b4eb2bb498956f7396fc256c5ba110 Mon Sep 17 00:00:00 2001 From: Christopher Mayor Date: Fri, 24 Apr 2026 14:39:54 -0700 Subject: [PATCH] feat: complete frontend UI - comparison views, profile, explore, layout --- src/app/(main)/explore/page.tsx | 216 +++++++++++++++++++++++++++++ src/app/(main)/layout.tsx | 158 ++++++++++++++++++--- src/app/(main)/profile/page.tsx | 157 +++++++++++++++++++++ src/app/page.tsx | 237 ++++++++++++++++++++++++-------- 4 files changed, 693 insertions(+), 75 deletions(-) create mode 100644 src/app/(main)/explore/page.tsx create mode 100644 src/app/(main)/profile/page.tsx diff --git a/src/app/(main)/explore/page.tsx b/src/app/(main)/explore/page.tsx new file mode 100644 index 0000000..5493bca --- /dev/null +++ b/src/app/(main)/explore/page.tsx @@ -0,0 +1,216 @@ +"use client" + +import { useState } from "react" +import { Input } from "@/components/ui/input" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { Avatar, AvatarFallback } from "@/components/ui/avatar" +import { Search, Eye, BarChart3, Filter, X, Loader2 } from "lucide-react" +import Link from "next/link" + +const allComparisons = [ + { + id: "1", + title: "React vs Vue vs Svelte", + description: "Frontend framework comparison for modern web development", + items: ["React", "Vue", "Svelte"], + tags: ["Tech", "JavaScript"], + author: "Alex Johnson", + overallScore: 8.5, + views: 1247, + }, + { + id: "2", + title: "GPT-4 vs Claude vs Gemini", + description: "Comparing top AI language models for reasoning tasks", + items: ["GPT-4", "Claude 3", "Gemini Pro"], + tags: ["AI", "Products"], + author: "Sarah Chen", + overallScore: 8.8, + views: 3891, + }, + { + id: "3", + title: "Notion vs Obsidian vs Roam", + description: "Knowledge management tools for productivity", + items: ["Notion", "Obsidian", "Roam Research"], + tags: ["Productivity", "Tools"], + author: "Mike Peters", + overallScore: 7.5, + views: 892, + }, + { + id: "4", + title: "AWS vs GCP vs Azure", + description: "Cloud platform comparison for enterprise infrastructure", + items: ["AWS", "Google Cloud", "Microsoft Azure"], + tags: ["Tech", "Cloud"], + author: "Emma Wilson", + overallScore: 9.0, + views: 2156, + }, + { + id: "5", + title: "iPhone 15 Pro vs Samsung S24 Ultra", + description: "Flagship smartphone comparison with camera and performance benchmarks", + items: ["iPhone 15 Pro", "Samsung S24 Ultra"], + tags: ["Products", "Mobile"], + author: "James Lee", + overallScore: 8.2, + views: 3421, + }, + { + id: "6", + title: "Python vs Rust vs Go", + description: "Systems programming languages compared for performance and productivity", + items: ["Python", "Rust", "Go"], + tags: ["Tech", "Programming"], + author: "Anna Kim", + overallScore: 8.4, + views: 1873, + }, +] + +const categories = ["All", "Tech", "Products", "AI", "Cloud", "Productivity"] + +export default function ExplorePage() { + const [searchQuery, setSearchQuery] = useState("") + const [selectedCategory, setSelectedCategory] = useState("All") + const [loading, setLoading] = useState(false) + + const filteredComparisons = allComparisons.filter((comparison) => { + const matchesSearch = + searchQuery === "" || + comparison.title.toLowerCase().includes(searchQuery.toLowerCase()) || + comparison.items.some((item) => + item.toLowerCase().includes(searchQuery.toLowerCase()) + ) + const matchesCategory = + selectedCategory === "All" || + comparison.tags.some((tag) => tag.toLowerCase() === selectedCategory.toLowerCase()) + return matchesSearch && matchesCategory + }) + + return ( +
+
+

Explore Comparisons

+ +
+
+ + setSearchQuery(e.target.value)} + className="pl-9" + /> +
+
+ +
+ {categories.map((category) => ( + + ))} +
+
+ + {loading ? ( +
+ +
+ ) : filteredComparisons.length > 0 ? ( +
+ {filteredComparisons.map((comparison) => ( + + + +
+ + {comparison.title} + +
+ + {comparison.description} + +
+ +
+ {comparison.tags.map((tag) => ( + + {tag} + + ))} +
+ +
+ + + {comparison.author.split(" ").map((n) => n[0]).join("")} + + + {comparison.author} +
+ +
+ + {comparison.items.join(" vs ")} + +
+ + + {comparison.views.toLocaleString()} + + + {comparison.overallScore}/10 + +
+
+
+
+ + ))} +
+ ) : ( + +
+
+ +
+
+

No comparisons found

+

+ Try adjusting your search or filters +

+
+ +
+
+ )} + +
+ +
+
+ ) +} \ No newline at end of file diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx index e750b3c..d99cbb4 100644 --- a/src/app/(main)/layout.tsx +++ b/src/app/(main)/layout.tsx @@ -1,50 +1,174 @@ +"use client" + import Link from "next/link" -import { Sparkles } from "lucide-react" +import { usePathname } from "next/navigation" +import { Sparkles, Home, BarChart3, Compass, User, Menu, X, Search } from "lucide-react" +import { useState } from "react" +import { Button } from "@/components/ui/button" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" +import { Input } from "@/components/ui/input" +import { cn } from "@/lib/utils" + +const navItems = [ + { href: "/", label: "Home", icon: Home }, + { href: "/compare", label: "Compare", icon: BarChart3 }, + { href: "/explore", label: "Explore", icon: Compass }, + { href: "/profile", label: "Profile", icon: User }, +] + +function NavSidebar({ className }: { className?: string }) { + const pathname = usePathname() + + return ( + + ) +} + +function MobileNav() { + const pathname = usePathname() + + return ( + + ) +} export default function MainLayout({ children, }: { children: React.ReactNode }) { + const [mobileMenuOpen, setMobileMenuOpen] = useState(false) + const [searchQuery, setSearchQuery] = useState("") + return (
-
- +
+ - ComparAIson + ComparAIson -
+
- + setSearchQuery(e.target.value)} + className="pl-9 h-9" />
-
- - + -
- U -
+ + + + + + U + + + + My Account + + + Profile + + + New Comparison + + + + Sign Out + + + + +
+ + {mobileMenuOpen && ( +
+
+ + setSearchQuery(e.target.value)} + className="pl-9" + /> +
+ +
+ )}
-
{children}
+
+ -
+
{children}
+
+ + + +
ComparAIson — AI-powered deep research comparisons
) -} +} \ No newline at end of file diff --git a/src/app/(main)/profile/page.tsx b/src/app/(main)/profile/page.tsx new file mode 100644 index 0000000..5ac15f0 --- /dev/null +++ b/src/app/(main)/profile/page.tsx @@ -0,0 +1,157 @@ +"use client" + +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { BarChart3, Eye, Calendar, Plus, ArrowRight } from "lucide-react" +import Link from "next/link" + +const mockUser = { + name: "Alex Johnson", + email: "alex@example.com", + avatar: "/placeholder-avatar.png", +} + +const mockComparisons = [ + { + id: "1", + title: "React vs Vue vs Svelte", + items: ["React", "Vue", "Svelte"], + tags: ["Tech", "JavaScript"], + overallScore: 8.5, + views: 1247, + createdAt: "2024-01-15", + }, + { + id: "2", + title: "GPT-4 vs Claude vs Gemini", + items: ["GPT-4", "Claude 3", "Gemini Pro"], + tags: ["AI", "Products"], + overallScore: 8.8, + views: 3891, + createdAt: "2024-01-10", + }, + { + id: "3", + title: "Notion vs Obsidian vs Roam", + items: ["Notion", "Obsidian", "Roam Research"], + tags: ["Productivity"], + overallScore: 7.5, + views: 892, + createdAt: "2024-01-05", + }, +] + +const stats = [ + { label: "Total Comparisons", value: 12, icon: BarChart3 }, + { label: "Total Views", value: "8.2K", icon: Eye }, +] + +export default function ProfilePage() { + return ( +
+
+ + + + {mockUser.name.split(" ").map((n) => n[0]).join("")} + + +
+

{mockUser.name}

+

{mockUser.email}

+
+
+ +
+ {stats.map((stat) => ( + + +
+ +
+
+

{stat.value}

+

{stat.label}

+
+
+
+ ))} +
+ +
+
+

My Comparisons

+ + + +
+ + {mockComparisons.length > 0 ? ( +
+ {mockComparisons.map((comparison) => ( + + + + {comparison.title} + + + {comparison.createdAt} + + + +
+ {comparison.tags.map((tag) => ( + + {tag} + + ))} +
+
+ + {comparison.items.join(" vs ")} + +
+ + + {comparison.views.toLocaleString()} + + + {comparison.overallScore}/10 + +
+
+
+
+ + ))} +
+ ) : ( + +
+
+ +
+
+

No comparisons yet

+

+ Create your first comparison to get started +

+
+ + + +
+
+ )} +
+
+ ) +} \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index 3f36f7c..cb8dcaf 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,65 +1,186 @@ -import Image from "next/image"; +import Link from "next/link" +import { Sparkles, BarChart3, Search, Share2, ArrowRight, CheckCircle2 } from "lucide-react" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -export default function Home() { +const exampleComparisons = [ + { + title: "React vs Vue vs Svelte", + description: "Frontend framework comparison for modern web development", + tags: ["Tech", "JavaScript"], + items: ["React", "Vue", "Svelte"], + scores: [8.5, 7.8, 8.2], + }, + { + title: "GPT-4 vs Claude vs Gemini", + description: "Comparing top AI language models for reasoning tasks", + tags: ["AI", "Products"], + items: ["GPT-4", "Claude 3", "Gemini Pro"], + scores: [8.8, 9.0, 8.4], + }, + { + title: "Notion vs Obsidian vs Roam", + description: "Knowledge management tools for productivity", + tags: ["Products", "Productivity"], + items: ["Notion", "Obsidian", "Roam Research"], + scores: [7.5, 8.3, 7.2], + }, + { + title: "AWS vs GCP vs Azure", + description: "Cloud platform comparison for enterprise infrastructure", + tags: ["Tech", "Cloud"], + items: ["AWS", "Google Cloud", "Microsoft Azure"], + scores: [9.0, 8.2, 8.5], + }, +] + +const features = [ + { + icon: BarChart3, + title: "Rich Visualizations", + description: "Interactive radar charts, bar graphs, and comparison tables to understand your results at a glance.", + }, + { + icon: Search, + title: "Deep Research", + description: "AI-powered research that gathers comprehensive data from multiple sources for each item.", + }, + { + icon: Share2, + title: "Save & Share", + description: "Keep your comparisons private or share them with the world. Build a library of research.", + }, +] + +export default function HomePage() { return ( -
-
- Next.js logo -
-

- To get started, edit the page.tsx file. +
+
+
+
+ + AI-Powered Research +
+ +

+ Compare Anything with{" "} + AI-Powered Deep Research

-

- Looking for a starting point or more instructions? Head over to{" "} - - Templates - {" "} - or the{" "} - - Learning - {" "} - center. + +

+ Stop spending hours researching. Let AI do the work for you with comprehensive, + multi-dimensional comparisons on anything you can think of.

+ +
+ + + + + + +
-
+ +
+
+

Example Comparisons

+ +
+ {exampleComparisons.map((example) => ( + + + +
+ {example.title} +
+ + {example.description} + +
+ +
+ {example.tags.map((tag) => ( + + {tag} + + ))} +
+
+ + {example.items.slice(0, 2).join(" vs ")} + {example.items.length > 2 && ` vs ${example.items.length - 2}+`} + +
+
+ {example.scores.slice(0, 3).map((score, i) => ( +
+ ))} +
+ + + + ))} +
-

+ + +
+
+

Why ComparAIson?

+ +
+ {features.map((feature) => ( +
+
+ +
+

{feature.title}

+

{feature.description}

+
+ ))} +
+
+
+ +
+
+

Ready to compare?

+

+ Start your first comparison in seconds. It's free to get started. +

+ + + +
+
+ +
- ); -} + ) +} \ No newline at end of file