feat: update Makelore modules and conversations
This commit is contained in:
1 parent
b8ca3f8eea
commit
80e8386fa6
175 files changed
+8036
-10581
No files matched your search
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
|
||||
import { Bot, FolderKanban, Loader2, Plus, RefreshCw, X } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { IMAGE_WORKSPACE_CREATE_PROJECT_EVENT } from '@/lib/image-workspace';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useImageWorkspaceStore } from '@/stores/image-workspace';
|
||||
@@ -93,59 +94,64 @@ export function ImageWorkspaceSidebar({ sidebarCollapsed }: ImageWorkspaceSideba
|
||||
};
|
||||
|
||||
return (
|
||||
<div data-testid="sidebar-image-workspace" className="min-h-0">
|
||||
<div data-testid="sidebar-image-workspace" className="min-h-0 space-y-1">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
data-testid="sidebar-create-image-project"
|
||||
className={cn(
|
||||
'mb-2 w-full border-2 border-[#26384D] bg-[#E9EFF5] text-[#26384D] shadow-[3px_3px_0_#26384D] hover:bg-[#DCE6EF]',
|
||||
sidebarCollapsed && 'px-0',
|
||||
'motion-press flex min-h-9 w-full items-center gap-2 rounded-lg border-0 bg-transparent px-2 py-1.5 text-left text-sm font-medium text-foreground shadow-none transition-colors hover:bg-surface-subtle active:scale-[0.985]',
|
||||
sidebarCollapsed && 'justify-center px-0',
|
||||
)}
|
||||
aria-label="新建项目"
|
||||
onClick={openCreateDialog}
|
||||
disabled={status !== 'ready'}
|
||||
>
|
||||
<Plus className={cn('h-4 w-4', !sidebarCollapsed && 'mr-2')} />
|
||||
<Plus className="h-4 w-4 shrink-0 text-brand" />
|
||||
{!sidebarCollapsed && '新建项目'}
|
||||
</Button>
|
||||
|
||||
<div className="mt-4 border-t-2 border-[#DCE6EF] pt-4">
|
||||
<div className="mt-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setProjectsOpen((open) => !open)}
|
||||
aria-expanded={projectsOpen}
|
||||
aria-controls="sidebar-image-projects"
|
||||
className={cn(
|
||||
'flex w-full items-center gap-2.5 rounded-lg px-2.5 py-2 text-left text-sm font-black transition-colors hover:bg-[#FFFFFF]',
|
||||
'motion-press flex min-h-8 w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left text-xs font-semibold text-muted-foreground transition-colors hover:bg-surface-subtle hover:text-foreground',
|
||||
sidebarCollapsed && 'justify-center px-0',
|
||||
)}
|
||||
>
|
||||
<FolderKanban className="h-[18px] w-[18px] shrink-0" />
|
||||
<FolderKanban className="h-4 w-4 shrink-0" />
|
||||
{!sidebarCollapsed ? (
|
||||
<>
|
||||
<span className="min-w-0 flex-1 truncate">项目</span>
|
||||
<span className="min-w-0 flex-1 truncate">项目列表</span>
|
||||
<span className="text-xs">{projectsOpen ? '收起' : '展开'}</span>
|
||||
</>
|
||||
) : null}
|
||||
</button>
|
||||
|
||||
{projectsOpen && !sidebarCollapsed ? (
|
||||
<div data-testid="sidebar-image-projects" className="mt-2 space-y-2">
|
||||
<div id="sidebar-image-projects" data-testid="sidebar-image-projects" className="mt-1 space-y-1">
|
||||
{status === 'idle' || status === 'loading' ? (
|
||||
<div className="flex items-center gap-2 rounded-lg border-2 border-dashed border-[#DCE6EF] bg-white/70 p-3 text-xs font-bold text-[#68788B]">
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
正在读取创作空间
|
||||
<div role="status" className="rounded-lg border border-dashed border-border/80 bg-background/60 px-3 py-3 text-xs font-medium text-muted-foreground">
|
||||
<div className="flex items-center gap-2">
|
||||
<Loader2 className="h-4 w-4 animate-spin text-brand" />
|
||||
正在读取创作空间
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{status === 'unavailable' || status === 'error' ? (
|
||||
<div
|
||||
data-testid="sidebar-image-workspace-unavailable"
|
||||
className="rounded-lg border-2 border-dashed border-[#26384D] bg-[#FFFFFF] p-3 text-xs font-bold text-[#68788B]"
|
||||
className="rounded-lg border border-destructive/20 bg-destructive/5 px-3 py-3 text-xs font-medium text-muted-foreground"
|
||||
>
|
||||
<p className="font-black text-[#26384D]">创作空间暂不可用</p>
|
||||
<p className="font-semibold text-foreground">创作空间暂不可用</p>
|
||||
{workspaceError ? <p className="mt-1 break-words">{workspaceError}</p> : null}
|
||||
<button
|
||||
type="button"
|
||||
className="mt-3 flex items-center gap-1.5 rounded-md border-2 border-[#26384D] bg-white px-2 py-1.5 font-black text-[#26384D]"
|
||||
className="motion-press mt-2 flex items-center gap-1.5 rounded-md bg-transparent px-1.5 py-1.5 font-semibold text-foreground hover:bg-background"
|
||||
onClick={() => void load()}
|
||||
>
|
||||
<RefreshCw className="h-3.5 w-3.5" />
|
||||
@@ -155,8 +161,9 @@ export function ImageWorkspaceSidebar({ sidebarCollapsed }: ImageWorkspaceSideba
|
||||
) : null}
|
||||
|
||||
{status === 'ready' && snapshot?.projects.length === 0 ? (
|
||||
<div className="rounded-lg border-2 border-dashed border-[#DCE6EF] bg-white/70 p-3 text-xs font-bold text-[#68788B]">
|
||||
暂无项目。新建项目后,创作空间会自动创建默认 Agent。
|
||||
<div className="rounded-lg border border-dashed border-border/80 bg-background/60 px-3 py-3 text-xs font-medium leading-5 text-muted-foreground">
|
||||
<span className="font-semibold text-foreground">还没有绘画项目</span>
|
||||
<span className="mt-1 block">新建项目后请手动添加 Agent。</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -168,42 +175,47 @@ export function ImageWorkspaceSidebar({ sidebarCollapsed }: ImageWorkspaceSideba
|
||||
key={project.id}
|
||||
data-testid={`sidebar-image-project-${project.id}`}
|
||||
className={cn(
|
||||
'rounded-lg border-2 p-3 text-left',
|
||||
'motion-press group/project relative overflow-hidden rounded-lg border px-2 py-1.5 text-left transition-[background-color,border-color,color]',
|
||||
active
|
||||
? 'border-[#26384D] bg-[#DCE6EF] shadow-[4px_4px_0_#26384D]'
|
||||
: 'border-[#DCE6EF] bg-[#FFFFFF]',
|
||||
? 'border-brand/35 bg-brand-soft shadow-soft before:absolute before:inset-y-2 before:left-0 before:w-0.5 before:rounded-full before:bg-brand'
|
||||
: 'border-transparent bg-transparent hover:border-border/70 hover:bg-surface-subtle',
|
||||
)}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full items-center gap-2 text-left"
|
||||
aria-current={active ? 'page' : undefined}
|
||||
className="flex w-full min-w-0 items-center gap-2 text-left"
|
||||
onClick={() => handleSelectProject(project.id)}
|
||||
>
|
||||
<FolderKanban className="h-4 w-4 shrink-0" />
|
||||
<span className="min-w-0 flex-1 truncate text-sm font-black">{project.name}</span>
|
||||
<span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-surface-input text-foreground">
|
||||
<FolderKanban className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
<span className="min-w-0 flex-1 truncate text-sm font-medium">{project.name}</span>
|
||||
<span className="shrink-0 text-[10px] font-medium text-muted-foreground">{project.agents.length} 个 Agent</span>
|
||||
</button>
|
||||
|
||||
<div className="mt-3 space-y-1.5" aria-label={`${project.name} 的 Agent`}>
|
||||
<div className="mt-1.5 space-y-0.5 pl-9" aria-label={`${project.name} 的 Agent`}>
|
||||
{project.agents.map((agent) => (
|
||||
<button
|
||||
key={agent.id}
|
||||
type="button"
|
||||
aria-pressed={active && selectedAgentId === agent.id}
|
||||
aria-current={active && selectedAgentId === agent.id ? 'page' : undefined}
|
||||
onClick={() => {
|
||||
selectProject(project.id);
|
||||
selectAgent(project.id, agent.id);
|
||||
navigate('/image-canvas');
|
||||
}}
|
||||
className={cn(
|
||||
'flex w-full items-center gap-2 rounded-md border-2 border-[#26384D] px-2 py-1.5 text-left text-xs font-black',
|
||||
active && selectedAgentId === agent.id ? 'bg-white' : 'bg-white/60',
|
||||
'motion-press flex w-full items-center gap-2 rounded-md border-0 bg-transparent px-2 py-1.5 text-left text-xs font-medium transition-colors hover:bg-background',
|
||||
active && selectedAgentId === agent.id ? 'bg-background font-semibold shadow-soft' : '',
|
||||
)}
|
||||
>
|
||||
<span className="flex h-6 w-6 shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-[#26384D] bg-[#E9EFF5]">
|
||||
<span className="flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-lg border border-border bg-surface-tertiary">
|
||||
{agent.avatarUrl ? (
|
||||
<img src={agent.avatarUrl} alt="" className="h-full w-full object-cover" />
|
||||
) : (
|
||||
<Bot className="h-3.5 w-3.5" />
|
||||
<Bot className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
)}
|
||||
</span>
|
||||
<span className="min-w-0 flex-1 truncate">{agent.name}</span>
|
||||
@@ -213,7 +225,7 @@ export function ImageWorkspaceSidebar({ sidebarCollapsed }: ImageWorkspaceSideba
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`为 ${project.name} 添加 Agent`}
|
||||
className="flex w-full items-center justify-center gap-1.5 rounded-md border-2 border-dashed border-[#26384D] bg-white/70 px-2 py-1.5 text-xs font-black"
|
||||
className="motion-press flex w-full items-center gap-1.5 rounded-md border-0 bg-transparent px-2 py-1.5 text-left text-xs font-semibold text-brand hover:bg-background"
|
||||
onClick={() => void handleAddAgent(project.id)}
|
||||
disabled={addingAgentProjectId === project.id}
|
||||
>
|
||||
@@ -227,34 +239,39 @@ export function ImageWorkspaceSidebar({ sidebarCollapsed }: ImageWorkspaceSideba
|
||||
);
|
||||
}) : null}
|
||||
|
||||
{agentError ? <p role="alert" className="rounded-md bg-[#ffd6d6] p-2 text-xs font-black">{agentError}</p> : null}
|
||||
{agentError ? <p role="alert" className="rounded-md bg-destructive/10 p-2 text-xs font-semibold">{agentError}</p> : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{createDialogOpen ? (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/55 px-4">
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="create-image-project-dialog-title"
|
||||
className="w-full max-w-sm rounded-lg border-4 border-[#26384D] bg-[#FFFFFF] p-4 text-[#26384D] shadow-[8px_8px_0_#26384D]"
|
||||
<Dialog
|
||||
open={createDialogOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) closeCreateDialog();
|
||||
}}
|
||||
>
|
||||
<DialogContent
|
||||
className="max-w-sm p-5"
|
||||
onInteractOutside={(event) => {
|
||||
if (creating) event.preventDefault();
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<DialogHeader className="flex-row items-start justify-between gap-3 space-y-0">
|
||||
<div>
|
||||
<h2 id="create-image-project-dialog-title" className="text-xl font-black">新建项目</h2>
|
||||
<p className="mt-1 text-xs font-bold text-[#68788B]">只需填写名称,创作空间会自动创建默认 Agent。</p>
|
||||
<DialogTitle className="text-xl">新建项目</DialogTitle>
|
||||
<DialogDescription className="mt-1 text-xs">填写名称后,再手动添加需要的 Agent。</DialogDescription>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="关闭新建项目"
|
||||
className="flex h-8 w-8 items-center justify-center rounded-md border-2 border-[#26384D] bg-white"
|
||||
className="flex h-8 w-8 items-center justify-center rounded-md border border-foreground/15 bg-white"
|
||||
onClick={closeCreateDialog}
|
||||
disabled={creating}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</DialogHeader>
|
||||
|
||||
<form
|
||||
className="mt-4 space-y-3"
|
||||
@@ -263,7 +280,7 @@ export function ImageWorkspaceSidebar({ sidebarCollapsed }: ImageWorkspaceSideba
|
||||
void handleCreateProject();
|
||||
}}
|
||||
>
|
||||
<label className="block text-xs font-black" htmlFor="image-project-name">项目名称</label>
|
||||
<label className="block text-xs font-semibold" htmlFor="image-project-name">项目名称</label>
|
||||
<input
|
||||
id="image-project-name"
|
||||
value={projectName}
|
||||
@@ -273,23 +290,23 @@ export function ImageWorkspaceSidebar({ sidebarCollapsed }: ImageWorkspaceSideba
|
||||
}}
|
||||
autoFocus
|
||||
disabled={creating}
|
||||
className="w-full rounded-md border-2 border-[#26384D] bg-white px-3 py-2 text-sm font-bold outline-none focus:ring-2 focus:ring-[#DCE6EF]"
|
||||
className="w-full rounded-md border border-foreground/15 bg-white px-3 py-2 text-sm font-medium outline-none focus:ring-2 focus:ring-brand/20"
|
||||
/>
|
||||
{createError ? <p role="alert" className="rounded-md bg-[#ffd6d6] p-2 text-xs font-black">{createError}</p> : null}
|
||||
{createError ? <p role="alert" className="rounded-md bg-destructive/10 p-2 text-xs font-semibold">{createError}</p> : null}
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button type="button" variant="outline" onClick={closeCreateDialog} disabled={creating}>取消</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={creating || !projectName.trim()}
|
||||
className="border-2 border-[#26384D] bg-[#DCE6EF] font-black text-[#26384D]"
|
||||
className="border border-foreground/15 bg-brand-soft font-semibold text-foreground"
|
||||
>
|
||||
{creating ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
|
||||
创建项目
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
) : null}
|
||||
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user