Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,397 changes: 1,355 additions & 42 deletions frontend/package-lock.json

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,19 @@
"@tabler/icons-react": "^3.40.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2",
"lucide-react": "^1.7.0",
"next-themes": "^0.4.6",
"react": "^19.2.0",
"react-day-picker": "^9.14.0",
"react-dom": "^19.2.0",
"react-resizable-panels": "^4.7.6",
"recharts": "^3.8.1",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"vaul": "^1.1.2",
"zustand": "^5.0.11"
},
"devDependencies": {
Expand Down
10 changes: 10 additions & 0 deletions frontend/skills-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"version": 1,
"skills": {
"vercel-react-best-practices": {
"source": "vercel-labs/agent-skills",
"sourceType": "github",
"computedHash": "bbc31a48537b473ff4feea6360ef0de3bfdcbef26c14f4967a5deefe8ca801d3"
}
}
}
25 changes: 12 additions & 13 deletions frontend/src/components/layout/CenterCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
IconPlayerStop,
IconSend,
} from '@tabler/icons-react';
import { useState } from 'react';
import { useCallback, useState } from 'react';
import { Button } from '@/components/ui/button';
import { ScrollArea } from '@/components/ui/scroll-area';
import { cn } from '@/lib/utils';
Expand Down Expand Up @@ -48,28 +48,27 @@ const mockMessages: Message[] = [
},
];

const modelOptions = ['GPT-4', 'Claude-3', 'DeepSeek'];
const MODEL_OPTIONS = ['GPT-4', 'Claude-3', 'DeepSeek'] as const;

function formatTime(timestamp: number) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+59

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asdf

return new Date(timestamp).toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit',
});
}

export function CenterCanvas() {
const { activeConversationId, setInputFocused } = useLayoutStore(
(state) => state,
);
const [inputValue, setInputValue] = useState('');
const [isGenerating] = useState(false);
const [selectedModel] = useState(modelOptions[0]);
const [selectedModel] = useState(MODEL_OPTIONS[0]);

const handleSend = () => {
const handleSend = useCallback(() => {
if (!inputValue.trim()) return;
setInputValue('');
};

const formatTime = (timestamp: number) => {
const date = new Date(timestamp);
return date.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit',
});
};
}, [inputValue]);

return (
<div className="flex h-full flex-1 flex-col bg-slate-50">
Expand Down
14 changes: 11 additions & 3 deletions frontend/src/components/layout/LeftRail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
IconPlus,
IconTrash,
} from '@tabler/icons-react';
import { useMemo } from 'react';
import { Button } from '@/components/ui/button';
import { ScrollArea } from '@/components/ui/scroll-area';
import { cn } from '@/lib/utils';
Expand All @@ -20,8 +21,15 @@ export function LeftRail() {
deleteConversation,
} = useLayoutStore((state) => state);

const getWorkspaceConversations = (workspaceId: string) =>
conversations.filter((c) => c.workspaceId === workspaceId);
const conversationsByWorkspace = useMemo(() => {
const map = new Map<string, typeof conversations>();
for (const c of conversations) {
const list = map.get(c.workspaceId) ?? [];
list.push(c);
map.set(c.workspaceId, list);
}
return map;
}, [conversations]);

return (
<div className="flex h-full w-[260px] flex-col border-r border-slate-200 bg-white">
Expand Down Expand Up @@ -59,7 +67,7 @@ export function LeftRail() {

{!workspace.collapsed && (
<div className="mt-0.5 ml-4">
{getWorkspaceConversations(workspace.id).map(
{(conversationsByWorkspace.get(workspace.id) ?? []).map(
(conversation) => (
<button
key={conversation.id}
Expand Down
51 changes: 26 additions & 25 deletions frontend/src/components/layout/RightRail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
IconPhoto,
IconUpload,
} from '@tabler/icons-react';
import type { ReactNode } from 'react';
import { Button } from '@/components/ui/button';
import { ScrollArea } from '@/components/ui/scroll-area';
import { cn } from '@/lib/utils';
Expand All @@ -14,10 +15,10 @@ import { useLayoutStore } from '@/store/appStore';
type QuickAction = {
id: string;
label: string;
icon: React.ReactNode;
icon: ReactNode;
};

const quickActions: QuickAction[] = [
const QUICK_ACTIONS: QuickAction[] = [
{
id: 'review',
label: '代码审查',
Expand All @@ -39,7 +40,7 @@ type ArtifactFile = {
updatedAt: number;
};

const mockArtifacts: ArtifactFile[] = [
const MOCK_ARTIFACTS: ArtifactFile[] = [
{
id: '1',
name: 'review-summary.md',
Expand All @@ -54,33 +55,33 @@ const mockArtifacts: ArtifactFile[] = [
},
];

const TABS = [
{
id: 'shortcuts' as const,
label: '快捷',
icon: <IconBolt className="size-4" />,
},
{
id: 'inbox' as const,
label: '收件箱',
icon: <IconInbox className="size-4" />,
},
{
id: 'artifacts' as const,
label: '工件',
icon: <IconFile className="size-4" />,
},
];

export function RightRail() {
const { activeRightTab, setActiveRightTab } = useLayoutStore(
(state) => state,
);

const tabs = [
{
id: 'shortcuts' as const,
label: '快捷',
icon: <IconBolt className="size-4" />,
},
{
id: 'inbox' as const,
label: '收件箱',
icon: <IconInbox className="size-4" />,
},
{
id: 'artifacts' as const,
label: '工件',
icon: <IconFile className="size-4" />,
},
];

return (
<div className="flex h-full w-[280px] flex-col border-l border-slate-200 bg-white">
<div className="flex border-b border-slate-200">
{tabs.map((tab) => (
{TABS.map((tab) => (
<button
key={tab.id}
type="button"
Expand All @@ -105,7 +106,7 @@ export function RightRail() {
<h3 className="text-xs font-medium text-slate-500 uppercase tracking-wide mb-3">
快捷操作
</h3>
{quickActions.map((action) => (
{QUICK_ACTIONS.map((action) => (
<Button
key={action.id}
variant="outline"
Expand Down Expand Up @@ -145,7 +146,7 @@ export function RightRail() {
<h3 className="text-xs font-medium text-slate-500 uppercase tracking-wide mb-3">
工件文件
</h3>
{mockArtifacts.map((artifact) => (
{MOCK_ARTIFACTS.map((artifact) => (
<div
key={artifact.id}
className="flex items-center gap-3 p-2 rounded-md hover:bg-slate-50 transition-colors cursor-pointer"
Expand All @@ -168,7 +169,7 @@ export function RightRail() {
</div>
</div>
))}
{mockArtifacts.length === 0 && (
{MOCK_ARTIFACTS.length === 0 && (
<p className="text-sm text-slate-400 text-center py-4">
暂无工件
</p>
Expand Down
Loading