Refactor: Make system responsive

This commit is contained in:
gpt-engineer-app[bot]
2025-10-29 15:02:56 +00:00
parent b9d7db533c
commit d3c2e31d15
9 changed files with 248 additions and 74 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ export function CreateAgentDialog({ open, onOpenChange }: CreateAgentDialogProps
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl"> <DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader> <DialogHeader>
<DialogTitle>Criar Novo Agente</DialogTitle> <DialogTitle>Criar Novo Agente</DialogTitle>
<DialogDescription> <DialogDescription>
+3 -1
View File
@@ -1,11 +1,13 @@
import { AppSidebar } from "./AppSidebar"; import { AppSidebar } from "./AppSidebar";
import { MobileNav } from "./MobileNav";
import { Outlet } from "react-router-dom"; import { Outlet } from "react-router-dom";
export function AppLayout() { export function AppLayout() {
return ( return (
<div className="flex h-screen w-full bg-background overflow-hidden"> <div className="flex h-screen w-full bg-background overflow-hidden">
<MobileNav />
<AppSidebar /> <AppSidebar />
<main className="flex-1 p-6 lg:p-8 overflow-y-auto"> <main className="flex-1 p-4 md:p-6 lg:p-8 overflow-y-auto pt-16 md:pt-6">
<Outlet /> <Outlet />
</main> </main>
</div> </div>
+74
View File
@@ -0,0 +1,74 @@
import { useState } from "react";
import { NavLink } from "react-router-dom";
import { Bot, FileText, TestTube, Menu, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ThemeToggle } from "./ThemeToggle";
const menuItems = [
{ title: "Agentes", url: "/agents", icon: Bot },
{ title: "Prompts", url: "/", icon: FileText },
{ title: "Testar Prompt", url: "/test", icon: TestTube },
];
export function MobileNav() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
{/* Mobile Header */}
<header className="md:hidden fixed top-0 left-0 right-0 z-50 bg-background border-b border-border px-4 py-3 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-primary to-secondary flex items-center justify-center">
<span className="text-xs font-bold text-white">HX</span>
</div>
<h1 className="text-lg font-bold gradient-text">HGTX PromptLab</h1>
</div>
<div className="flex items-center gap-2">
<ThemeToggle />
<Button
variant="ghost"
size="icon"
onClick={() => setIsOpen(!isOpen)}
>
{isOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
</Button>
</div>
</header>
{/* Mobile Menu Overlay */}
{isOpen && (
<>
<div
className="md:hidden fixed inset-0 bg-background/80 backdrop-blur-sm z-40"
onClick={() => setIsOpen(false)}
/>
<nav className="md:hidden fixed top-[57px] left-0 right-0 bg-background border-b border-border z-40 animate-fade-in">
<div className="px-4 py-2 space-y-1">
{menuItems.map((item) => {
const Icon = item.icon;
return (
<NavLink
key={item.title}
to={item.url}
end
onClick={() => setIsOpen(false)}
className={({ isActive }) =>
`flex items-center gap-3 px-4 py-3 rounded-lg transition-all ${
isActive
? "bg-sidebar-accent text-sidebar-accent-foreground"
: "text-foreground hover:bg-accent"
}`
}
>
<Icon className="w-5 h-5" />
<span className="font-medium">{item.title}</span>
</NavLink>
);
})}
</div>
</nav>
</>
)}
</>
);
}
@@ -80,7 +80,7 @@ Siga estas diretrizes em todas as suas interações.`;
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-5xl max-h-[90vh] overflow-y-auto"> <DialogContent className="max-w-5xl max-h-[90vh] overflow-y-auto w-[95vw] sm:w-full">
<DialogHeader> <DialogHeader>
<DialogTitle>Criar Novo Prompt</DialogTitle> <DialogTitle>Criar Novo Prompt</DialogTitle>
<DialogDescription> <DialogDescription>
+1 -1
View File
@@ -83,7 +83,7 @@ export function EditPromptDialog({ open, onOpenChange, prompt }: EditPromptDialo
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-5xl max-h-[90vh] overflow-y-auto"> <DialogContent className="max-w-5xl max-h-[90vh] overflow-y-auto w-[95vw] sm:w-full">
<DialogHeader> <DialogHeader>
<DialogTitle>Editar Prompt</DialogTitle> <DialogTitle>Editar Prompt</DialogTitle>
<DialogDescription> <DialogDescription>
@@ -120,7 +120,7 @@ export function PromptHistoryDialog({ open, onOpenChange, prompt }: PromptHistor
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl max-h-[90vh]"> <DialogContent className="max-w-4xl max-h-[90vh] w-[95vw] sm:w-full">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex items-center gap-2"> <DialogTitle className="flex items-center gap-2">
<GitBranch className="h-5 w-5" /> <GitBranch className="h-5 w-5" />
+116 -61
View File
@@ -56,14 +56,14 @@ export default function Agents() {
return ( return (
<div className="animate-fade-in"> <div className="animate-fade-in">
<div className="flex items-center justify-between mb-6"> <div className="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
<div> <div>
<h1 className="text-3xl font-bold text-foreground mb-2">Gestão de Agentes</h1> <h1 className="text-2xl md:text-3xl font-bold text-foreground mb-2">Gestão de Agentes</h1>
<p className="text-muted-foreground"> <p className="text-sm md:text-base text-muted-foreground">
Crie e gerencie agentes de IA com prompts e modelos específicos Crie e gerencie agentes de IA com prompts e modelos específicos
</p> </p>
</div> </div>
<Button className="gap-2" onClick={() => setIsCreateDialogOpen(true)}> <Button className="gap-2 w-full md:w-auto" onClick={() => setIsCreateDialogOpen(true)}>
<Plus className="h-4 w-4" /> <Plus className="h-4 w-4" />
Criar Agente Criar Agente
</Button> </Button>
@@ -89,64 +89,119 @@ export default function Agents() {
<p className="text-muted-foreground">Nenhum agente encontrado.</p> <p className="text-muted-foreground">Nenhum agente encontrado.</p>
</div> </div>
) : ( ) : (
<div className="rounded-md border"> <>
<Table> {/* Mobile Cards */}
<TableHeader> <div className="md:hidden space-y-4">
<TableRow> {filteredAgents.map((agent) => (
<TableHead>Nome</TableHead> <div key={agent.id} className="bg-card border rounded-lg p-4 space-y-3">
<TableHead>Prompt</TableHead> <div className="flex items-start justify-between">
<TableHead>Modelo</TableHead> <div>
<TableHead>Criado</TableHead> <h3 className="font-medium text-lg">{agent.name}</h3>
<TableHead>Status</TableHead> <p className="text-sm text-muted-foreground">{agent.createdAt}</p>
<TableHead className="text-right">Ações</TableHead> </div>
</TableRow> <DropdownMenu>
</TableHeader> <DropdownMenuTrigger asChild>
<TableBody> <Button variant="ghost" size="icon">
{filteredAgents.map((agent) => ( <MoreVertical className="h-4 w-4" />
<TableRow key={agent.id}> </Button>
<TableCell className="font-medium">{agent.name}</TableCell> </DropdownMenuTrigger>
<TableCell>{agent.prompt}</TableCell> <DropdownMenuContent align="end">
<TableCell> <DropdownMenuItem onClick={() => console.log("Edit", agent.id)}>
<code className="text-xs bg-muted px-2 py-1 rounded"> <Edit className="h-4 w-4 mr-2" />
{agent.model} Editar
</code> </DropdownMenuItem>
</TableCell> <DropdownMenuItem
<TableCell>{agent.createdAt}</TableCell> onClick={() => console.log("Delete", agent.id)}
<TableCell> className="text-destructive"
<Badge >
variant={agent.status === "active" ? "default" : "secondary"} <Trash2 className="h-4 w-4 mr-2" />
className={agent.status === "active" ? "bg-green-600 hover:bg-green-700" : "bg-muted text-muted-foreground hover:bg-muted"} Excluir
> </DropdownMenuItem>
{agent.status === "active" ? "Ativo" : "Inativo"} </DropdownMenuContent>
</Badge> </DropdownMenu>
</TableCell> </div>
<TableCell className="text-right"> <div className="space-y-2">
<DropdownMenu> <div>
<DropdownMenuTrigger asChild> <span className="text-xs text-muted-foreground">Prompt:</span>
<Button variant="ghost" size="icon"> <p className="text-sm">{agent.prompt}</p>
<MoreVertical className="h-4 w-4" /> </div>
</Button> <div>
</DropdownMenuTrigger> <span className="text-xs text-muted-foreground">Modelo:</span>
<DropdownMenuContent align="end"> <p className="text-sm">
<DropdownMenuItem onClick={() => console.log("Edit", agent.id)}> <code className="text-xs bg-muted px-2 py-1 rounded">{agent.model}</code>
<Edit className="h-4 w-4 mr-2" /> </p>
Editar </div>
</DropdownMenuItem> </div>
<DropdownMenuItem <Badge
onClick={() => console.log("Delete", agent.id)} variant={agent.status === "active" ? "default" : "secondary"}
className="text-destructive" className={agent.status === "active" ? "bg-green-600 hover:bg-green-700" : "bg-muted text-muted-foreground hover:bg-muted"}
> >
<Trash2 className="h-4 w-4 mr-2" /> {agent.status === "active" ? "Ativo" : "Inativo"}
Excluir </Badge>
</DropdownMenuItem> </div>
</DropdownMenuContent> ))}
</DropdownMenu> </div>
</TableCell>
{/* Desktop Table */}
<div className="hidden md:block rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Nome</TableHead>
<TableHead>Prompt</TableHead>
<TableHead>Modelo</TableHead>
<TableHead>Criado</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Ações</TableHead>
</TableRow> </TableRow>
))} </TableHeader>
</TableBody> <TableBody>
</Table> {filteredAgents.map((agent) => (
</div> <TableRow key={agent.id}>
<TableCell className="font-medium">{agent.name}</TableCell>
<TableCell>{agent.prompt}</TableCell>
<TableCell>
<code className="text-xs bg-muted px-2 py-1 rounded">
{agent.model}
</code>
</TableCell>
<TableCell>{agent.createdAt}</TableCell>
<TableCell>
<Badge
variant={agent.status === "active" ? "default" : "secondary"}
className={agent.status === "active" ? "bg-green-600 hover:bg-green-700" : "bg-muted text-muted-foreground hover:bg-muted"}
>
{agent.status === "active" ? "Ativo" : "Inativo"}
</Badge>
</TableCell>
<TableCell className="text-right">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<MoreVertical className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => console.log("Edit", agent.id)}>
<Edit className="h-4 w-4 mr-2" />
Editar
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => console.log("Delete", agent.id)}
className="text-destructive"
>
<Trash2 className="h-4 w-4 mr-2" />
Excluir
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</>
)} )}
<CreateAgentDialog <CreateAgentDialog
+48 -5
View File
@@ -144,14 +144,14 @@ export default function Prompts() {
return ( return (
<div className="animate-fade-in"> <div className="animate-fade-in">
<div className="flex items-center justify-between mb-6"> <div className="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
<div> <div>
<h1 className="text-3xl font-bold text-foreground mb-2">Gestão de Prompts</h1> <h1 className="text-2xl md:text-3xl font-bold text-foreground mb-2">Gestão de Prompts</h1>
<p className="text-muted-foreground"> <p className="text-sm md:text-base text-muted-foreground">
Crie, edite e gerencie os prompts dos seus agentes de IA Crie, edite e gerencie os prompts dos seus agentes de IA
</p> </p>
</div> </div>
<Button className="gap-2" onClick={() => setIsCreateDialogOpen(true)}> <Button className="gap-2 w-full md:w-auto" onClick={() => setIsCreateDialogOpen(true)}>
<Plus className="h-4 w-4" /> <Plus className="h-4 w-4" />
Criar Prompt Criar Prompt
</Button> </Button>
@@ -178,7 +178,50 @@ export default function Prompts() {
</div> </div>
) : ( ) : (
<> <>
<div className="rounded-md border"> {/* Mobile Cards */}
<div className="md:hidden space-y-4 mb-6">
{paginatedPrompts.map((prompt) => (
<div key={prompt.id} className="bg-card border rounded-lg p-4 space-y-3">
<div className="flex items-start justify-between">
<div className="flex-1">
<h3 className="font-medium text-lg">{prompt.title}</h3>
<p className="text-sm text-muted-foreground mt-1">
por {prompt.creator} {prompt.lastModified}
</p>
</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<MoreVertical className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => handleEditPrompt(prompt)}>
<Edit className="h-4 w-4 mr-2" />
Editar
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleViewHistory(prompt)}>
<History className="h-4 w-4 mr-2" />
Histórico
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="flex items-center justify-between">
<code className="text-xs bg-muted px-2 py-1 rounded">{prompt.version}</code>
<Badge
variant={prompt.status === "published" ? "default" : "secondary"}
className={prompt.status === "published" ? "bg-green-600 hover:bg-green-700" : "bg-muted text-muted-foreground hover:bg-muted"}
>
{prompt.status === "published" ? "Publicado" : "Rascunho"}
</Badge>
</div>
</div>
))}
</div>
{/* Desktop Table */}
<div className="hidden md:block rounded-md border">
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
+3 -3
View File
@@ -67,9 +67,9 @@ export default function TestPrompt() {
return ( return (
<div className="animate-fade-in h-full flex flex-col max-w-5xl mx-auto"> <div className="animate-fade-in h-full flex flex-col max-w-5xl mx-auto">
<div className="mb-6"> <div className="mb-4 md:mb-6">
<h1 className="text-3xl font-bold text-foreground mb-2">Teste de Prompt</h1> <h1 className="text-2xl md:text-3xl font-bold text-foreground mb-2">Teste de Prompt</h1>
<p className="text-muted-foreground"> <p className="text-sm md:text-base text-muted-foreground">
Converse com a IA para testar como o prompt se comporta Converse com a IA para testar como o prompt se comporta
</p> </p>
</div> </div>