feat: Enhance plugin store and experiment design infrastructure

- Add plugin store system with dynamic loading of robot actions
- Implement plugin store API routes and database schema
- Update experiment designer to support plugin-based actions
- Refactor environment configuration and sidebar navigation
- Improve authentication session handling with additional user details
- Update Tailwind CSS configuration and global styles
- Remove deprecated files and consolidate project structure
This commit is contained in:
2025-02-28 11:10:56 -05:00
parent 88c305de61
commit ab08c1b724
75 changed files with 7641 additions and 3382 deletions

View File

@@ -0,0 +1,73 @@
"use client";
import { motion } from "framer-motion";
import { BotIcon } from "lucide-react";
import Link from "next/link";
import { Button } from "~/components/ui/button";
import { Card, CardContent } from "~/components/ui/card";
interface CTASectionProps {
isLoggedIn: boolean;
}
export function CTASection({ isLoggedIn }: CTASectionProps) {
return (
<section className="container mx-auto px-4 py-24">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
>
<Card className="relative overflow-hidden">
<div className="pointer-events-none absolute inset-0 bg-gradient-to-br from-primary via-primary to-secondary" />
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_120%,rgba(0,0,0,0)_30%,rgba(0,0,0,0.15)_100%)]" />
<CardContent className="relative p-12 flex flex-col items-center text-center space-y-6 text-primary-foreground">
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
whileInView={{ scale: 1, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.2, duration: 0.5 }}
>
<BotIcon className="size-12 mb-4" />
</motion.div>
<motion.h2
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.3, duration: 0.5 }}
className="text-3xl font-bold tracking-tight"
>
Ready to Transform Your Research?
</motion.h2>
<motion.p
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.4, duration: 0.5 }}
className="text-primary-foreground/90 max-w-[600px]"
>
Join the growing community of researchers using HRIStudio to advance human-robot interaction studies.
</motion.p>
<motion.div
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.5, duration: 0.5 }}
>
{!isLoggedIn ? (
<Button size="lg" variant="secondary" asChild className="mt-4 bg-background/20 hover:bg-background/30">
<Link href="/auth/signup">Start Your Journey</Link>
</Button>
) : (
<Button size="lg" variant="secondary" asChild className="mt-4 bg-background/20 hover:bg-background/30">
<Link href="/dashboard">Go to Dashboard</Link>
</Button>
)}
</motion.div>
</CardContent>
</Card>
</motion.div>
</section>
);
}

View File

@@ -0,0 +1,67 @@
"use client";
import { motion } from "framer-motion";
import { Sparkles, Brain, Microscope } from "lucide-react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
const features = [
{
icon: <Sparkles className="size-6 text-primary" />,
title: "Visual Experiment Design",
description: "Create and configure experiments using an intuitive drag-and-drop interface without extensive coding."
},
{
icon: <Brain className="size-6 text-primary" />,
title: "Real-time Control",
description: "Execute experiments with synchronized views for wizards and observers, enabling seamless collaboration."
},
{
icon: <Microscope className="size-6 text-primary" />,
title: "Comprehensive Analysis",
description: "Record, playback, and analyze experimental data with built-in annotation and export tools."
}
];
export function FeaturesSection() {
return (
<section className="container mx-auto px-4 py-24 space-y-12">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="text-center space-y-4"
>
<h2 className="text-3xl font-bold tracking-tight bg-gradient-to-br from-foreground to-foreground/70 bg-clip-text text-transparent inline-block">
Powerful Features for HRI Research
</h2>
<p className="text-muted-foreground max-w-[600px] mx-auto">
Everything you need to design, execute, and analyze your human-robot interaction experiments.
</p>
</motion.div>
<div className="grid md:grid-cols-3 gap-8">
{features.map((feature, index) => (
<motion.div
key={feature.title}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: index * 0.1, duration: 0.5 }}
>
<Card className="group relative overflow-hidden border bg-background/60 backdrop-blur supports-[backdrop-filter]:bg-background/60 hover:shadow-lg transition-all">
<div className="pointer-events-none absolute inset-0 bg-gradient-to-br from-primary/10 via-primary/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
<CardHeader>
<div className="size-12 rounded-lg bg-gradient-to-br from-primary/20 to-primary/10 flex items-center justify-center mb-4">
{feature.icon}
</div>
<CardTitle>{feature.title}</CardTitle>
<CardDescription>{feature.description}</CardDescription>
</CardHeader>
</Card>
</motion.div>
))}
</div>
</section>
);
}

View File

@@ -0,0 +1,101 @@
"use client";
import { motion } from "framer-motion";
import { BotIcon, ArrowRight } from "lucide-react";
import Link from "next/link";
import { Button } from "~/components/ui/button";
interface HeroSectionProps {
isLoggedIn: boolean;
}
export function HeroSection({ isLoggedIn }: HeroSectionProps) {
return (
<section className="relative">
{/* Hero gradient background */}
<div className="absolute inset-0 bg-gradient-to-b from-background via-primary/5 to-background">
<div className="absolute inset-0"
style={{
backgroundImage: `radial-gradient(circle at 50% 50%, hsl(var(--primary)/.08) 0%, transparent 50%)`,
}}
/>
</div>
<div className="container mx-auto px-4 py-24 relative">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="grid lg:grid-cols-2 gap-12 items-center"
>
<div className="space-y-6">
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2, duration: 0.5 }}
className="inline-flex rounded-lg bg-gradient-to-br from-primary/20 via-secondary/20 to-background p-1 mb-8"
>
<span className="rounded-md bg-background/95 px-3 py-1 text-sm backdrop-blur">
Now with Visual Experiment Designer
</span>
</motion.div>
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.5 }}
className="text-4xl font-bold tracking-tight lg:text-6xl bg-gradient-to-br from-foreground via-foreground/90 to-foreground/70 bg-clip-text text-transparent"
>
Streamline Your HRI Research
</motion.h1>
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4, duration: 0.5 }}
className="text-xl text-muted-foreground"
>
A comprehensive platform for designing, executing, and analyzing Wizard-of-Oz experiments in human-robot interaction studies.
</motion.p>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5, duration: 0.5 }}
className="flex flex-col sm:flex-row gap-4 pt-4"
>
{!isLoggedIn ? (
<Button size="lg" className="w-full sm:w-auto group bg-gradient-to-r from-primary to-primary hover:from-primary/90 hover:to-primary" asChild>
<Link href="/auth/signup">
Get Started
<ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</Link>
</Button>
) : (
<Button size="lg" className="w-full sm:w-auto group bg-gradient-to-r from-primary to-primary hover:from-primary/90 hover:to-primary" asChild>
<Link href="/dashboard">
Go to Dashboard
<ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</Link>
</Button>
)}
<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>
</motion.div>
</div>
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 0.4, duration: 0.5 }}
className="relative aspect-square lg:aspect-video"
>
<div className="absolute inset-0 bg-gradient-to-br from-primary/30 via-secondary/20 to-background rounded-lg border shadow-xl" />
<div className="absolute inset-0 flex items-center justify-center">
<BotIcon className="h-32 w-32 text-primary/40" />
</div>
</motion.div>
</motion.div>
</div>
</section>
);
}