feat: add Digital Twin onboarding component with GSAP animations and user configuration steps
All checks were successful
GBCI / build (push) Successful in 4m30s
All checks were successful
GBCI / build (push) Successful in 4m30s
This commit is contained in:
parent
57dd607037
commit
1d7ac7c0a2
4 changed files with 366 additions and 1 deletions
|
@ -22,6 +22,7 @@ export default function DashboardScreen() {
|
|||
</header>
|
||||
|
||||
<main className="container p-4 space-y-4">
|
||||
s
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-2xl font-bold">Dashboard</h1>
|
||||
<div className="flex items-center space-x-2">
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
import React from 'react';
|
||||
import { ProfileForm } from './profile-form';
|
||||
|
||||
|
@ -7,7 +9,17 @@ export default function SettingsProfilePage() {
|
|||
<div>
|
||||
<h2 className="text-lg font-medium">Profile</h2>
|
||||
<p className="text-sm text-gray-500">
|
||||
This is how others will see you on the site.
|
||||
- **Ports Used**:
|
||||
Main website: (https://www.pragmatismo.com.br).
|
||||
Webmail (Stalwart): (https://mail.pragmatismo.com.br).
|
||||
Database (PostgreSQL): .
|
||||
SSO (Zitadel): (https://sso.pragmatismo.com.br).
|
||||
Storage (MinIO): (https://drive.pragmatismo.com.br).
|
||||
ALM (Forgejo): (https://alm.pragmatismo.com.br).
|
||||
BotServer : (https://gb.pragmatismo.com.br).
|
||||
Meeting: (https://call.pragmatismo.com.br).
|
||||
IMAP: 993.
|
||||
SMTP: 465.
|
||||
</p>
|
||||
</div>
|
||||
<div className="border-t border-gray-200 my-4" />
|
||||
|
|
1
app/tree/prompt.md
Normal file
1
app/tree/prompt.md
Normal file
|
@ -0,0 +1 @@
|
|||
- The UI shoule look exactly xtree gold but using shadcn with keyborad shortcut well explicit.
|
351
components/projectors/newbot/page.tsx
Normal file
351
components/projectors/newbot/page.tsx
Normal file
|
@ -0,0 +1,351 @@
|
|||
"use client";
|
||||
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { gsap } from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { Rocket, BrainCircuit, UserCog, Database, Shield } from 'lucide-react';
|
||||
|
||||
// Register GSAP plugins
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
interface OnboardingStep {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
component: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function DigitalTwinOnboarding() {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const progressRef = useRef<HTMLDivElement>(null);
|
||||
const [currentStep, setCurrentStep] = React.useState(0);
|
||||
const [completedSteps, setCompletedSteps] = React.useState<Set<string>>(new Set());
|
||||
|
||||
// Animation setup
|
||||
useEffect(() => {
|
||||
const ctx = gsap.context(() => {
|
||||
gsap.from(".onboarding-card", {
|
||||
opacity: 0,
|
||||
y: 50,
|
||||
duration: 0.8,
|
||||
stagger: 0.15,
|
||||
ease: "power3.out",
|
||||
});
|
||||
|
||||
ScrollTrigger.create({
|
||||
trigger: containerRef.current,
|
||||
start: "top top",
|
||||
end: "bottom bottom",
|
||||
onUpdate: (self) => {
|
||||
if (progressRef.current) {
|
||||
progressRef.current.style.width = `${self.progress * 100}%`;
|
||||
}
|
||||
},
|
||||
});
|
||||
}, containerRef);
|
||||
|
||||
return () => ctx.revert();
|
||||
}, []);
|
||||
|
||||
const onboardingSteps: OnboardingStep[] = [
|
||||
{
|
||||
id: "personalization",
|
||||
title: "Personalization Setup",
|
||||
description: "Configure your digital twin's personality and interaction style",
|
||||
icon: <UserCog className="w-6 h-6 text-indigo-600" />,
|
||||
component: (
|
||||
<div className="space-y-6">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="communication-style">Communication Style</Label>
|
||||
<select
|
||||
id="communication-style"
|
||||
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
<option value="professional">Professional</option>
|
||||
<option value="friendly">Friendly</option>
|
||||
<option value="concise">Concise</option>
|
||||
<option value="detailed">Detailed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="response-length">Response Length</Label>
|
||||
<Input id="response-length" type="range" min="1" max="5" defaultValue="3" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="knowledge-domains">Primary Knowledge Domains</Label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{['Technology', 'Business', 'Creative Arts', 'Science', 'Health'].map((domain) => (
|
||||
<Button
|
||||
key={domain}
|
||||
variant="outline"
|
||||
className="rounded-full"
|
||||
size="sm"
|
||||
>
|
||||
{domain}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "data-sources",
|
||||
title: "Data Integration",
|
||||
description: "Connect your digital twin to your knowledge sources",
|
||||
icon: <Database className="w-6 h-6 text-blue-600" />,
|
||||
component: (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex-1 space-y-1">
|
||||
<Label>Email Integration</Label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Connect your email for communication context
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="outline">Connect</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex-1 space-y-1">
|
||||
<Label>Calendar Access</Label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Enable scheduling and time management
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="outline">Connect</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex-1 space-y-1">
|
||||
<Label>Cloud Storage</Label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Access your documents and files
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="outline">Connect</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "capabilities",
|
||||
title: "Capabilities Selection",
|
||||
description: "Select your digital twin's core competencies",
|
||||
icon: <BrainCircuit className="w-6 h-6 text-purple-600" />,
|
||||
component: (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{[
|
||||
"Email Management",
|
||||
"Schedule Optimization",
|
||||
"Research Assistant",
|
||||
"Meeting Summaries",
|
||||
"Data Analysis",
|
||||
"Content Generation",
|
||||
"Task Automation",
|
||||
"Learning Companion",
|
||||
].map((capability) => (
|
||||
<Card key={capability} className="hover:border-primary transition-colors">
|
||||
<CardHeader className="flex flex-row items-center space-y-0 space-x-4 p-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`capability-${capability.toLowerCase().replace(' ', '-')}`}
|
||||
className="h-5 w-5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<Label htmlFor={`capability-${capability.toLowerCase().replace(' ', '-')}`}>
|
||||
{capability}
|
||||
</Label>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "security",
|
||||
title: "Privacy & Security",
|
||||
description: "Configure your data protection preferences",
|
||||
icon: <Shield className="w-6 h-6 text-green-600" />,
|
||||
component: (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className="flex items-center h-5">
|
||||
<input
|
||||
id="data-retention"
|
||||
name="data-retention"
|
||||
type="checkbox"
|
||||
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
defaultChecked
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<Label htmlFor="data-retention">Automatic Data Retention</Label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Allow temporary data storage for context continuity
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className="flex items-center h-5">
|
||||
<input
|
||||
id="analytics"
|
||||
name="analytics"
|
||||
type="checkbox"
|
||||
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
defaultChecked
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<Label htmlFor="analytics">Anonymous Usage Analytics</Label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Help improve the system while protecting your identity
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className="flex items-center h-5">
|
||||
<input
|
||||
id="encryption"
|
||||
name="encryption"
|
||||
type="checkbox"
|
||||
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
defaultChecked
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<Label htmlFor="encryption">End-to-End Encryption</Label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Maximum security for all your communications
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const handleNext = () => {
|
||||
setCompletedSteps(new Set(completedSteps).add(onboardingSteps[currentStep].id));
|
||||
if (currentStep < onboardingSteps.length - 1) {
|
||||
setCurrentStep(currentStep + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
if (currentStep > 0) {
|
||||
setCurrentStep(currentStep - 1);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="min-h-screen bg-gradient-to-b from-slate-50 to-slate-100 py-12 px-4 sm:px-6 lg:px-8"
|
||||
>
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="text-center mb-12">
|
||||
<h1 className="text-4xl font-extrabold tracking-tight text-slate-900 sm:text-5xl mb-4">
|
||||
Configure Your <span className="text-indigo-600">Digital Twin</span>
|
||||
</h1>
|
||||
<p className="text-xl text-slate-600 max-w-3xl mx-auto">
|
||||
Personalize your AI companion in just a few steps
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-8">
|
||||
<div className="flex justify-between mb-2">
|
||||
{onboardingSteps.map((step, index) => (
|
||||
<div
|
||||
key={step.id}
|
||||
className={`flex flex-col items-center ${index < onboardingSteps.length - 1 ? 'flex-1' : ''}`}
|
||||
>
|
||||
<div
|
||||
className={`w-10 h-10 rounded-full flex items-center justify-center mb-2 transition-colors ${
|
||||
currentStep >= index
|
||||
? 'bg-indigo-600 text-white'
|
||||
: 'bg-slate-200 text-slate-600'
|
||||
} ${
|
||||
completedSteps.has(step.id) ? 'ring-2 ring-offset-2 ring-indigo-500' : ''
|
||||
}`}
|
||||
>
|
||||
{index + 1}
|
||||
</div>
|
||||
<span
|
||||
className={`text-sm font-medium ${
|
||||
currentStep === index ? 'text-indigo-600' : 'text-slate-600'
|
||||
}`}
|
||||
>
|
||||
{step.title}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="relative h-2 bg-slate-200 rounded-full overflow-hidden">
|
||||
<div
|
||||
ref={progressRef}
|
||||
className="absolute top-0 left-0 h-full bg-indigo-600 transition-all duration-300 ease-out"
|
||||
style={{
|
||||
width: `${(currentStep / (onboardingSteps.length - 1)) * 100}%`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card className="onboarding-card shadow-xl">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-4 mb-2">
|
||||
{onboardingSteps[currentStep].icon}
|
||||
<div>
|
||||
<CardTitle className="text-2xl">
|
||||
{onboardingSteps[currentStep].title}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
{onboardingSteps[currentStep].description}
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-8">
|
||||
{onboardingSteps[currentStep].component}
|
||||
|
||||
<div className="flex justify-between pt-6 border-t border-slate-200">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleBack}
|
||||
disabled={currentStep === 0}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleNext}
|
||||
className="gap-2"
|
||||
>
|
||||
{currentStep === onboardingSteps.length - 1 ? (
|
||||
<>
|
||||
Complete Setup <Rocket className="w-4 h-4" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Next Step
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
Loading…
Add table
Reference in a new issue