feat(*): 创作配置 - 支持 Midjourney、多图保存与自定义公告
Co-authored-by: ddcat666 <26564566+ddcat666@users.noreply.github.com>
This commit is contained in:
@@ -344,192 +344,192 @@ export function AgentChatComposer({
|
||||
<div className="agent-composer-wrap min-w-0 shrink-0" onWheelCapture={(event) => event.stopPropagation()}>
|
||||
{/* 有底部附加内容时,外壳托住输入卡片与底部条,形成一张整卡。 */}
|
||||
<div className="agent-composer-shell relative" data-has-footer={footer ? "" : undefined}>
|
||||
{/* 整卡模式下发送光环包住整张卡,避免画在输入区与连接器之间形成一条线。 */}
|
||||
{footer && sending && !reducedMotion ? <WorkingGlow active color={theme.accent.primary} radius={22} /> : null}
|
||||
<div
|
||||
className="agent-composer-surface group/composer relative transition-[background-color,box-shadow] duration-200"
|
||||
style={{
|
||||
color: theme.accent.primary,
|
||||
}}
|
||||
>
|
||||
{!footer && sending && !reducedMotion ? <WorkingGlow active color={theme.accent.primary} radius={22} /> : null}
|
||||
{attachments.length ? (
|
||||
<div className="thin-scrollbar mb-2 flex gap-2 overflow-x-auto pb-1">
|
||||
{attachments.map((item, index) => (
|
||||
<div key={item.id} className="group relative w-20 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
className="relative block size-20 overflow-hidden rounded-lg"
|
||||
title="点击放大预览"
|
||||
aria-label={`预览 ${item.name || `图片${index + 1}`}`}
|
||||
onClick={() => setPreviewAttachment(item)}
|
||||
onDoubleClick={() => setPreviewAttachment(item)}
|
||||
>
|
||||
<img src={item.url} alt={item.name} className="size-full object-cover" />
|
||||
</button>
|
||||
<div className="mt-1 flex min-w-0 items-center justify-between gap-1">
|
||||
<button type="button" className="flex min-w-0 items-center gap-0.5 truncate text-[var(--fs-tiny)] opacity-80 hover:opacity-100" title={`插入 @图片${index + 1}`} onClick={() => insertAttachmentMention(item)}>
|
||||
<AtSign className="size-2.5 shrink-0" />
|
||||
<span className="truncate">图片{index + 1}</span>
|
||||
{/* 整卡模式下发送光环包住整张卡,避免画在输入区与连接器之间形成一条线。 */}
|
||||
{footer && sending && !reducedMotion ? <WorkingGlow active color={theme.accent.primary} radius={22} /> : null}
|
||||
<div
|
||||
className="agent-composer-surface group/composer relative transition-[background-color,box-shadow] duration-200"
|
||||
style={{
|
||||
color: theme.accent.primary,
|
||||
}}
|
||||
>
|
||||
{!footer && sending && !reducedMotion ? <WorkingGlow active color={theme.accent.primary} radius={22} /> : null}
|
||||
{attachments.length ? (
|
||||
<div className="thin-scrollbar mb-2 flex gap-2 overflow-x-auto pb-1">
|
||||
{attachments.map((item, index) => (
|
||||
<div key={item.id} className="group relative w-20 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
className="relative block size-20 overflow-hidden rounded-lg"
|
||||
title="点击放大预览"
|
||||
aria-label={`预览 ${item.name || `图片${index + 1}`}`}
|
||||
onClick={() => setPreviewAttachment(item)}
|
||||
onDoubleClick={() => setPreviewAttachment(item)}
|
||||
>
|
||||
<img src={item.url} alt={item.name} className="size-full object-cover" />
|
||||
</button>
|
||||
{onRemoveAttachment ? (
|
||||
<button
|
||||
type="button"
|
||||
className="grid size-4 shrink-0 place-items-center rounded-full opacity-70 hover:opacity-100"
|
||||
style={{ background: theme.toolbar.panel, color: theme.node.text }}
|
||||
onClick={() => onRemoveAttachment(item.id)}
|
||||
aria-label="移除图片"
|
||||
>
|
||||
<X className="size-3" />
|
||||
<div className="mt-1 flex min-w-0 items-center justify-between gap-1">
|
||||
<button type="button" className="flex min-w-0 items-center gap-0.5 truncate text-[var(--fs-tiny)] opacity-80 hover:opacity-100" title={`插入 @图片${index + 1}`} onClick={() => insertAttachmentMention(item)}>
|
||||
<AtSign className="size-2.5 shrink-0" />
|
||||
<span className="truncate">图片{index + 1}</span>
|
||||
</button>
|
||||
) : null}
|
||||
{onRemoveAttachment ? (
|
||||
<button
|
||||
type="button"
|
||||
className="grid size-4 shrink-0 place-items-center rounded-full opacity-70 hover:opacity-100"
|
||||
style={{ background: theme.toolbar.panel, color: theme.node.text }}
|
||||
onClick={() => onRemoveAttachment(item.id)}
|
||||
aria-label="移除图片"
|
||||
>
|
||||
<X className="size-3" />
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="relative" onKeyDownCapture={handleSlashKeyCapture} onPasteCapture={handlePasteCapture}>
|
||||
<button
|
||||
type="button"
|
||||
role="separator"
|
||||
aria-orientation="horizontal"
|
||||
aria-label="调整提示词面板高度"
|
||||
aria-valuemin={MIN_AGENT_PROMPT_HEIGHT}
|
||||
aria-valuemax={MAX_AGENT_PROMPT_HEIGHT}
|
||||
aria-valuenow={promptHeight}
|
||||
className="agent-composer-resize-handle"
|
||||
style={{ color: theme.node.muted }}
|
||||
onPointerDown={startPromptResize}
|
||||
onPointerMove={resizePrompt}
|
||||
onPointerUp={finishPromptResize}
|
||||
onPointerCancel={finishPromptResize}
|
||||
onKeyDown={resizePromptByKeyboard}
|
||||
>
|
||||
<span />
|
||||
</button>
|
||||
<div className="agent-composer-prompt-scroll" style={{ height: promptHeight }}>
|
||||
<CanvasResourceMentionTextarea
|
||||
value={prompt}
|
||||
references={composerReferences}
|
||||
includeAssetLibrary={includeAssetLibrary}
|
||||
sendOnEnter={canSubmit ? "both" : false}
|
||||
disabled={disabled}
|
||||
onChange={handlePromptChange}
|
||||
onSubmit={() => {
|
||||
if (canSubmit) onSubmit();
|
||||
}}
|
||||
onContentSizeChange={handlePromptContentSizeChange}
|
||||
className="w-full resize-none border-0 bg-transparent px-1 py-1 text-sm leading-5 outline-none placeholder:opacity-45"
|
||||
containerClassName="min-h-[60px] h-full"
|
||||
style={{ color: theme.node.text }}
|
||||
placeholder={placeholder}
|
||||
aria-label="Agent 输入"
|
||||
/>
|
||||
</div>
|
||||
{slash && slashCandidates.length ? (
|
||||
<div
|
||||
data-agent-slash-menu
|
||||
className="absolute bottom-full left-0 z-[var(--z-toolbar)] mb-2 w-full max-w-xs overflow-hidden rounded-2xl p-1.5 shadow-2xl"
|
||||
style={{ background: theme.toolbar.panel, boxShadow: `0 18px 44px ${theme.spatial.shadow}` }}
|
||||
onMouseDown={(event) => event.preventDefault()}
|
||||
>
|
||||
{slashCandidates.map((skill, index) => (
|
||||
<button
|
||||
key={skill.skillId}
|
||||
type="button"
|
||||
className="flex w-full min-w-0 items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs"
|
||||
style={{ background: index === activeSlashIndex ? theme.toolbar.itemHover : "transparent", color: theme.node.text }}
|
||||
onMouseEnter={() => setSlashIndex(index)}
|
||||
onClick={() => applySlashSkill(skill)}
|
||||
>
|
||||
<Sparkles className="size-3.5 shrink-0 opacity-70" />
|
||||
<span className="min-w-0 truncate font-medium">{skill.skillName}</span>
|
||||
{skill.description ? <span className="min-w-0 flex-1 truncate opacity-50">{skill.description}</span> : null}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="agent-composer-toolbar mt-2">
|
||||
<div className="agent-composer-controls flex min-w-0 items-center gap-1">
|
||||
{onAddFiles ? (
|
||||
<>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
hidden
|
||||
type="file"
|
||||
accept="image/*"
|
||||
multiple
|
||||
onChange={(event) => {
|
||||
void onAddFiles(event.target.files);
|
||||
event.target.value = "";
|
||||
}}
|
||||
/>
|
||||
<Tooltip title="上传图片">
|
||||
<Button
|
||||
type="text"
|
||||
shape="circle"
|
||||
className="!h-8 !w-8 !min-w-8 !transition-transform hover:!scale-105 active:!scale-95"
|
||||
disabled={sending}
|
||||
style={{ color: theme.node.muted }}
|
||||
icon={<ImagePlus className="size-4" />}
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
/>
|
||||
</Tooltip>
|
||||
</>
|
||||
<div className="relative" onKeyDownCapture={handleSlashKeyCapture} onPasteCapture={handlePasteCapture}>
|
||||
<button
|
||||
type="button"
|
||||
role="separator"
|
||||
aria-orientation="horizontal"
|
||||
aria-label="调整提示词面板高度"
|
||||
aria-valuemin={MIN_AGENT_PROMPT_HEIGHT}
|
||||
aria-valuemax={MAX_AGENT_PROMPT_HEIGHT}
|
||||
aria-valuenow={promptHeight}
|
||||
className="agent-composer-resize-handle"
|
||||
style={{ color: theme.node.muted }}
|
||||
onPointerDown={startPromptResize}
|
||||
onPointerMove={resizePrompt}
|
||||
onPointerUp={finishPromptResize}
|
||||
onPointerCancel={finishPromptResize}
|
||||
onKeyDown={resizePromptByKeyboard}
|
||||
>
|
||||
<span />
|
||||
</button>
|
||||
<div className="agent-composer-prompt-scroll" style={{ height: promptHeight }}>
|
||||
<CanvasResourceMentionTextarea
|
||||
value={prompt}
|
||||
references={composerReferences}
|
||||
includeAssetLibrary={includeAssetLibrary}
|
||||
sendOnEnter={canSubmit ? "both" : false}
|
||||
disabled={disabled}
|
||||
onChange={handlePromptChange}
|
||||
onSubmit={() => {
|
||||
if (canSubmit) onSubmit();
|
||||
}}
|
||||
onContentSizeChange={handlePromptContentSizeChange}
|
||||
className="w-full resize-none border-0 bg-transparent px-1 py-1 text-sm leading-5 outline-none placeholder:opacity-45"
|
||||
containerClassName="min-h-[60px] h-full"
|
||||
style={{ color: theme.node.text }}
|
||||
placeholder={placeholder}
|
||||
aria-label="Agent 输入"
|
||||
/>
|
||||
</div>
|
||||
{slash && slashCandidates.length ? (
|
||||
<div
|
||||
data-agent-slash-menu
|
||||
className="absolute bottom-full left-0 z-[var(--z-toolbar)] mb-2 w-full max-w-xs overflow-hidden rounded-2xl p-1.5 shadow-2xl"
|
||||
style={{ background: theme.toolbar.panel, boxShadow: `0 18px 44px ${theme.spatial.shadow}` }}
|
||||
onMouseDown={(event) => event.preventDefault()}
|
||||
>
|
||||
{slashCandidates.map((skill, index) => (
|
||||
<button
|
||||
key={skill.skillId}
|
||||
type="button"
|
||||
className="flex w-full min-w-0 items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs"
|
||||
style={{ background: index === activeSlashIndex ? theme.toolbar.itemHover : "transparent", color: theme.node.text }}
|
||||
onMouseEnter={() => setSlashIndex(index)}
|
||||
onClick={() => applySlashSkill(skill)}
|
||||
>
|
||||
<Sparkles className="size-3.5 shrink-0 opacity-70" />
|
||||
<span className="min-w-0 truncate font-medium">{skill.skillName}</span>
|
||||
{skill.description ? <span className="min-w-0 flex-1 truncate opacity-50">{skill.description}</span> : null}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
{left}
|
||||
</div>
|
||||
<div className="agent-composer-submit flex items-center gap-2">
|
||||
{submitAccessory}
|
||||
{canStop ? (
|
||||
<div className="agent-composer-toolbar mt-2">
|
||||
<div className="agent-composer-controls flex min-w-0 items-center gap-1">
|
||||
{onAddFiles ? (
|
||||
<>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
hidden
|
||||
type="file"
|
||||
accept="image/*"
|
||||
multiple
|
||||
onChange={(event) => {
|
||||
void onAddFiles(event.target.files);
|
||||
event.target.value = "";
|
||||
}}
|
||||
/>
|
||||
<Tooltip title="上传图片">
|
||||
<Button
|
||||
type="text"
|
||||
shape="circle"
|
||||
className="!h-8 !w-8 !min-w-8 !transition-transform hover:!scale-105 active:!scale-95"
|
||||
disabled={sending}
|
||||
style={{ color: theme.node.muted }}
|
||||
icon={<ImagePlus className="size-4" />}
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
/>
|
||||
</Tooltip>
|
||||
</>
|
||||
) : null}
|
||||
{left}
|
||||
</div>
|
||||
<div className="agent-composer-submit flex items-center gap-2">
|
||||
{submitAccessory}
|
||||
{canStop ? (
|
||||
<motion.button
|
||||
type="button"
|
||||
disabled={stopping}
|
||||
aria-label="停止本轮"
|
||||
title="停止当前 Agent 运行"
|
||||
onClick={() => void onStop?.()}
|
||||
whileHover={!reducedMotion && !stopping ? { scale: 1.06, y: -1 } : undefined}
|
||||
whileTap={!reducedMotion && !stopping ? { scale: 0.9, y: 1 } : undefined}
|
||||
animate={stopping && !reducedMotion ? { scale: [1, 0.94, 1] } : { scale: 1 }}
|
||||
transition={{ type: "spring", stiffness: 420, damping: 24 }}
|
||||
className="grid size-7 shrink-0 place-items-center rounded-full p-0 outline-none transition-[background-color,box-shadow,color,transform] duration-200 focus-visible:ring-2 focus-visible:ring-current/35 disabled:cursor-not-allowed"
|
||||
style={{ background: theme.accent.danger, color: theme.accent.onPrimary }}
|
||||
>
|
||||
{stopping ? <LoaderCircle className="size-4 animate-spin" /> : <Square className="size-3.5" fill="currentColor" />}
|
||||
</motion.button>
|
||||
) : null}
|
||||
<motion.button
|
||||
type="button"
|
||||
disabled={stopping}
|
||||
aria-label="停止本轮"
|
||||
title="停止当前 Agent 运行"
|
||||
onClick={() => void onStop?.()}
|
||||
whileHover={!reducedMotion && !stopping ? { scale: 1.06, y: -1 } : undefined}
|
||||
whileTap={!reducedMotion && !stopping ? { scale: 0.9, y: 1 } : undefined}
|
||||
animate={stopping && !reducedMotion ? { scale: [1, 0.94, 1] } : { scale: 1 }}
|
||||
transition={{ type: "spring", stiffness: 420, damping: 24 }}
|
||||
className="grid size-7 shrink-0 place-items-center rounded-full p-0 outline-none transition-[background-color,box-shadow,color,transform] duration-200 focus-visible:ring-2 focus-visible:ring-current/35 disabled:cursor-not-allowed"
|
||||
style={{ background: theme.accent.danger, color: theme.accent.onPrimary }}
|
||||
disabled={!canSubmit}
|
||||
aria-label={sending ? "发送中" : canStop ? "插话" : "发送"}
|
||||
title={canStop ? "插话:Agent 下一次开口时看到它" : "点击发送;Enter 或 ⌘/Ctrl+Enter 发送"}
|
||||
onClick={() => onSubmit()}
|
||||
whileHover={canSubmit && !reducedMotion ? { scale: 1.06, y: -1 } : undefined}
|
||||
whileTap={canSubmit && !reducedMotion ? { scale: 0.9, y: 1 } : undefined}
|
||||
animate={stopping && !reducedMotion ? { scale: [1, 0.94, 1] } : { scale: 1, rotate: 0 }}
|
||||
transition={sending && !reducedMotion ? { duration: 0.42, ease: "easeOut" } : { type: "spring", stiffness: 420, damping: 24 }}
|
||||
data-icon-only
|
||||
className="agent-composer-send grid size-7 shrink-0 place-items-center rounded-full p-0 outline-none transition-[background-color,box-shadow,color,transform] duration-200 focus-visible:ring-2 focus-visible:ring-current/35 disabled:cursor-not-allowed"
|
||||
style={{
|
||||
background: canSubmit || sending ? theme.accent.primary : theme.spatial.surface,
|
||||
color: canSubmit || sending ? theme.accent.onPrimary : theme.node.muted,
|
||||
}}
|
||||
>
|
||||
{stopping ? <LoaderCircle className="size-4 animate-spin" /> : <Square className="size-3.5" fill="currentColor" />}
|
||||
<motion.span
|
||||
key={stopping ? "stopping" : sending ? "sending" : "ready"}
|
||||
initial={reducedMotion ? false : { opacity: 0, scale: 0.65, rotate: sending ? -25 : 25 }}
|
||||
animate={{ opacity: 1, scale: 1, rotate: 0 }}
|
||||
transition={{ duration: reducedMotion ? 0 : 0.18, ease: "easeOut" }}
|
||||
className="grid place-items-center"
|
||||
>
|
||||
{sending ? <LoaderCircle className="size-3.5 animate-spin" /> : <ArrowUp className="size-3.5" />}
|
||||
</motion.span>
|
||||
</motion.button>
|
||||
) : null}
|
||||
<motion.button
|
||||
type="button"
|
||||
disabled={!canSubmit}
|
||||
aria-label={sending ? "发送中" : canStop ? "插话" : "发送"}
|
||||
title={canStop ? "插话:Agent 下一次开口时看到它" : "点击发送;Enter 或 ⌘/Ctrl+Enter 发送"}
|
||||
onClick={() => onSubmit()}
|
||||
whileHover={canSubmit && !reducedMotion ? { scale: 1.06, y: -1 } : undefined}
|
||||
whileTap={canSubmit && !reducedMotion ? { scale: 0.9, y: 1 } : undefined}
|
||||
animate={stopping && !reducedMotion ? { scale: [1, 0.94, 1] } : { scale: 1, rotate: 0 }}
|
||||
transition={sending && !reducedMotion ? { duration: 0.42, ease: "easeOut" } : { type: "spring", stiffness: 420, damping: 24 }}
|
||||
data-icon-only
|
||||
className="agent-composer-send grid size-7 shrink-0 place-items-center rounded-full p-0 outline-none transition-[background-color,box-shadow,color,transform] duration-200 focus-visible:ring-2 focus-visible:ring-current/35 disabled:cursor-not-allowed"
|
||||
style={{
|
||||
background: canSubmit || sending ? theme.accent.primary : theme.spatial.surface,
|
||||
color: canSubmit || sending ? theme.accent.onPrimary : theme.node.muted,
|
||||
}}
|
||||
>
|
||||
<motion.span
|
||||
key={stopping ? "stopping" : sending ? "sending" : "ready"}
|
||||
initial={reducedMotion ? false : { opacity: 0, scale: 0.65, rotate: sending ? -25 : 25 }}
|
||||
animate={{ opacity: 1, scale: 1, rotate: 0 }}
|
||||
transition={{ duration: reducedMotion ? 0 : 0.18, ease: "easeOut" }}
|
||||
className="grid place-items-center"
|
||||
>
|
||||
{sending ? <LoaderCircle className="size-3.5 animate-spin" /> : <ArrowUp className="size-3.5" />}
|
||||
</motion.span>
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{footer}
|
||||
{footer}
|
||||
</div>
|
||||
{previewAttachment ? <AgentImagePreview attachment={previewAttachment} onClose={() => setPreviewAttachment(null)} /> : null}
|
||||
</div>
|
||||
|
||||
@@ -18,8 +18,16 @@ type AgentConnector = {
|
||||
function NotionIcon() {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 100 100" fill="none">
|
||||
<path d="M6.017 4.313l55.333 -4.087c6.797 -0.583 8.543 -0.19 12.817 2.917l17.663 12.443c2.913 2.14 3.883 2.723 3.883 5.053v68.243c0 4.277 -1.553 6.807 -6.99 7.193L24.467 99.967c-4.08 0.193 -6.023 -0.39 -8.16 -3.113L3.3 79.94c-2.333 -3.113 -3.3 -5.443 -3.3 -8.167V11.113c0 -3.497 1.553 -6.413 6.017 -6.8z" fill="#fff"/>
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M61.35 0.227l-55.333 4.087C1.553 4.7 0 7.617 0 11.113v60.66c0 2.724 0.967 5.053 3.3 8.167l13.007 16.913c2.137 2.723 4.08 3.307 8.16 3.113l64.257 -3.89c5.433 -0.387 6.99 -2.917 6.99 -7.193V20.64c0 -2.21 -0.873 -2.847 -3.443 -4.733L74.167 3.143c-4.273 -3.107 -6.02 -3.5 -12.817 -2.917zM25.92 19.523c-5.247 0.353 -6.437 0.433 -9.417 -1.99L8.927 11.507c-0.77 -0.78 -0.383 -1.753 1.557 -1.947l53.193 -3.887c4.467 -0.39 6.793 1.167 8.54 2.527l9.123 6.61c0.39 0.197 1.36 1.36 0.193 1.36l-54.933 3.307 -0.68 0.047zM19.803 88.3V30.367c0 -2.53 0.777 -3.697 3.103 -3.893L86 22.78c2.14 -0.193 3.107 1.167 3.107 3.693v57.547c0 2.53 -0.39 4.67 -3.883 4.863l-60.377 3.5c-3.493 0.193 -5.043 -0.97 -5.043 -4.083zm59.6 -54.827c0.387 1.75 0 3.5 -1.75 3.7l-2.91 0.577v42.773c-2.527 1.36 -4.853 2.137 -6.797 2.137 -3.107 0 -3.883 -0.973 -6.21 -3.887l-19.03 -29.94v28.967l6.02 1.363s0 3.5 -4.857 3.5l-13.39 0.777c-0.39 -0.78 0 -2.723 1.357 -3.11l3.497 -0.97v-38.3L30.48 40.667c-0.39 -1.75 0.58 -4.277 3.3 -4.473l14.367 -0.967 19.8 30.327v-26.83l-5.047 -0.58c-0.39 -2.143 1.163 -3.7 3.103 -3.89l13.4 -0.78z" fill="#000"/>
|
||||
<path
|
||||
d="M6.017 4.313l55.333 -4.087c6.797 -0.583 8.543 -0.19 12.817 2.917l17.663 12.443c2.913 2.14 3.883 2.723 3.883 5.053v68.243c0 4.277 -1.553 6.807 -6.99 7.193L24.467 99.967c-4.08 0.193 -6.023 -0.39 -8.16 -3.113L3.3 79.94c-2.333 -3.113 -3.3 -5.443 -3.3 -8.167V11.113c0 -3.497 1.553 -6.413 6.017 -6.8z"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M61.35 0.227l-55.333 4.087C1.553 4.7 0 7.617 0 11.113v60.66c0 2.724 0.967 5.053 3.3 8.167l13.007 16.913c2.137 2.723 4.08 3.307 8.16 3.113l64.257 -3.89c5.433 -0.387 6.99 -2.917 6.99 -7.193V20.64c0 -2.21 -0.873 -2.847 -3.443 -4.733L74.167 3.143c-4.273 -3.107 -6.02 -3.5 -12.817 -2.917zM25.92 19.523c-5.247 0.353 -6.437 0.433 -9.417 -1.99L8.927 11.507c-0.77 -0.78 -0.383 -1.753 1.557 -1.947l53.193 -3.887c4.467 -0.39 6.793 1.167 8.54 2.527l9.123 6.61c0.39 0.197 1.36 1.36 0.193 1.36l-54.933 3.307 -0.68 0.047zM19.803 88.3V30.367c0 -2.53 0.777 -3.697 3.103 -3.893L86 22.78c2.14 -0.193 3.107 1.167 3.107 3.693v57.547c0 2.53 -0.39 4.67 -3.883 4.863l-60.377 3.5c-3.493 0.193 -5.043 -0.97 -5.043 -4.083zm59.6 -54.827c0.387 1.75 0 3.5 -1.75 3.7l-2.91 0.577v42.773c-2.527 1.36 -4.853 2.137 -6.797 2.137 -3.107 0 -3.883 -0.973 -6.21 -3.887l-19.03 -29.94v28.967l6.02 1.363s0 3.5 -4.857 3.5l-13.39 0.777c-0.39 -0.78 0 -2.723 1.357 -3.11l3.497 -0.97v-38.3L30.48 40.667c-0.39 -1.75 0.58 -4.277 3.3 -4.473l14.367 -0.967 19.8 30.327v-26.83l-5.047 -0.58c-0.39 -2.143 1.163 -3.7 3.103 -3.89l13.4 -0.78z"
|
||||
fill="#000"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -27,11 +35,11 @@ function NotionIcon() {
|
||||
function FeishuIcon() {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||||
<rect width="24" height="24" rx="6" fill="#3370FF"/>
|
||||
<path d="M7 7h10v3H7V7z" fill="#fff"/>
|
||||
<path d="M7 11h4v6H7v-6z" fill="#fff" opacity="0.9"/>
|
||||
<path d="M12 11h5v2.5h-5V11z" fill="#fff" opacity="0.75"/>
|
||||
<path d="M12 14.5h5V17h-5v-2.5z" fill="#fff" opacity="0.75"/>
|
||||
<rect width="24" height="24" rx="6" fill="#3370FF" />
|
||||
<path d="M7 7h10v3H7V7z" fill="#fff" />
|
||||
<path d="M7 11h4v6H7v-6z" fill="#fff" opacity="0.9" />
|
||||
<path d="M12 11h5v2.5h-5V11z" fill="#fff" opacity="0.75" />
|
||||
<path d="M12 14.5h5V17h-5v-2.5z" fill="#fff" opacity="0.75" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -39,9 +47,9 @@ function FeishuIcon() {
|
||||
function BasecampIcon() {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||||
<circle cx="12" cy="12" r="11" fill="#1DB954"/>
|
||||
<path d="M12 6c-3.5 0-6 2.5-6 6s2.5 6 6 6 6-2.5 6-6-2.5-6-6-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" fill="#fff"/>
|
||||
<circle cx="12" cy="12" r="2" fill="#fff"/>
|
||||
<circle cx="12" cy="12" r="11" fill="#1DB954" />
|
||||
<path d="M12 6c-3.5 0-6 2.5-6 6s2.5 6 6 6 6-2.5 6-6-2.5-6-6-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" fill="#fff" />
|
||||
<circle cx="12" cy="12" r="2" fill="#fff" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -49,9 +57,9 @@ function BasecampIcon() {
|
||||
function ObsidianIcon() {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||||
<rect width="24" height="24" rx="6" fill="#7C3AED"/>
|
||||
<path d="M12 4l7 4v8l-7 4-7-4V8l7-4z" stroke="#fff" strokeWidth="1.5" fill="none"/>
|
||||
<path d="M12 4v8m0 8V12m-7-4l7 4m7-4l-7 4" stroke="#fff" strokeWidth="1.2" opacity="0.6"/>
|
||||
<rect width="24" height="24" rx="6" fill="#7C3AED" />
|
||||
<path d="M12 4l7 4v8l-7 4-7-4V8l7-4z" stroke="#fff" strokeWidth="1.5" fill="none" />
|
||||
<path d="M12 4v8m0 8V12m-7-4l7 4m7-4l-7 4" stroke="#fff" strokeWidth="1.2" opacity="0.6" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -59,8 +67,13 @@ function ObsidianIcon() {
|
||||
function GitHubIcon() {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||||
<circle cx="12" cy="12" r="11" fill="#24292e"/>
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M12 3C7.03 3 3 7.03 3 12c0 3.98 2.58 7.35 6.15 8.54.45.08.62-.19.62-.43v-1.7c-2.52.55-3.05-1.08-3.05-1.08-.41-1.04-1-1.32-1-1.32-.82-.56.06-.55.06-.55.91.06 1.39.93 1.39.93.81 1.38 2.12.98 2.63.75.08-.58.31-.98.57-1.2-2.01-.23-4.13-1-4.13-4.47 0-.99.35-1.8.93-2.43-.09-.23-.4-1.14.09-2.38 0 0 .76-.24 2.48.92a8.6 8.6 0 012.26-.3c.77 0 1.54.1 2.26.3 1.72-1.16 2.48-.92 2.48-.92.49 1.24.18 2.15.09 2.38.58.63.93 1.44.93 2.43 0 3.48-2.13 4.24-4.15 4.46.33.28.62.83.62 1.67v2.47c0 .24.17.52.63.43A9.003 9.003 0 0021 12c0-4.97-4.03-9-9-9z" fill="#fff"/>
|
||||
<circle cx="12" cy="12" r="11" fill="#24292e" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12 3C7.03 3 3 7.03 3 12c0 3.98 2.58 7.35 6.15 8.54.45.08.62-.19.62-.43v-1.7c-2.52.55-3.05-1.08-3.05-1.08-.41-1.04-1-1.32-1-1.32-.82-.56.06-.55.06-.55.91.06 1.39.93 1.39.93.81 1.38 2.12.98 2.63.75.08-.58.31-.98.57-1.2-2.01-.23-4.13-1-4.13-4.47 0-.99.35-1.8.93-2.43-.09-.23-.4-1.14.09-2.38 0 0 .76-.24 2.48.92a8.6 8.6 0 012.26-.3c.77 0 1.54.1 2.26.3 1.72-1.16 2.48-.92 2.48-.92.49 1.24.18 2.15.09 2.38.58.63.93 1.44.93 2.43 0 3.48-2.13 4.24-4.15 4.46.33.28.62.83.62 1.67v2.47c0 .24.17.52.63.43A9.003 9.003 0 0021 12c0-4.97-4.03-9-9-9z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -68,12 +81,12 @@ function GitHubIcon() {
|
||||
function TencentDocsIcon() {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||||
<rect width="24" height="24" rx="6" fill="#1E6FFF"/>
|
||||
<path d="M8 6h5.5l3 3v8.5a1 1 0 01-1 1H8a1 1 0 01-1-1V7a1 1 0 011-1z" fill="#fff"/>
|
||||
<path d="M13.5 6v2.2c0 .4.3.8.8.8H17" fill="#BFD4FF"/>
|
||||
<rect x="9.5" y="12" width="5.5" height="1.2" rx=".6" fill="#1E6FFF"/>
|
||||
<rect x="9.5" y="14.5" width="5.5" height="1.2" rx=".6" fill="#1E6FFF" opacity=".7"/>
|
||||
<rect x="9.5" y="17" width="3.5" height="1.2" rx=".6" fill="#1E6FFF" opacity=".5"/>
|
||||
<rect width="24" height="24" rx="6" fill="#1E6FFF" />
|
||||
<path d="M8 6h5.5l3 3v8.5a1 1 0 01-1 1H8a1 1 0 01-1-1V7a1 1 0 011-1z" fill="#fff" />
|
||||
<path d="M13.5 6v2.2c0 .4.3.8.8.8H17" fill="#BFD4FF" />
|
||||
<rect x="9.5" y="12" width="5.5" height="1.2" rx=".6" fill="#1E6FFF" />
|
||||
<rect x="9.5" y="14.5" width="5.5" height="1.2" rx=".6" fill="#1E6FFF" opacity=".7" />
|
||||
<rect x="9.5" y="17" width="3.5" height="1.2" rx=".6" fill="#1E6FFF" opacity=".5" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -81,10 +94,10 @@ function TencentDocsIcon() {
|
||||
function SlackIcon() {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M8.5 3.5a2 2 0 11-4 0 2 2 0 014 0zm0 7a2 2 0 01-2 2h-2a2 2 0 010-4h2a2 2 0 012 2z" fill="#E01E5A"/>
|
||||
<path d="M15.5 10.5a2 2 0 100-4 2 2 0 000 4zm7 0a2 2 0 01-2 2h-2a2 2 0 110-4h2a2 2 0 012 2z" fill="#36C5F0"/>
|
||||
<path d="M15.5 20.5a2 2 0 100-4 2 2 0 000 4zm0-7a2 2 0 012-2v-2a2 2 0 10-4 0v2a2 2 0 012 2z" fill="#2EB67D"/>
|
||||
<path d="M8.5 13.5a2 2 0 10-4 0 2 2 0 004 0zm7 0a2 2 0 01-2 2v2a2 2 0 104 0v-2a2 2 0 01-2-2z" fill="#ECB22E"/>
|
||||
<path d="M8.5 3.5a2 2 0 11-4 0 2 2 0 014 0zm0 7a2 2 0 01-2 2h-2a2 2 0 010-4h2a2 2 0 012 2z" fill="#E01E5A" />
|
||||
<path d="M15.5 10.5a2 2 0 100-4 2 2 0 000 4zm7 0a2 2 0 01-2 2h-2a2 2 0 110-4h2a2 2 0 012 2z" fill="#36C5F0" />
|
||||
<path d="M15.5 20.5a2 2 0 100-4 2 2 0 000 4zm0-7a2 2 0 012-2v-2a2 2 0 10-4 0v2a2 2 0 012 2z" fill="#2EB67D" />
|
||||
<path d="M8.5 13.5a2 2 0 10-4 0 2 2 0 004 0zm7 0a2 2 0 01-2 2v2a2 2 0 104 0v-2a2 2 0 01-2-2z" fill="#ECB22E" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -111,12 +124,7 @@ export function AgentConnectorsBar({ onClose }: { onClose: () => void }) {
|
||||
<div className="agent-connectors-list">
|
||||
{AGENT_CONNECTORS.map((connector) => (
|
||||
<Tooltip key={connector.id} title={`${connector.name} · 研发中`} placement="top">
|
||||
<button
|
||||
type="button"
|
||||
className="agent-connector-item"
|
||||
aria-label={`${connector.name}(研发中)`}
|
||||
onClick={() => message.info({ content: `${connector.name}连接器研发中,敬请期待`, key: `agent-connector-${connector.id}` })}
|
||||
>
|
||||
<button type="button" className="agent-connector-item" aria-label={`${connector.name}(研发中)`} onClick={() => message.info({ content: `${connector.name}连接器研发中,敬请期待`, key: `agent-connector-${connector.id}` })}>
|
||||
{connector.icon}
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
@@ -239,7 +239,13 @@ export function AgentContextRing({ view }: { view: AgentContextUsageView }) {
|
||||
</span>
|
||||
{view.compactAtTokens ? <span>压缩线 {formatContextCount(view.compactAtTokens)}</span> : null}
|
||||
</div>
|
||||
{view.compactionError ? <p className="agent-context-note" role="status">{view.compactionError}</p> : view.lastCompaction ? <p className="agent-context-note">本轮已完成一次上下文压缩,下一次读数会刷新。</p> : null}
|
||||
{view.compactionError ? (
|
||||
<p className="agent-context-note" role="status">
|
||||
{view.compactionError}
|
||||
</p>
|
||||
) : view.lastCompaction ? (
|
||||
<p className="agent-context-note">本轮已完成一次上下文压缩,下一次读数会刷新。</p>
|
||||
) : null}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user