diff --git a/community-chatbot/.gitignore b/community-chatbot/.gitignore index f398c97d..e7fbc9c1 100644 --- a/community-chatbot/.gitignore +++ b/community-chatbot/.gitignore @@ -31,3 +31,4 @@ next-env.d.ts __pycache__/ *.sql *.py +Jira/ \ No newline at end of file diff --git a/community-chatbot/app/(agent)/[mode]/page.tsx b/community-chatbot/app/(agent)/[mode]/page.tsx index d44365fd..ef8c38e3 100644 --- a/community-chatbot/app/(agent)/[mode]/page.tsx +++ b/community-chatbot/app/(agent)/[mode]/page.tsx @@ -4,8 +4,8 @@ import Image from 'next/image'; import { usePathname } from 'next/navigation'; import { - Card, CardContent, CardDescription, - CardHeader, CardTitle, + Card, CardContent, CardDescription, + CardHeader, CardTitle, } from '@/components/ui/card'; import { integrationModes } from '@/lib/constants/chat'; diff --git a/community-chatbot/app/(agent)/layout.tsx b/community-chatbot/app/(agent)/layout.tsx index 5f1ce780..7ba8fdb4 100644 --- a/community-chatbot/app/(agent)/layout.tsx +++ b/community-chatbot/app/(agent)/layout.tsx @@ -5,6 +5,7 @@ import React, { useEffect } from 'react'; import { ChatHeader } from '@/components/agent/Header'; import { ModeSelector } from '@/components/agent/ModeSelector'; import { AppSidebar } from '@/components/agent/Sidebar'; +import { AppTour } from '@/components/agent/AppTour'; import { useAgentStore } from '@/lib/store/agent/agentStore'; export default function RootLayout({ @@ -21,6 +22,7 @@ export default function RootLayout({ return (
+
diff --git a/community-chatbot/app/globals.css b/community-chatbot/app/globals.css index ac684423..988e7d61 100644 --- a/community-chatbot/app/globals.css +++ b/community-chatbot/app/globals.css @@ -48,6 +48,7 @@ body { --sidebar-border: 220 13% 91%; --sidebar-ring: 217.2 91.2% 59.8%; } + .dark { --background: 0 0% 3.9%; --foreground: 0 0% 98%; @@ -92,3 +93,44 @@ body { @apply bg-background text-foreground; } } + +@layer utilities { + + /* Minimal aesthetic scrollbar */ + .scrollbar-aesthetic { + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: rgba(0, 0, 0, 0.8) transparent; + } + + /* Chrome / Edge / Safari */ + .scrollbar-aesthetic::-webkit-scrollbar { + width: 6px; + } + + .scrollbar-aesthetic::-webkit-scrollbar-track { + background: transparent; + } + + .scrollbar-aesthetic::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.5); + border-radius: 9999px; + } + + .scrollbar-aesthetic::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 1); + } + + /* Dark mode */ + .dark .scrollbar-aesthetic { + scrollbar-color: rgba(255, 255, 255, 0.3) transparent; + } + + .dark .scrollbar-aesthetic::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + } + + .dark .scrollbar-aesthetic::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.5); + } +} \ No newline at end of file diff --git a/community-chatbot/components/agent/AppTour.tsx b/community-chatbot/components/agent/AppTour.tsx new file mode 100644 index 00000000..0fa1e65d --- /dev/null +++ b/community-chatbot/components/agent/AppTour.tsx @@ -0,0 +1,42 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import Joyride, { CallBackProps, STATUS } from 'react-joyride'; +import { TourTooltip } from '@/components/agent/AppTour/TourTooltip'; +import { getJoyrideStyles } from '@/components/agent/AppTour/styles'; +import { steps } from '@/components/agent/AppTour/steps'; + +export function AppTour() { + const [run, setRun] = useState(false); + + useEffect(() => { + const hasSeenTour = localStorage.getItem('hasSeenAppTour'); + if (!hasSeenTour) { + setRun(true); + } + }, []); + + const handleJoyrideCallback = (data: CallBackProps) => { + const { status } = data; + const finishedStatuses: string[] = [STATUS.FINISHED, STATUS.SKIPPED]; + + if (finishedStatuses.includes(status)) { + setRun(false); + localStorage.setItem('hasSeenAppTour', 'true'); + } + }; + + return ( + + ); +} diff --git a/community-chatbot/components/agent/AppTour/TourTooltip.tsx b/community-chatbot/components/agent/AppTour/TourTooltip.tsx new file mode 100644 index 00000000..3d35432a --- /dev/null +++ b/community-chatbot/components/agent/AppTour/TourTooltip.tsx @@ -0,0 +1,73 @@ +'use client'; + +import React from 'react'; +import { TooltipRenderProps } from 'react-joyride'; +import { X, ArrowRight, ArrowLeft, Check } from 'lucide-react'; +import { Button } from '@/components/ui/button'; + +export function TourTooltip({ + index, + step, + backProps, + primaryProps, + skipProps, + isLastStep, +}: TooltipRenderProps) { + return ( +
+ {/* Header / Step Progress */} +
+ + Step {index + 1} + + +
+ + {/* Content Area */} +
+ {step.content} +
+ + {/* Footer / Navigation */} +
+ {index > 0 && ( + + )} + +
+ + +
+
+ ); +} diff --git a/community-chatbot/components/agent/AppTour/steps.tsx b/community-chatbot/components/agent/AppTour/steps.tsx new file mode 100644 index 00000000..a900e3c7 --- /dev/null +++ b/community-chatbot/components/agent/AppTour/steps.tsx @@ -0,0 +1,77 @@ +import { Step } from "react-joyride"; + +export const steps: Step[] = [ + { + target: 'body', + content: ( +
+

Welcome

+

+ Welcome to your workspace. This app uses different assistants for different tasks. Let’s take a quick tour. +

+
+ ), + placement: 'center', + disableBeacon: true, + }, + { + target: '#mode-selector', + content: ( +
+

Assistants

+

+ Select an assistant based on what you want to do. Each assistant is designed for a specific type of work. +

+
+ ), + placement: 'bottom', + }, + { + target: '#active-assistant', + content: ( +
+

Current Assistant

+

+ Only one assistant can be active at a time. All actions and responses follow this selection. +

+
+ ), + placement: 'bottom', + }, + { + target: '#chat-history', + content: ( +
+

Conversation History

+

+ This shows past conversations for the selected assistant. Each assistant has its own history. +

+
+ ), + placement: 'right', + }, + { + target: '#new-chat-button', + content: ( +
+

New Chat

+

+ Start a new conversation here. The chat will belong to the currently selected assistant. +

+
+ ), + placement: 'bottom', + }, + { + target: 'body', + content: ( +
+

All Set

+

+ You’re ready to begin. Choose an assistant and start your first conversation. +

+
+ ), + placement: 'center', + }, +]; diff --git a/community-chatbot/components/agent/AppTour/styles.ts b/community-chatbot/components/agent/AppTour/styles.ts new file mode 100644 index 00000000..c9ce362d --- /dev/null +++ b/community-chatbot/components/agent/AppTour/styles.ts @@ -0,0 +1,14 @@ +export const getJoyrideStyles = () => ({ + options: { + overlayColor: 'rgba(0, 0, 0, 0.6)', + primaryColor: '#2563eb', + zIndex: 10000, + }, + spotlight: { + borderRadius: '1rem', + }, + tooltip: { + backgroundColor: 'transparent', + padding: 0, + }, +}); diff --git a/community-chatbot/components/agent/Header/HeaderActions.tsx b/community-chatbot/components/agent/Header/HeaderActions.tsx index 4fe1ea7f..24bd0f15 100644 --- a/community-chatbot/components/agent/Header/HeaderActions.tsx +++ b/community-chatbot/components/agent/Header/HeaderActions.tsx @@ -14,7 +14,7 @@ export function HeaderActions() { const { isCreatingConversation } = useAgentStore(); return ( -
+