From 3adabe7a1687d77a53269619fd5a081ea83d6d63 Mon Sep 17 00:00:00 2001 From: "DESKTOP-RTLN3BA\\$punk" Date: Thu, 2 Oct 2025 12:43:43 -0700 Subject: [PATCH] feat: frontpage --- surfsense_web/app/page.tsx | 6 +- .../ModernHeroWithGradients.tsx | 7 +- surfsense_web/components/homepage/cta.tsx | 110 +++++ .../homepage/features-bento-grid.tsx | 448 ++++++++++++++++++ .../components/homepage/features-card.tsx | 74 +++ surfsense_web/components/ui/bento-grid.tsx | 54 +++ .../public/homepage/comments-audio.webp | Bin 0 -> 12336 bytes 7 files changed, 696 insertions(+), 3 deletions(-) rename surfsense_web/components/{ => homepage}/ModernHeroWithGradients.tsx (98%) create mode 100644 surfsense_web/components/homepage/cta.tsx create mode 100644 surfsense_web/components/homepage/features-bento-grid.tsx create mode 100644 surfsense_web/components/homepage/features-card.tsx create mode 100644 surfsense_web/components/ui/bento-grid.tsx create mode 100644 surfsense_web/public/homepage/comments-audio.webp diff --git a/surfsense_web/app/page.tsx b/surfsense_web/app/page.tsx index e5501d35f..dfa0e7587 100644 --- a/surfsense_web/app/page.tsx +++ b/surfsense_web/app/page.tsx @@ -1,7 +1,9 @@ "use client"; import { Footer } from "@/components/Footer"; -import { ModernHeroWithGradients } from "@/components/ModernHeroWithGradients"; +import { CTAHomepage } from "@/components/homepage/cta"; +import { FeaturesBentoGrid } from "@/components/homepage/features-bento-grid"; +import { ModernHeroWithGradients } from "@/components/homepage/ModernHeroWithGradients"; import { Navbar } from "@/components/Navbar"; export default function HomePage() { @@ -9,6 +11,8 @@ export default function HomePage() {
+ +
); diff --git a/surfsense_web/components/ModernHeroWithGradients.tsx b/surfsense_web/components/homepage/ModernHeroWithGradients.tsx similarity index 98% rename from surfsense_web/components/ModernHeroWithGradients.tsx rename to surfsense_web/components/homepage/ModernHeroWithGradients.tsx index 543e1b4eb..bb7a49d74 100644 --- a/surfsense_web/components/ModernHeroWithGradients.tsx +++ b/surfsense_web/components/homepage/ModernHeroWithGradients.tsx @@ -1,12 +1,14 @@ "use client"; import { IconBrandDiscord, IconBrandGithub, IconFileTypeDoc, IconMail } from "@tabler/icons-react"; +import Image from "next/image"; import Link from "next/link"; import { cn } from "@/lib/utils"; -import { Logo } from "./Logo"; +import { Logo } from "../Logo"; +import { Features } from "./features-card"; export function ModernHeroWithGradients() { return ( -
+
@@ -77,6 +79,7 @@ export function ModernHeroWithGradients() {
+
diff --git a/surfsense_web/components/homepage/cta.tsx b/surfsense_web/components/homepage/cta.tsx new file mode 100644 index 000000000..1176c69df --- /dev/null +++ b/surfsense_web/components/homepage/cta.tsx @@ -0,0 +1,110 @@ +"use client"; +import { IconMessageCircleQuestion } from "@tabler/icons-react"; +import Link from "next/link"; +import type React from "react"; +import { cn } from "@/lib/utils"; + +export function CTAHomepage() { + return ( +
+ + + + +
+

+ Transform how your team{" "} + discovers and collaborates +

+

+ Unite your team's knowledge in one collaborative + space with intelligent search. +

+ +
+ + + +
+
+ {/*
+

+ "SurfSense has revolutionized how our team shares and discovers knowledge. + Everyone can contribute and find what they need instantly. True collaboration at scale." +

+
+

+ Sarah Chen +

+

+ Research Lead +

+
+
*/} +
+ ); +} + +const GridLineHorizontal = ({ className, offset }: { className?: string; offset?: string }) => { + return ( +
+ ); +}; + +const GridLineVertical = ({ className, offset }: { className?: string; offset?: string }) => { + return ( +
+ ); +}; diff --git a/surfsense_web/components/homepage/features-bento-grid.tsx b/surfsense_web/components/homepage/features-bento-grid.tsx new file mode 100644 index 000000000..d9a5b7428 --- /dev/null +++ b/surfsense_web/components/homepage/features-bento-grid.tsx @@ -0,0 +1,448 @@ +import { IconFileBroken, IconSparkles, IconTableColumn, IconUsers } from "@tabler/icons-react"; +import Image from "next/image"; +import React from "react"; +import { BentoGrid, BentoGridItem } from "@/components/ui/bento-grid"; + +export function FeaturesBentoGrid() { + return ( + + {items.map((item, i) => ( + + ))} + + ); +} + +const CitationIllustration = () => ( +
+ + Citation feature illustration showing clickable source reference + {/* Background chat message */} + + {/* Chat bubble */} + + {/* Text lines */} + + + + {/* Citation badge with glow */} + + + + + + + + + + + {/* Clickable citation */} + + + + [1] + + + + + {/* Connecting line with animation effect */} + + + + + + {/* Arrow head */} + + + + {/* Citation popup card */} + + {/* Card shadow */} + + + {/* Main card */} + + + {/* Card header */} + + + + {/* Header text */} + + Referenced Chunk + + + {/* Content lines */} + + + + + + {/* Sparkle effects */} + + {/* Sparkle 1 */} + + + + + + + + {/* Sparkle 2 */} + + + + + + + + {/* Sparkle 3 */} + + + + + + {/* AI Sparkle icon in corner */} + + + + + + +
+); + +const CollaborationIllustration = () => ( +
+
+
+
+ + {/* Real-time */} + + Real-time + + + + + Rich + + + collabo + orat + + + + Alex + + + ion + +
+
+ {/* Bottom gradient fade */} +
+ {/* Right gradient fade */} +
+
+
+); + +const AnnotationIllustration = () => ( +
+
+
+ {/* Text above the comment box */} +
+ + Add context with +
+
{" "} + + comments + +
+ + {/* Comment card */} +
+
+ Let's discuss this tomorrow! +
+ + {/* Reaction icons */} +
+ {/* @ icon */} + + Mention icon + + + + + + + {/* Emoji icon */} + + Emoji icon + + + + + + + {/* Attachment icon */} + + Attachment icon + + +
+
+
+ + {/* Bottom gradient fade */} +
+ {/* Right gradient fade */} +
+
+
+); + +const AudioCommentIllustration = () => ( +
+ Audio Comment Illustration +
+); + +const items = [ + { + title: "Find, Ask, Act", + description: + "Get instant information, detailed updates, and cited answers across company and personal knowledge.", + header: , + className: "md:col-span-2", + icon: , + }, + { + title: "Work Together in Real Time", + description: + "Transform your company docs into multiplayer spaces with live edits, synced content, and presence.", + header: , + className: "md:col-span-1", + icon: , + }, + { + title: "Collaborate Beyond Text", + description: + "Create podcasts and multimedia your team can comment on, share, and refine together.", + header: , + className: "md:col-span-1", + icon: , + }, + { + title: "Context Where It Counts", + description: "Add comments directly to your chats and docs for clear, in-the-moment feedback.", + header: , + className: "md:col-span-2", + icon: , + }, +]; diff --git a/surfsense_web/components/homepage/features-card.tsx b/surfsense_web/components/homepage/features-card.tsx new file mode 100644 index 000000000..78c4cccc1 --- /dev/null +++ b/surfsense_web/components/homepage/features-card.tsx @@ -0,0 +1,74 @@ +import { Sliders, Users, Workflow } from "lucide-react"; +import type { ReactNode } from "react"; +import { Card, CardContent, CardHeader } from "@/components/ui/card"; + +export function Features() { + return ( +
+
+ {/*
+

Built to cover your needs

+

Libero sapiente aliquam quibusdam aspernatur, praesentium iusto repellendus.

+
*/} +
+ + + + + + +

Customizable

+
+ + +

Customize your research agent to your specific needs.

+
+
+ + + + + + + +

Streamline your workflow

+
+ + +

+ Pull all your knowledge into one place, so you can find what matters and get things + done faster. +

+
+
+ + + + + + + +

Seamless Collaboration

+
+ + +

Make your company and personal content collaborative.

+
+
+
+
+
+ ); +} + +const CardDecorator = ({ children }: { children: ReactNode }) => ( +
+
+
+ {children} +
+
+); diff --git a/surfsense_web/components/ui/bento-grid.tsx b/surfsense_web/components/ui/bento-grid.tsx new file mode 100644 index 000000000..77614fc97 --- /dev/null +++ b/surfsense_web/components/ui/bento-grid.tsx @@ -0,0 +1,54 @@ +import { cn } from "@/lib/utils"; + +export const BentoGrid = ({ + className, + children, +}: { + className?: string; + children?: React.ReactNode; +}) => { + return ( +
+ {children} +
+ ); +}; + +export const BentoGridItem = ({ + className, + title, + description, + header, + icon, +}: { + className?: string; + title?: string | React.ReactNode; + description?: string | React.ReactNode; + header?: React.ReactNode; + icon?: React.ReactNode; +}) => { + return ( +
+ {header} +
+ {icon} +
+ {title} +
+
+ {description} +
+
+
+ ); +}; diff --git a/surfsense_web/public/homepage/comments-audio.webp b/surfsense_web/public/homepage/comments-audio.webp new file mode 100644 index 0000000000000000000000000000000000000000..c56ac6008e0c37054dc6da3936b895c46e8cadad GIT binary patch literal 12336 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