Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
661 changes: 622 additions & 39 deletions frontend/package-lock.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,24 @@
"@mantine/core": "^7.14.2",
"@mantine/hooks": "^7.14.2",
"@radix-ui/react-alert-dialog": "^1.1.3",
"@radix-ui/react-checkbox": "^1.3.2",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.2",
"@supabase/ssr": "^0.6.1",
"@supabase/supabase-js": "^2.49.7",
"@tabler/icons-react": "^3.22.0",
"axios": "^1.9.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.468.0",
"next": "15.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^5.5.0",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
"zustand": "^5.0.2"
Expand Down
Binary file added frontend/public/pathonai_org.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 106 additions & 0 deletions frontend/src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { useState } from "react";
import { HiMenu, HiX } from "react-icons/hi";
import { FaLinkedin, FaTwitter, FaDiscord, FaGithub } from 'react-icons/fa';
import Link from "next/link";
import { useRouter } from "next/router";

const Header = () => {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const router = useRouter();

const isActive = (path: string) => {
return router.pathname === path;
};

return (
<header className="fixed w-full z-10">
<div className="px-6 py-5 flex justify-between items-center bg-gray-100 shadow-md">
<div className="flex items-center">
<Link href="/" className="flex items-center text-xl font-bold text-gray-900 mr-12">
<img
src="/pathonai_org.png"
alt="PathOnAI Logo"
className="h-8 w-auto mr-2"
/>
PathOnAI
</Link>
<nav className="hidden md:flex space-x-8">
<Link
href="https://www.pathonai.org/projects/litewebagent"
className={`text-sm font-medium ${isActive('/')
? 'text-blue-600'
: 'text-gray-700 hover:text-blue-600'}`}
>
LiteWebAgent Project Page
</Link>
<Link
href="https://www.pathonai.org/projects/visualtreesearch"
className={`text-sm font-medium ${isActive('/projects')
? 'text-blue-600'
: 'text-gray-700 hover:text-blue-600'}`}
>
Visual Tree Search Project Page
</Link>
</nav>
</div>
<div className="flex items-center">
{/* Social Media Links */}
<div className="hidden md:flex items-center space-x-5 mr-6">
<a
href="https://github.com/PathOnAI"
target="_blank"
rel="noopener noreferrer"
className="text-gray-700 hover:text-blue-600"
aria-label="GitHub"
>
<FaGithub className="h-6 w-6" />
</a>
<a
href="https://www.linkedin.com/company/pathonai/"
target="_blank"
rel="noopener noreferrer"
className="text-gray-700 hover:text-blue-600"
aria-label="LinkedIn"
>
<FaLinkedin className="h-6 w-6" />
</a>
<a
href="https://x.com/PathOnAI"
target="_blank"
rel="noopener noreferrer"
className="text-gray-700 hover:text-blue-600"
aria-label="Twitter"
>
<FaTwitter className="h-6 w-6" />
</a>
<a
href="https://discord.com/invite/UTxjyNwTeP"
target="_blank"
rel="noopener noreferrer"
className="text-gray-700 hover:text-blue-600"
aria-label="Discord"
>
<FaDiscord className="h-6 w-6" />
</a>
</div>

<div className="md:hidden">
<button
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
className="text-gray-700"
>
{mobileMenuOpen ? (
<HiX className="h-6 w-6" />
) : (
<HiMenu className="h-6 w-6" />
)}
</button>
</div>
</div>
</div>

</header>
);
};

export default Header;
19 changes: 19 additions & 0 deletions frontend/src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import Sidebar from "./Sidebar";
import Header from "./Header";

interface LayoutProps {
children: React.ReactNode;
}

export default function Layout({ children }: LayoutProps) {
return (
<div className="flex flex-col h-screen bg-background">
<Header />
<div className="flex flex-1 overflow-hidden">
<Sidebar />
<main className="flex-1 overflow-auto p-6 mt-16">{children}</main>
</div>
</div>
);
}
63 changes: 63 additions & 0 deletions frontend/src/components/layout/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Link from "next/link";
import { useRouter } from "next/router";
import { Home, LineChart, FileText, LogIn} from "lucide-react";
import { Button } from "@/components/ui/button";

export default function Sidebar() {
const router = useRouter();

// Helper to add custom active styles
const activeClass =
"bg-blue-50 border-l-4 border-blue-600 text-blue-700 font-semibold shadow-sm";

return (
<div className="w-64 h-full border-r border-foreground/10 bg-background">
<div className="p-4 border-b border-foreground/10">
<h1 className="text-xl font-bold">LiteWebAgent</h1>
</div>

<nav className="p-2">
<div className="space-y-1">
<Button
variant={router.pathname === "/" ? "secondary" : "ghost"}
className={`w-full justify-start ${
router.pathname === "/" ? activeClass : ""
}`}
asChild
>
<Link href="/">
<Home className="mr-2 h-4 w-4" />
Home
</Link>
</Button>

<Button
variant={router.pathname === "/playground" ? "secondary" : "ghost"}
className={`w-full justify-start ${
router.pathname === "/playground" ? activeClass : ""
}`}
asChild
>
<Link href="/playground">
<LineChart className="mr-2 h-4 w-4" />
Playground
</Link>
</Button>

<Button
variant={router.pathname === "/login" ? "secondary" : "ghost"}
className={`w-full justify-start ${
router.pathname === "/login" ? activeClass : ""
}`}
asChild
>
<Link href="/login">
<LogIn className="mr-2 h-4 w-4" />
Login
</Link>
</Button>
</div>
</nav>
</div>
);
}
28 changes: 28 additions & 0 deletions frontend/src/components/ui/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Check } from "lucide-react"

