mirror of
https://github.com/soconnor0919/hristudio.git
synced 2025-12-11 22:54:45 -05:00
feat: Add landing page
This commit is contained in:
3
.env
3
.env
@@ -1,3 +0,0 @@
|
||||
POSTGRES_URL=""
|
||||
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_ZmFjdHVhbC1saWdlci0xMi5jbGVyay5hY2NvdW50cy5kZXYk
|
||||
CLERK_SECRET_KEY=sk_test_67aglhtMoQwtdV5sRzkpCDE4F8S2nWyyGVW5XQAJ6o
|
||||
BIN
public/hristudio_laptop.png
Normal file
BIN
public/hristudio_laptop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
46
src/app/icon.tsx
Normal file
46
src/app/icon.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { ImageResponse } from "next/og";
|
||||
|
||||
export const runtime = "edge";
|
||||
export const contentType = "image/svg+xml";
|
||||
export const size = {
|
||||
width: 32,
|
||||
height: 32,
|
||||
};
|
||||
|
||||
export default function Icon() {
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
background: "transparent",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M12 8V4H8" />
|
||||
<rect width="16" height="12" x="4" y="8" rx="2" />
|
||||
<path d="M2 14h2" />
|
||||
<path d="M20 14h2" />
|
||||
<path d="M15 13v2" />
|
||||
<path d="M9 13v2" />
|
||||
</svg>
|
||||
</div>
|
||||
),
|
||||
{
|
||||
...size,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -3,9 +3,20 @@ import {
|
||||
} from '@clerk/nextjs';
|
||||
import { Inter } from 'next/font/google';
|
||||
import './globals.css';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'HRIStudio',
|
||||
description: 'A platform for managing human-robot interaction studies',
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/icon', type: 'image/svg+xml' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
|
||||
110
src/app/page.tsx
110
src/app/page.tsx
@@ -1,38 +1,100 @@
|
||||
'use client';
|
||||
|
||||
import { SignedIn, SignedOut, SignInButton, SignOutButton, UserButton, useUser } from "@clerk/nextjs";
|
||||
import { SignedIn, SignedOut, SignInButton, SignOutButton, UserButton } from "@clerk/nextjs";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { BotIcon } from "lucide-react";
|
||||
import { Logo } from "~/components/logo";
|
||||
|
||||
export default function Home() {
|
||||
const { user, isLoaded } = useUser(); // Get user information and loading state
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoaded) {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [isLoaded]);
|
||||
|
||||
if (loading) {
|
||||
return <div>Loading...</div>; // Show a loading state while fetching user data
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen p-8">
|
||||
<h1 className="text-3xl font-bold mb-4">Welcome to HRIStudio</h1>
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Navigation Bar */}
|
||||
<nav className="border-b bg-card/50 backdrop-blur supports-[backdrop-filter]:bg-card/50">
|
||||
<div className="container mx-auto px-4 h-16 flex items-center justify-between">
|
||||
<Logo />
|
||||
<div className="flex items-center space-x-4">
|
||||
<SignedOut>
|
||||
<SignInButton>
|
||||
<Button>Sign In</Button>
|
||||
<SignInButton mode="modal">
|
||||
<Button variant="ghost">Sign In</Button>
|
||||
</SignInButton>
|
||||
<SignInButton mode="modal">
|
||||
<Button>Sign Up</Button>
|
||||
</SignInButton>
|
||||
</SignedOut>
|
||||
<SignedIn>
|
||||
<UserButton />
|
||||
<p className="mt-4">Signed in as: {user?.emailAddresses[0].emailAddress}</p> {/* Display user's email */}
|
||||
<SignOutButton>
|
||||
<Button>Sign Out</Button>
|
||||
</SignOutButton>
|
||||
<UserButton afterSignOutUrl="/" />
|
||||
</SignedIn>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="container mx-auto px-4 py-24 grid lg:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold tracking-tight lg:text-6xl">
|
||||
Streamline Your HRI Research
|
||||
</h1>
|
||||
<p className="mt-6 text-xl text-muted-foreground">
|
||||
A comprehensive platform for designing, executing, and analyzing Wizard-of-Oz experiments in human-robot interaction studies.
|
||||
</p>
|
||||
<div className="mt-8 flex flex-col sm:flex-row gap-4">
|
||||
<SignedOut>
|
||||
<SignInButton mode="modal">
|
||||
<Button size="lg" className="w-full sm:w-auto">
|
||||
Get Started
|
||||
</Button>
|
||||
</SignInButton>
|
||||
</SignedOut>
|
||||
<SignedIn>
|
||||
<Button size="lg" className="w-full sm:w-auto" asChild>
|
||||
<Link href="/dashboard">
|
||||
Go to Dashboard
|
||||
</Link>
|
||||
</Button>
|
||||
</SignedIn>
|
||||
<Button size="lg" variant="outline" className="w-full sm:w-auto" asChild>
|
||||
<Link href="https://github.com/soconnor0919/hristudio" target="_blank">
|
||||
View on GitHub
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Image
|
||||
src="/hristudio_laptop.png"
|
||||
alt="HRIStudio Interface"
|
||||
width={800}
|
||||
height={600}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Features Section */}
|
||||
<section className="container mx-auto px-4 py-24">
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-semibold">Visual Experiment Design</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Create and configure experiments using an intuitive drag-and-drop interface without extensive coding.
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-semibold">Real-time Control</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Execute experiments with synchronized views for wizards and observers, enabling seamless collaboration.
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-semibold">Comprehensive Analysis</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Record, playback, and analyze experimental data with built-in annotation and export tools.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
36
src/components/logo.tsx
Normal file
36
src/components/logo.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { BotIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
interface LogoProps {
|
||||
href?: string;
|
||||
className?: string;
|
||||
iconClassName?: string;
|
||||
textClassName?: string;
|
||||
}
|
||||
|
||||
export function Logo({
|
||||
href = "/",
|
||||
className,
|
||||
iconClassName,
|
||||
textClassName
|
||||
}: LogoProps) {
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
className={cn(
|
||||
"flex items-center font-sans text-xl",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<BotIcon className={cn(
|
||||
"h-6 w-6 mr-1 text-muted-foreground",
|
||||
iconClassName
|
||||
)} />
|
||||
<span className={cn(textClassName)}>
|
||||
<span className="font-extrabold">HRI</span>
|
||||
<span className="font-normal">Studio</span>
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import { useState } from "react"
|
||||
import { Button } from "~/components/ui/button"
|
||||
import { Sheet, SheetContent, SheetTrigger, SheetTitle } from "~/components/ui/sheet"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { Logo } from "~/components/logo"
|
||||
|
||||
const navItems = [
|
||||
{ name: "Dashboard", href: "/dashboard", icon: LayoutDashboard },
|
||||
@@ -34,14 +35,6 @@ export function Sidebar() {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const { user } = useUser()
|
||||
|
||||
const HRIStudioLogo = () => (
|
||||
<Link href="/dashboard" className="flex items-center font-sans text-xl text-[hsl(var(--sidebar-foreground))]">
|
||||
<BotIcon className="h-6 w-6 mr-1 text-[hsl(var(--sidebar-muted))]" />
|
||||
<span className="font-extrabold">HRI</span>
|
||||
<span className="font-normal">Studio</span>
|
||||
</Link>
|
||||
)
|
||||
|
||||
const SidebarContent = () => (
|
||||
<div className="flex h-full flex-col bg-gradient-to-b from-[hsl(var(--sidebar-background-top))] to-[hsl(var(--sidebar-background-bottom))]">
|
||||
<nav className="flex-1 overflow-y-auto p-4">
|
||||
@@ -86,7 +79,11 @@ export function Sidebar() {
|
||||
<>
|
||||
<div className="lg:hidden fixed top-0 left-0 right-0 z-50">
|
||||
<div className="flex h-14 items-center justify-between border-b px-4 bg-background">
|
||||
<HRIStudioLogo />
|
||||
<Logo
|
||||
href="/dashboard"
|
||||
className="text-[hsl(var(--sidebar-foreground))]"
|
||||
iconClassName="text-[hsl(var(--sidebar-muted))]"
|
||||
/>
|
||||
<Sheet open={isOpen} onOpenChange={setIsOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="ghost" className="h-14 w-14 px-0">
|
||||
@@ -102,7 +99,11 @@ export function Sidebar() {
|
||||
</div>
|
||||
<div className="hidden lg:flex lg:w-64 lg:flex-col lg:border-r lg:bg-gradient-to-b lg:from-[hsl(var(--sidebar-background-top))] lg:to-[hsl(var(--sidebar-background-bottom))]">
|
||||
<div className="flex h-14 items-center border-b px-4">
|
||||
<HRIStudioLogo />
|
||||
<Logo
|
||||
href="/dashboard"
|
||||
className="text-[hsl(var(--sidebar-foreground))]"
|
||||
iconClassName="text-[hsl(var(--sidebar-muted))]"
|
||||
/>
|
||||
</div>
|
||||
<SidebarContent />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user