From 480d771841c7c54da944b24b607bdc509d7728ce Mon Sep 17 00:00:00 2001
From: "gpt-engineer-app[bot]"
<159125892+gpt-engineer-app[bot]@users.noreply.github.com>
Date: Thu, 16 Oct 2025 18:40:35 +0000
Subject: [PATCH] Implement HGTX Codex interface
---
index.html | 10 +-
src/components/ChatHeader.tsx | 48 ++++++
src/components/Layout.tsx | 90 +++++++++++
src/components/audio/AudioView.tsx | 222 ++++++++++++++++++++++++++++
src/components/chat/ChatInput.tsx | 70 +++++++++
src/components/chat/ChatMessage.tsx | 72 +++++++++
src/components/chat/ChatView.tsx | 79 ++++++++++
src/components/images/ImageView.tsx | 146 ++++++++++++++++++
src/components/ui/button.tsx | 8 +-
src/index.css | 157 ++++++++++----------
src/pages/Index.tsx | 19 ++-
tailwind.config.ts | 36 +++--
12 files changed, 854 insertions(+), 103 deletions(-)
create mode 100644 src/components/ChatHeader.tsx
create mode 100644 src/components/Layout.tsx
create mode 100644 src/components/audio/AudioView.tsx
create mode 100644 src/components/chat/ChatInput.tsx
create mode 100644 src/components/chat/ChatMessage.tsx
create mode 100644 src/components/chat/ChatView.tsx
create mode 100644 src/components/images/ImageView.tsx
diff --git a/index.html b/index.html
index 0795b05..3b041b8 100644
--- a/index.html
+++ b/index.html
@@ -3,12 +3,12 @@
- hgtx-nova-era
-
-
+ HGTX Codex - AI Interface System
+
+
-
-
+
+
diff --git a/src/components/ChatHeader.tsx b/src/components/ChatHeader.tsx
new file mode 100644
index 0000000..c088fb4
--- /dev/null
+++ b/src/components/ChatHeader.tsx
@@ -0,0 +1,48 @@
+import { ChevronDown } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+
+export const ChatHeader = () => {
+ const models = [
+ "ChatGPT 4.1",
+ "GPT-5 Mini",
+ "Claude 3.5 Sonnet",
+ "Gemini 2.5 Flash",
+ ];
+
+ return (
+
+ );
+};
diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx
new file mode 100644
index 0000000..a92a3e7
--- /dev/null
+++ b/src/components/Layout.tsx
@@ -0,0 +1,90 @@
+import { MessageSquare, Image, Mic, Settings, Plus } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { Separator } from "@/components/ui/separator";
+
+interface LayoutProps {
+ children: React.ReactNode;
+ activeTab: "chat" | "images" | "audio";
+ onTabChange: (tab: "chat" | "images" | "audio") => void;
+}
+
+type TabType = "chat" | "images" | "audio";
+
+export const Layout = ({ children, activeTab, onTabChange }: LayoutProps) => {
+
+ const tabs = [
+ { id: "chat" as TabType, label: "Bate-papo", icon: MessageSquare },
+ { id: "images" as TabType, label: "Imagens", icon: Image },
+ { id: "audio" as TabType, label: "Áudio", icon: Mic },
+ ];
+
+ return (
+
+ {/* Sidebar */}
+
+ {/* Logo */}
+
+
HGTX Codex
+
AI Interface System
+
+
+ {/* New Chat Button */}
+
+
+ {/* Navigation Tabs */}
+
+ {tabs.map((tab) => {
+ const Icon = tab.icon;
+ const isActive = activeTab === tab.id;
+ return (
+ onTabChange(tab.id)}
+ className={`w-full flex items-center gap-3 px-4 py-3 rounded-lg transition-all ${
+ isActive
+ ? "bg-sidebar-accent text-sidebar-accent-foreground cyber-border"
+ : "text-sidebar-foreground hover:bg-sidebar-accent/50"
+ }`}
+ >
+
+ {tab.label}
+
+ );
+ })}
+
+
+
+
+ {/* Recent Section */}
+
+
+ Recentes
+
+
+
+ Conversa anterior...
+
+
+
+
+ {/* Settings */}
+
+
+
+ Configurações
+
+
+
+
+ {/* Main Content */}
+
+ {children}
+
+
+ );
+};
diff --git a/src/components/audio/AudioView.tsx b/src/components/audio/AudioView.tsx
new file mode 100644
index 0000000..4a4ba2c
--- /dev/null
+++ b/src/components/audio/AudioView.tsx
@@ -0,0 +1,222 @@
+import { useState } from "react";
+import { ChatHeader } from "@/components/ChatHeader";
+import { Button } from "@/components/ui/button";
+import { Textarea } from "@/components/ui/textarea";
+import { Upload, Mic, Play, Download, Copy, Trash2 } from "lucide-react";
+import { ScrollArea } from "@/components/ui/scroll-area";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+
+export const AudioView = () => {
+ const [textToSpeech, setTextToSpeech] = useState("");
+ const [isProcessing, setIsProcessing] = useState(false);
+
+ const handleGenerateAudio = () => {
+ setIsProcessing(true);
+ setTimeout(() => setIsProcessing(false), 2000);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ Transcrição de Áudio
+
+ Geração de Voz
+
+
+ {/* Transcription Tab */}
+
+
+
+ Converter Áudio em Texto
+
+
+ Envie um arquivo de áudio (.mp3, .wav) para transcrição
+
+
+
+
+
+
+
+
+ Clique para selecionar ou arraste o arquivo
+
+
+ Suporta MP3, WAV (máx. 25MB)
+
+
+
+
+ Selecionar Arquivo
+
+
+
+
+ {/* Sample Transcription Result */}
+
+
+
+
audio_sample.mp3
+
+ Transcrito há 5 minutos
+
+
+
+
+
+ Copiar
+
+
+
+
+
+
+
+
+
+
+
+ Esta é uma transcrição de exemplo do áudio enviado. O
+ sistema utilizará modelos de IA avançados para converter
+ sua fala em texto com alta precisão.
+
+
+
+
+
+ {/* Generation Tab */}
+
+
+
+ Converter Texto em Voz
+
+
+
+
+ Digite o texto para converter
+
+
+
+
+
+ Tipo de Voz
+
+
+
+
+
+ Neutra
+ Masculina
+ Feminina
+ Infantil
+
+
+
+
+
+
+ {isProcessing ? "Gerando..." : "Gerar Áudio"}
+
+
+
+ {isProcessing && (
+
+
+
+ Processando áudio...
+
+
+ )}
+
+
+ {/* Sample Generated Audio */}
+
+
+
+
Áudio Gerado
+
+ Há 2 minutos · Voz Neutra
+
+
+
+
+
+ Baixar
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0:12 / 0:35
+
+
+
+
+
+
+ {/* History Section */}
+
+
Histórico Recente
+
+ {[1, 2].map((i) => (
+
+
+
+
+
+
+
audio_file_{i}.mp3
+
+ Processado há {i} hora{i > 1 ? "s" : ""}
+
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+ );
+};
diff --git a/src/components/chat/ChatInput.tsx b/src/components/chat/ChatInput.tsx
new file mode 100644
index 0000000..db7c37b
--- /dev/null
+++ b/src/components/chat/ChatInput.tsx
@@ -0,0 +1,70 @@
+import { Send, Paperclip, Mic } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { Textarea } from "@/components/ui/textarea";
+import { useState } from "react";
+
+interface ChatInputProps {
+ onSendMessage: (message: string) => void;
+}
+
+export const ChatInput = ({ onSendMessage }: ChatInputProps) => {
+ const [message, setMessage] = useState("");
+
+ const handleSend = () => {
+ if (message.trim()) {
+ onSendMessage(message);
+ setMessage("");
+ }
+ };
+
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === "Enter" && !e.shiftKey) {
+ e.preventDefault();
+ handleSend();
+ }
+ };
+
+ return (
+
+
+
+
+ Pressione Enter para enviar, Shift + Enter para nova linha
+
+
+
+ );
+};
diff --git a/src/components/chat/ChatMessage.tsx b/src/components/chat/ChatMessage.tsx
new file mode 100644
index 0000000..c925372
--- /dev/null
+++ b/src/components/chat/ChatMessage.tsx
@@ -0,0 +1,72 @@
+import { Bot, User, Copy, Edit, Trash2 } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { useState } from "react";
+
+interface ChatMessageProps {
+ role: "user" | "assistant";
+ content: string;
+}
+
+export const ChatMessage = ({ role, content }: ChatMessageProps) => {
+ const [showActions, setShowActions] = useState(false);
+ const isAssistant = role === "assistant";
+
+ return (
+ setShowActions(true)}
+ onMouseLeave={() => setShowActions(false)}
+ >
+
+ {isAssistant ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ {showActions && (
+
+
+
+ Copiar
+
+
+
+ Editar
+
+
+
+ Excluir
+
+
+ )}
+
+
+ );
+};
diff --git a/src/components/chat/ChatView.tsx b/src/components/chat/ChatView.tsx
new file mode 100644
index 0000000..c876a53
--- /dev/null
+++ b/src/components/chat/ChatView.tsx
@@ -0,0 +1,79 @@
+import { useState } from "react";
+import { ChatHeader } from "@/components/ChatHeader";
+import { ChatMessage } from "./ChatMessage";
+import { ChatInput } from "./ChatInput";
+import { ScrollArea } from "@/components/ui/scroll-area";
+
+interface Message {
+ id: string;
+ role: "user" | "assistant";
+ content: string;
+}
+
+export const ChatView = () => {
+ const [messages, setMessages] = useState([
+ {
+ id: "1",
+ role: "assistant",
+ content: "Olá! Sou o assistente HGTX Codex. Como posso ajudá-lo hoje?",
+ },
+ ]);
+
+ const [isLoading, setIsLoading] = useState(false);
+
+ const handleSendMessage = (content: string) => {
+ const newMessage: Message = {
+ id: Date.now().toString(),
+ role: "user",
+ content,
+ };
+
+ setMessages((prev) => [...prev, newMessage]);
+ setIsLoading(true);
+
+ // Simulate AI response
+ setTimeout(() => {
+ const aiResponse: Message = {
+ id: (Date.now() + 1).toString(),
+ role: "assistant",
+ content:
+ "Esta é uma resposta simulada. Em breve, estarei conectado a modelos de IA reais para fornecer respostas inteligentes e úteis.",
+ };
+ setMessages((prev) => [...prev, aiResponse]);
+ setIsLoading(false);
+ }, 1500);
+ };
+
+ return (
+
+
+
+
+
+ {messages.map((message) => (
+
+ ))}
+
+ {isLoading && (
+
+ )}
+
+
+
+
+
+ );
+};
diff --git a/src/components/images/ImageView.tsx b/src/components/images/ImageView.tsx
new file mode 100644
index 0000000..59a0a9f
--- /dev/null
+++ b/src/components/images/ImageView.tsx
@@ -0,0 +1,146 @@
+import { useState } from "react";
+import { ChatHeader } from "@/components/ChatHeader";
+import { Button } from "@/components/ui/button";
+import { Textarea } from "@/components/ui/textarea";
+import { Download, Copy, Trash2, Sparkles } from "lucide-react";
+import { ScrollArea } from "@/components/ui/scroll-area";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+
+export const ImageView = () => {
+ const [prompt, setPrompt] = useState("");
+ const [isGenerating, setIsGenerating] = useState(false);
+ const [images, setImages] = useState([]);
+
+ const handleGenerate = () => {
+ setIsGenerating(true);
+ // Simulate image generation
+ setTimeout(() => {
+ setImages((prev) => [
+ "https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=512&h=512&fit=crop",
+ ...prev,
+ ]);
+ setIsGenerating(false);
+ }, 3000);
+ };
+
+ return (
+
+
+
+
+
+ {/* Generation Form */}
+
+
+
+ Descreva a imagem
+
+
+
+
+
+
+ Tamanho
+
+
+
+
+
+
+ 512x512
+ 1024x1024
+ 1792x1024 (Wide)
+ 1024x1792 (Tall)
+
+
+
+
+
+
+ {isGenerating ? "Gerando..." : "Gerar Imagem"}
+
+
+
+
+ {/* Loading State */}
+ {isGenerating && (
+
+
+
+ Gerando sua imagem...
+
+
+ Isso pode levar alguns segundos
+
+
+ )}
+
+ {/* Generated Images Grid */}
+ {images.length > 0 && (
+
+
Imagens Geradas
+
+ {images.map((image, index) => (
+
+
+
+
+
+
+ Baixar
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+ )}
+
+
+
+ );
+};
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index cdedd4f..f2e666a 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -5,14 +5,14 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ default: "bg-primary text-primary-foreground hover:bg-primary/90 shadow-lg hover:shadow-primary/50",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
- outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ outline: "border border-border bg-background hover:bg-accent hover:text-accent-foreground",
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-md hover:shadow-secondary/40",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
diff --git a/src/index.css b/src/index.css
index 4844bbd..9f6ee69 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,96 +1,61 @@
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
+
@tailwind base;
@tailwind components;
@tailwind utilities;
-/* Definition of the design system. All colors, gradients, fonts, etc should be defined here.
-All colors MUST be HSL.
-*/
-
@layer base {
:root {
- --background: 0 0% 100%;
- --foreground: 222.2 84% 4.9%;
+ /* HGTX Codex - Cyberpunk Dark Theme */
+ --background: 222 47% 5%;
+ --foreground: 200 100% 95%;
- --card: 0 0% 100%;
- --card-foreground: 222.2 84% 4.9%;
+ --card: 222 40% 8%;
+ --card-foreground: 200 100% 95%;
- --popover: 0 0% 100%;
- --popover-foreground: 222.2 84% 4.9%;
+ --popover: 222 45% 10%;
+ --popover-foreground: 200 100% 95%;
- --primary: 222.2 47.4% 11.2%;
- --primary-foreground: 210 40% 98%;
+ --primary: 190 100% 50%;
+ --primary-foreground: 222 47% 5%;
- --secondary: 210 40% 96.1%;
- --secondary-foreground: 222.2 47.4% 11.2%;
+ --secondary: 210 100% 50%;
+ --secondary-foreground: 222 47% 5%;
- --muted: 210 40% 96.1%;
- --muted-foreground: 215.4 16.3% 46.9%;
+ --muted: 222 30% 15%;
+ --muted-foreground: 200 20% 65%;
- --accent: 210 40% 96.1%;
- --accent-foreground: 222.2 47.4% 11.2%;
+ --accent: 190 100% 60%;
+ --accent-foreground: 222 47% 5%;
- --destructive: 0 84.2% 60.2%;
- --destructive-foreground: 210 40% 98%;
+ --destructive: 0 84% 60%;
+ --destructive-foreground: 200 100% 95%;
- --border: 214.3 31.8% 91.4%;
- --input: 214.3 31.8% 91.4%;
- --ring: 222.2 84% 4.9%;
+ --border: 222 30% 18%;
+ --input: 222 30% 18%;
+ --ring: 190 100% 50%;
- --radius: 0.5rem;
+ --radius: 0.75rem;
- --sidebar-background: 0 0% 98%;
+ /* Sidebar specific */
+ --sidebar-background: 222 45% 7%;
+ --sidebar-foreground: 200 100% 90%;
+ --sidebar-primary: 190 100% 50%;
+ --sidebar-primary-foreground: 222 47% 5%;
+ --sidebar-accent: 222 35% 12%;
+ --sidebar-accent-foreground: 190 100% 60%;
+ --sidebar-border: 222 30% 15%;
+ --sidebar-ring: 190 100% 50%;
- --sidebar-foreground: 240 5.3% 26.1%;
-
- --sidebar-primary: 240 5.9% 10%;
-
- --sidebar-primary-foreground: 0 0% 98%;
-
- --sidebar-accent: 240 4.8% 95.9%;
-
- --sidebar-accent-foreground: 240 5.9% 10%;
-
- --sidebar-border: 220 13% 91%;
-
- --sidebar-ring: 217.2 91.2% 59.8%;
- }
-
- .dark {
- --background: 222.2 84% 4.9%;
- --foreground: 210 40% 98%;
-
- --card: 222.2 84% 4.9%;
- --card-foreground: 210 40% 98%;
-
- --popover: 222.2 84% 4.9%;
- --popover-foreground: 210 40% 98%;
-
- --primary: 210 40% 98%;
- --primary-foreground: 222.2 47.4% 11.2%;
-
- --secondary: 217.2 32.6% 17.5%;
- --secondary-foreground: 210 40% 98%;
-
- --muted: 217.2 32.6% 17.5%;
- --muted-foreground: 215 20.2% 65.1%;
-
- --accent: 217.2 32.6% 17.5%;
- --accent-foreground: 210 40% 98%;
-
- --destructive: 0 62.8% 30.6%;
- --destructive-foreground: 210 40% 98%;
-
- --border: 217.2 32.6% 17.5%;
- --input: 217.2 32.6% 17.5%;
- --ring: 212.7 26.8% 83.9%;
- --sidebar-background: 240 5.9% 10%;
- --sidebar-foreground: 240 4.8% 95.9%;
- --sidebar-primary: 224.3 76.3% 48%;
- --sidebar-primary-foreground: 0 0% 100%;
- --sidebar-accent: 240 3.7% 15.9%;
- --sidebar-accent-foreground: 240 4.8% 95.9%;
- --sidebar-border: 240 3.7% 15.9%;
- --sidebar-ring: 217.2 91.2% 59.8%;
+ /* Custom gradients */
+ --gradient-cyber: linear-gradient(135deg, hsl(190 100% 50%) 0%, hsl(210 100% 50%) 100%);
+ --gradient-subtle: linear-gradient(180deg, hsl(222 45% 8%) 0%, hsl(222 47% 5%) 100%);
+ --glow-cyan: 0 0 40px hsl(190 100% 50% / 0.3);
+ --glow-blue: 0 0 30px hsl(210 100% 50% / 0.25);
+
+ /* Animation speeds */
+ --transition-smooth: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ --transition-bounce: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
}
@@ -100,6 +65,44 @@ All colors MUST be HSL.
}
body {
- @apply bg-background text-foreground;
+ @apply bg-background text-foreground font-sans antialiased;
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
+ }
+
+ /* Scrollbar styling */
+ ::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+ }
+
+ ::-webkit-scrollbar-track {
+ @apply bg-background;
+ }
+
+ ::-webkit-scrollbar-thumb {
+ @apply bg-muted rounded-full;
+ }
+
+ ::-webkit-scrollbar-thumb:hover {
+ @apply bg-primary/50;
+ }
+}
+
+@layer components {
+ .glass-effect {
+ @apply bg-card/40 backdrop-blur-xl border border-border/50;
+ }
+
+ .cyber-glow {
+ box-shadow: var(--glow-cyan);
+ }
+
+ .cyber-border {
+ @apply border border-primary/30 rounded-lg;
+ box-shadow: 0 0 20px hsl(190 100% 50% / 0.1);
+ }
+
+ .gradient-text {
+ @apply bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent;
}
}
diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx
index 7130b54..34b27d9 100644
--- a/src/pages/Index.tsx
+++ b/src/pages/Index.tsx
@@ -1,13 +1,18 @@
-// Update this page (the content is just a fallback if you fail to update the page)
+import { useState } from "react";
+import { Layout } from "@/components/Layout";
+import { ChatView } from "@/components/chat/ChatView";
+import { ImageView } from "@/components/images/ImageView";
+import { AudioView } from "@/components/audio/AudioView";
const Index = () => {
+ const [activeView, setActiveView] = useState<"chat" | "images" | "audio">("chat");
+
return (
-
-
-
Welcome to Your Blank App
-
Start building your amazing project here!
-
-
+
+ {activeView === "chat" && }
+ {activeView === "images" && }
+ {activeView === "audio" && }
+
);
};
diff --git a/tailwind.config.ts b/tailwind.config.ts
index a1edb69..254556f 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -13,6 +13,9 @@ export default {
},
},
extend: {
+ fontFamily: {
+ sans: ['Inter', 'system-ui', 'sans-serif'],
+ },
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
@@ -65,25 +68,38 @@ export default {
},
keyframes: {
"accordion-down": {
- from: {
- height: "0",
- },
- to: {
- height: "var(--radix-accordion-content-height)",
- },
+ from: { height: "0" },
+ to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
- from: {
- height: "var(--radix-accordion-content-height)",
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: "0" },
+ },
+ "pulse-glow": {
+ "0%, 100%": {
+ boxShadow: "0 0 20px hsl(190 100% 50% / 0.3)",
+ transform: "scale(1)"
},
- to: {
- height: "0",
+ "50%": {
+ boxShadow: "0 0 40px hsl(190 100% 50% / 0.5)",
+ transform: "scale(1.02)"
},
},
+ "slide-in-right": {
+ "0%": { transform: "translateX(100%)", opacity: "0" },
+ "100%": { transform: "translateX(0)", opacity: "1" },
+ },
+ "fade-in": {
+ "0%": { opacity: "0", transform: "translateY(10px)" },
+ "100%": { opacity: "1", transform: "translateY(0)" },
+ },
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
+ "pulse-glow": "pulse-glow 2s ease-in-out infinite",
+ "slide-in-right": "slide-in-right 0.3s ease-out",
+ "fade-in": "fade-in 0.3s ease-out",
},
},
},