import { cn } from "@/lib/utils"

const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className
)}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
>
<Check className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName

export { Checkbox }
24 changes: 24 additions & 0 deletions frontend/src/components/ui/label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)

const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName

export { Label }
13 changes: 12 additions & 1 deletion frontend/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import { DeepgramContextProvider } from '@/context/DeepgramContextProvider';
import { MicrophoneContextProvider } from '@/context/MicrophoneContextProvider';
import { MantineProvider } from '@mantine/core';
import { Inter } from "next/font/google";
import Layout from "@/components/layout/Layout";
import '@mantine/core/styles.css';
import type { AppProps } from 'next/app';

const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
});

export default function App({ Component, pageProps }: AppProps) {
return (
<MicrophoneContextProvider>
<DeepgramContextProvider>
<MantineProvider>
<Component {...pageProps} />
<div className={inter.variable}>
<Layout>
<Component {...pageProps} />
</Layout>
</div>
</MantineProvider>
</DeepgramContextProvider>
</MicrophoneContextProvider>
Expand Down
89 changes: 52 additions & 37 deletions frontend/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,56 @@
import { useState } from "react"
import Playground from "./playground"
import { AlertDialog, AlertDialogContent, AlertDialogDescription, AlertDialogTitle } from '@/components/ui/alert-dialog'
import { Button } from "@/components/ui/button"
import { AlertCircle } from 'lucide-react'
import type { GetServerSidePropsContext } from "next";
import { useRouter } from "next/router";
import { createClient } from "@/utils/supabase/server-props";
import { BrainCircuit } from "lucide-react";

export default function Page() {
const [showWelcomeModal, setShowWelcomeModal] = useState(true)
interface PageProps {
user?: any;
}

export default function Page({ user }: PageProps) {
const router = useRouter();

return (
<>
<Playground
initialSteps_={[]}
processId="x"
onSessionEnd={() => console.log('done')}
/>

<AlertDialog open={showWelcomeModal} onOpenChange={setShowWelcomeModal}>
<AlertDialogContent className="max-w-xl !bg-white/95">
<div className="space-y-4">
<AlertDialogTitle className="text-xl font-semibold text-gray-900 flex items-center gap-2">
<AlertCircle className="w-6 h-6 text-yellow-500" />
Important Notice
</AlertDialogTitle>
<AlertDialogDescription className="text-gray-700 text-base leading-relaxed">
We are using the BrowserBase hobby plan 🔄, which only supports 3 concurrent browsers. If you are not able to get the web agent up and running ⚠️, it is most likely because someone else is using a remote BrowserBase browser 💻. The BrowserBase startup and scale plans 💰 are too expensive for our open source project 🔓.
</AlertDialogDescription>
<div className="flex justify-end pt-4">
<Button
onClick={() => setShowWelcomeModal(false)}
className="bg-blue-600 hover:bg-blue-700 text-white"
>
I Understand
</Button>
</div>
</div>
</AlertDialogContent>
</AlertDialog>
</>
)
<div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-br from-gray-50 via-gray-50 to-blue-50">
{/* Enlarged Logo and Title Section */}
<div className="flex items-center space-x-6 mb-12">
<div className="bg-gradient-to-br from-blue-600 to-indigo-600 text-white p-6 rounded-2xl shadow-xl flex items-center justify-center">
<BrainCircuit className="w-16 h-16" />
</div>
<div>
<span className="font-semibold text-gray-800 text-4xl block mb-2">Web Agent Demo</span>
<p className="text-2xl text-gray-500">Interactive Browser Assistant</p>
</div>
</div>
{user ? (
<button
onClick={() => router.push("/playground")}
className="px-8 py-3 rounded-lg bg-blue-600 text-white font-semibold text-xl hover:bg-blue-700 transition"
>
Go to Playground
</button>
) : (
<div className="flex flex-col items-center">
<h1 className="text-2xl font-bold mb-4">Please log in to view this page.</h1>
<button
onClick={() => router.push("/login")}
className="px-6 py-2 rounded bg-blue-600 text-white font-semibold hover:bg-blue-700 transition"
>
Go to Login
</button>
</div>
)}
</div>
);
}

export async function getServerSideProps(context: GetServerSidePropsContext) {
const supabase = createClient(context);
const { data } = await supabase.auth.getUser();

return {
props: {
user: data?.user || null,
},
};
}
Loading