Skip to content

Commit 262e0b8

Browse files
committed
refactor(web): redesign draft pane with agent and file editor split layout
- Replace single-column agent card grid with left-right two-panel layout - Agent panel: compact button list with icon + name + arrow - File Editor panel: dashed drop zone for drag-to-open files - Center the component within the draft pane - Add footer description line - Collapse to stacked layout in narrow containers - Remove unused kicker, description, and meta styles
1 parent 9a0e559 commit 262e0b8

2 files changed

Lines changed: 247 additions & 166 deletions

File tree

packages/web/src/features/agent-panes/views/shared/draft-launcher.tsx

Lines changed: 134 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -253,87 +253,141 @@ export const DraftLauncher: FC<DraftLauncherProps> = ({
253253

254254
<div className="agent-draft-launcher">
255255
<div className="agent-draft-content">
256-
<span className="agent-draft-kicker">SESSION LAUNCHER</span>
257-
<p className="agent-draft-description">
258-
选择一个 AI 会话,在当前 workspace 里继续查看文件、运行命令和推进代码修改。
259-
</p>
260-
<div className="agent-draft-providers">
261-
{(
262-
[
263-
{
264-
id: "claude",
265-
title: "Claude",
266-
meta: "analysis",
267-
icon: <ThemedIcon semantic="agent.provider.claude" size={18} />,
268-
description: "更适合长上下文梳理、方案分析和代码审查。",
269-
className: "agent-provider-card-claude",
270-
},
271-
{
272-
id: "codex",
273-
title: "Codex",
274-
meta: "workspace",
275-
icon: <ThemedIcon semantic="agent.provider.codex" size={18} />,
276-
description: "更适合终端操作、直接改文件和逐步修复问题。",
277-
className: "agent-provider-card-codex",
278-
},
279-
] as const
280-
).map((provider) => {
281-
const state = states[provider.id];
282-
const guide = getProviderGuide(provider.id);
283-
const isBusy =
284-
state.loading ||
285-
state.installJob?.status === "queued" ||
286-
state.installJob?.status === "running";
287-
288-
return (
289-
<Button
290-
key={provider.id}
291-
className={`agent-provider-card ${provider.className}`}
292-
disabled={isAnyProviderBusy}
293-
leadingIcon={<span className="agent-provider-card-icon">{provider.icon}</span>}
294-
onClick={() => {
295-
void launch(provider.id);
296-
}}
297-
trailingIcon={<ArrowRight size={16} className="agent-provider-card-arrow" />}
298-
variant="secondary"
299-
>
300-
<span className="agent-provider-card-body">
301-
<span className="agent-provider-card-title-row">
302-
<span className="agent-provider-card-title">{provider.title}</span>
303-
<span className="agent-provider-card-meta">{provider.meta}</span>
304-
</span>
305-
<span className="agent-provider-card-desc">{provider.description}</span>
306-
<span className="agent-provider-card-cta">{getProviderCta(provider.id)}</span>
307-
{isBusy ? (
308-
<span className="agent-provider-card-status">
309-
{t("provider.install.status.installing")}
310-
</span>
311-
) : null}
312-
{guide.message ? (
313-
<span className="agent-provider-card-guide">
314-
<span>{guide.message}</span>
315-
{guide.docUrl ? (
316-
<a
317-
href={guide.docUrl}
318-
onClick={(event) => event.stopPropagation()}
319-
rel="noreferrer"
320-
target="_blank"
321-
>
322-
{t("provider.install.open_docs")}
323-
</a>
324-
) : null}
325-
<a
326-
href={buildProviderDiagnosticsPath(provider.id)}
327-
onClick={(event) => event.stopPropagation()}
328-
>
329-
{t("diagnostics.actions.open_diagnostics")}
330-
</a>
331-
</span>
332-
) : null}
256+
<div className="agent-draft-component">
257+
<div className="agent-draft-component-row">
258+
{/* Agent panel */}
259+
<div className="agent-draft-panel">
260+
<div className="agent-draft-panel-header">
261+
<span className="agent-draft-panel-icon">
262+
<ThemedIcon semantic="agent.provider.claude" size={13} />
333263
</span>
334-
</Button>
335-
);
336-
})}
264+
<span className="agent-draft-panel-label">Agent</span>
265+
</div>
266+
267+
<div className="agent-draft-panel-list">
268+
{(
269+
[
270+
{
271+
id: "claude",
272+
title: "Claude",
273+
icon: <ThemedIcon semantic="agent.provider.claude" size={18} />,
274+
className: "agent-provider-card-claude",
275+
},
276+
{
277+
id: "codex",
278+
title: "Codex",
279+
icon: <ThemedIcon semantic="agent.provider.codex" size={18} />,
280+
className: "agent-provider-card-codex",
281+
},
282+
] as const
283+
).map((provider) => {
284+
const state = states[provider.id];
285+
const guide = getProviderGuide(provider.id);
286+
const isBusy =
287+
state.loading ||
288+
state.installJob?.status === "queued" ||
289+
state.installJob?.status === "running";
290+
291+
return (
292+
<Button
293+
key={provider.id}
294+
className={`agent-provider-card ${provider.className}`}
295+
disabled={isAnyProviderBusy}
296+
leadingIcon={
297+
<span className="agent-provider-card-icon">{provider.icon}</span>
298+
}
299+
onClick={() => {
300+
void launch(provider.id);
301+
}}
302+
trailingIcon={
303+
<ArrowRight size={16} className="agent-provider-card-arrow" />
304+
}
305+
variant="secondary"
306+
>
307+
<span className="agent-provider-card-body">
308+
<span className="agent-provider-card-title-row">
309+
<span className="agent-provider-card-title">{provider.title}</span>
310+
</span>
311+
<span className="agent-provider-card-cta">
312+
{getProviderCta(provider.id)}
313+
</span>
314+
{isBusy ? (
315+
<span className="agent-provider-card-status">
316+
{t("provider.install.status.installing")}
317+
</span>
318+
) : null}
319+
{guide.message ? (
320+
<span className="agent-provider-card-guide">
321+
<span>{guide.message}</span>
322+
{guide.docUrl ? (
323+
<a
324+
href={guide.docUrl}
325+
onClick={(event) => event.stopPropagation()}
326+
rel="noreferrer"
327+
target="_blank"
328+
>
329+
{t("provider.install.open_docs")}
330+
</a>
331+
) : null}
332+
<a
333+
href={buildProviderDiagnosticsPath(provider.id)}
334+
onClick={(event) => event.stopPropagation()}
335+
>
336+
{t("diagnostics.actions.open_diagnostics")}
337+
</a>
338+
</span>
339+
) : null}
340+
</span>
341+
</Button>
342+
);
343+
})}
344+
</div>
345+
</div>
346+
347+
{/* File Editor panel */}
348+
<div className="agent-draft-panel">
349+
<div className="agent-draft-panel-header">
350+
<span className="agent-draft-panel-icon">
351+
<svg
352+
width="13"
353+
height="13"
354+
viewBox="0 0 24 24"
355+
fill="none"
356+
stroke="currentColor"
357+
strokeWidth="2"
358+
strokeLinecap="round"
359+
strokeLinejoin="round"
360+
>
361+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" />
362+
<polyline points="14 2 14 8 20 8" />
363+
</svg>
364+
</span>
365+
<span className="agent-draft-panel-label">File Editor</span>
366+
</div>
367+
368+
<div className="agent-draft-drop-zone">
369+
<div className="agent-draft-drop-zone-icon">
370+
<svg
371+
width="16"
372+
height="16"
373+
viewBox="0 0 24 24"
374+
fill="none"
375+
stroke="currentColor"
376+
strokeWidth="1.5"
377+
strokeLinecap="round"
378+
strokeLinejoin="round"
379+
>
380+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
381+
<polyline points="7 10 12 15 17 10" />
382+
<line x1="12" y1="15" x2="12" y2="3" />
383+
</svg>
384+
</div>
385+
<span className="agent-draft-drop-zone-title">拖入文件打开</span>
386+
</div>
387+
</div>
388+
</div>
389+
390+
<div className="agent-draft-footer">点击启动 Agent 或直接拖拽文件到右侧区域打开</div>
337391
</div>
338392
</div>
339393
</div>

0 commit comments

Comments
 (0)