mirror of
https://github.com/soconnor0919/hristudio.git
synced 2025-12-12 07:04:44 -05:00
Initial commit
This commit is contained in:
20
src/app/dash/layout.tsx
Normal file
20
src/app/dash/layout.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { type PropsWithChildren } from "react"
|
||||
import { Sidebar } from "~/components/sidebar"
|
||||
import { inter } from "../layout"
|
||||
|
||||
import "~/styles/globals.css"
|
||||
|
||||
export default function RootLayout({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`font-sans ${inter.variable}`}>
|
||||
<div className="flex h-screen">
|
||||
<Sidebar />
|
||||
<main className="flex-1 overflow-y-auto">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
54
src/app/dash/page.tsx
Normal file
54
src/app/dash/page.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '~/components/ui/card';
|
||||
import { Button } from '~/components/ui/button';
|
||||
|
||||
const HomePage: React.FC = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-b from-blue-100 to-white pt-14 lg:pt-0">
|
||||
<div className="container mx-auto px-4 py-16">
|
||||
<header className="text-center mb-16">
|
||||
<h1 className="text-5xl font-bold mb-4 text-blue-800">Welcome to the HRIStudio Dashboard!</h1>
|
||||
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
||||
Manage your Human-Robot Interaction projects and experiments
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<Card className="bg-white shadow-lg">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold text-blue-700">Projects</CardTitle>
|
||||
<CardDescription>Manage your HRI projects</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4">Create, edit, and analyze your HRI projects.</p>
|
||||
<Button className="bg-blue-600 hover:bg-blue-700 text-white">View Projects</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-white shadow-lg">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold text-blue-700">Experiments</CardTitle>
|
||||
<CardDescription>Design and run experiments</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4">Set up, conduct, and analyze HRI experiments.</p>
|
||||
<Button className="bg-green-600 hover:bg-green-700 text-white">New Experiment</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-white shadow-lg">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold text-blue-700">Data Analysis</CardTitle>
|
||||
<CardDescription>Analyze your research data</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4">Visualize and interpret your HRI research data.</p>
|
||||
<Button className="bg-purple-600 hover:bg-purple-700 text-white">Analyze Data</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomePage;
|
||||
@@ -1,20 +1,31 @@
|
||||
import "~/styles/globals.css";
|
||||
import { ClerkProvider } from '@clerk/nextjs'
|
||||
import { Inter } from "next/font/google"
|
||||
import { ThemeProvider } from "next-themes"
|
||||
|
||||
import { GeistSans } from "geist/font/sans";
|
||||
import { type Metadata } from "next";
|
||||
import "~/styles/globals.css"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create T3 App",
|
||||
description: "Generated by create-t3-app",
|
||||
export const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
variable: "--font-sans",
|
||||
})
|
||||
|
||||
export const metadata = {
|
||||
title: "T3 App",
|
||||
description: "Created with create-t3-app",
|
||||
icons: [{ rel: "icon", url: "/favicon.ico" }],
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{ children: React.ReactNode }>) {
|
||||
return (
|
||||
<html lang="en" className={`${GeistSans.variable}`}>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: React.PropsWithChildren) {
|
||||
return (
|
||||
<ClerkProvider>
|
||||
{/* <ThemeProvider attribute="class" defaultTheme="system" enableSystem> */}
|
||||
<html lang="en" className={inter.variable}>
|
||||
<body className="font-sans">
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
{/* </ThemeProvider> */}
|
||||
</ClerkProvider>
|
||||
)
|
||||
}
|
||||
@@ -1,37 +1,74 @@
|
||||
import Link from "next/link";
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { auth } from "@clerk/nextjs/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function HomePage() {
|
||||
const { userId } = auth();
|
||||
|
||||
if (userId) {
|
||||
redirect("/dash");
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
|
||||
<h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]">
|
||||
Create <span className="text-[hsl(280,100%,70%)]">T3</span> App
|
||||
</h1>
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8">
|
||||
<Link
|
||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
||||
href="https://create.t3.gg/en/usage/first-steps"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 className="text-2xl font-bold">First Steps →</h3>
|
||||
<div className="text-lg">
|
||||
Just the basics - Everything you need to know to set up your
|
||||
database and authentication.
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
||||
href="https://create.t3.gg/en/introduction"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 className="text-2xl font-bold">Documentation →</h3>
|
||||
<div className="text-lg">
|
||||
Learn more about Create T3 App, the libraries it uses, and how to
|
||||
deploy it.
|
||||
</div>
|
||||
</Link>
|
||||
<div className="min-h-screen bg-gradient-to-b from-blue-100 to-white">
|
||||
<div className="container mx-auto px-4 py-16">
|
||||
<header className="text-center mb-16">
|
||||
<h1 className="text-5xl font-bold mb-4 text-blue-800">Welcome to HRIStudio</h1>
|
||||
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
||||
Empowering Human-Robot Interaction Research and Development
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-12 items-center mb-16">
|
||||
<div>
|
||||
<h2 className="text-3xl font-semibold mb-4 text-blue-700">About HRIStudio</h2>
|
||||
<p className="text-lg text-gray-700 mb-4">
|
||||
HRIStudio is a cutting-edge platform designed to streamline the process of creating,
|
||||
managing, and analyzing Human-Robot Interaction experiments. Our suite of tools
|
||||
empowers researchers and developers to push the boundaries of HRI research.
|
||||
</p>
|
||||
<p className="text-lg text-gray-700 mb-4">
|
||||
With HRIStudio, you can:
|
||||
</p>
|
||||
<ul className="list-disc list-inside text-gray-700 mb-6">
|
||||
<li>Design complex interaction scenarios with ease</li>
|
||||
<li>Collect and analyze data in real-time</li>
|
||||
<li>Collaborate seamlessly with team members</li>
|
||||
<li>Visualize results with advanced reporting tools</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="relative aspect-video w-full">
|
||||
<Image
|
||||
src="/hristudio_laptop.png"
|
||||
alt="HRIStudio Interface on Laptop"
|
||||
fill
|
||||
style={{ objectFit: 'contain' }}
|
||||
// className="rounded-lg shadow-lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl font-semibold mb-4 text-blue-700">Join the HRI Revolution</h2>
|
||||
<p className="text-lg text-gray-700 mb-6">
|
||||
Whether you're a seasoned researcher or just starting in the field of Human-Robot Interaction,
|
||||
HRIStudio provides the tools and support you need to succeed.
|
||||
</p>
|
||||
<div className="space-x-4">
|
||||
<Link href="/sign-in" className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-full transition duration-300">
|
||||
Sign In
|
||||
</Link>
|
||||
<Link href="/sign-up" className="bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-6 rounded-full transition duration-300">
|
||||
Sign Up
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer className="text-center text-gray-600">
|
||||
<p>© 2024 HRIStudio. All rights reserved.</p>
|
||||
</footer>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
102
src/app/sign-in/[[...sign-in]]/page.tsx
Normal file
102
src/app/sign-in/[[...sign-in]]/page.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { useSignIn } from "@clerk/nextjs"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "~/components/ui/card"
|
||||
import { Input } from "~/components/ui/input"
|
||||
import { Button } from "~/components/ui/button"
|
||||
import { Separator } from "~/components/ui/separator"
|
||||
import Link from "next/link"
|
||||
import { FcGoogle } from "react-icons/fc"
|
||||
import { FaApple } from "react-icons/fa"
|
||||
|
||||
export default function SignInPage() {
|
||||
const { isLoaded, signIn, setActive } = useSignIn()
|
||||
const [emailAddress, setEmailAddress] = useState("")
|
||||
const [password, setPassword] = useState("")
|
||||
const router = useRouter()
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (!isLoaded) return
|
||||
|
||||
try {
|
||||
const result = await signIn.create({
|
||||
identifier: emailAddress,
|
||||
password,
|
||||
})
|
||||
|
||||
if (result.status === "complete") {
|
||||
await setActive({ session: result.createdSessionId })
|
||||
router.push("/dash")
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error("Error:", err.errors[0].message)
|
||||
}
|
||||
}
|
||||
|
||||
const signInWith = (strategy: "oauth_google" | "oauth_apple") => {
|
||||
if (!isLoaded) return
|
||||
signIn.authenticateWithRedirect({
|
||||
strategy,
|
||||
redirectUrl: "/sso-callback",
|
||||
redirectUrlComplete: "/dash",
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-b from-blue-100 to-white flex items-center justify-center">
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>Sign In to HRIStudio</CardTitle>
|
||||
<CardDescription>Enter your email and password to sign in</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid w-full items-center gap-4">
|
||||
<Button variant="outline" onClick={() => signInWith("oauth_google")}>
|
||||
<FcGoogle className="mr-2 h-4 w-4" />
|
||||
Sign in with Google
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => signInWith("oauth_apple")}>
|
||||
<FaApple className="mr-2 h-4 w-4" />
|
||||
Sign in with Apple
|
||||
</Button>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="grid w-full items-center gap-4">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Input
|
||||
id="email"
|
||||
placeholder="Email"
|
||||
type="email"
|
||||
value={emailAddress}
|
||||
onChange={(e) => setEmailAddress(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Input
|
||||
id="password"
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Button className="w-full" type="submit">Sign In</Button>
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
<CardFooter className="flex flex-col">
|
||||
<p className="mt-4 text-sm text-center">
|
||||
Don't have an account?{" "}
|
||||
<Link href="/sign-up" className="text-blue-600 hover:underline">
|
||||
Sign up
|
||||
</Link>
|
||||
</p>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
102
src/app/sign-up/[[...sign-up]]/page.tsx
Normal file
102
src/app/sign-up/[[...sign-up]]/page.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { useSignUp } from "@clerk/nextjs"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "~/components/ui/card"
|
||||
import { Input } from "~/components/ui/input"
|
||||
import { Button } from "~/components/ui/button"
|
||||
import { Separator } from "~/components/ui/separator"
|
||||
import Link from "next/link"
|
||||
import { FcGoogle } from "react-icons/fc"
|
||||
import { FaApple } from "react-icons/fa"
|
||||
|
||||
export default function SignUpPage() {
|
||||
const { isLoaded, signUp, setActive } = useSignUp()
|
||||
const [emailAddress, setEmailAddress] = useState("")
|
||||
const [password, setPassword] = useState("")
|
||||
const router = useRouter()
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (!isLoaded) return
|
||||
|
||||
try {
|
||||
const result = await signUp.create({
|
||||
emailAddress,
|
||||
password,
|
||||
})
|
||||
|
||||
if (result.status === "complete") {
|
||||
await setActive({ session: result.createdSessionId })
|
||||
router.push("/dash")
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error("Error:", err.errors[0].message)
|
||||
}
|
||||
}
|
||||
|
||||
const signUpWith = (strategy: "oauth_google" | "oauth_apple") => {
|
||||
if (!isLoaded) return
|
||||
signUp.authenticateWithRedirect({
|
||||
strategy,
|
||||
redirectUrl: "/sso-callback",
|
||||
redirectUrlComplete: "/dash",
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-b from-blue-100 to-white flex items-center justify-center">
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>Sign Up for HRIStudio</CardTitle>
|
||||
<CardDescription>Create an account to get started</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid w-full items-center gap-4">
|
||||
<Button variant="outline" onClick={() => signUpWith("oauth_google")}>
|
||||
<FcGoogle className="mr-2 h-4 w-4" />
|
||||
Sign up with Google
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => signUpWith("oauth_apple")}>
|
||||
<FaApple className="mr-2 h-4 w-4" />
|
||||
Sign up with Apple
|
||||
</Button>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="grid w-full items-center gap-4">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Input
|
||||
id="email"
|
||||
placeholder="Email"
|
||||
type="email"
|
||||
value={emailAddress}
|
||||
onChange={(e) => setEmailAddress(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Input
|
||||
id="password"
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Button className="w-full" type="submit">Sign Up</Button>
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
<CardFooter className="flex flex-col">
|
||||
<p className="mt-4 text-sm text-center">
|
||||
Already have an account?{" "}
|
||||
<Link href="/sign-in" className="text-blue-600 hover:underline">
|
||||
Sign in
|
||||
</Link>
|
||||
</p>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user