+
{content ?? ""}
+
);
diff --git a/frontend/src/components/workspace/input-box.tsx b/frontend/src/components/workspace/input-box.tsx
index dd22041c..67a6d167 100644
--- a/frontend/src/components/workspace/input-box.tsx
+++ b/frontend/src/components/workspace/input-box.tsx
@@ -42,6 +42,7 @@ import {
} from "@/components/ai-elements/prompt-input";
import { Button } from "@/components/ui/button";
import { ConfettiButton } from "@/components/ui/confetti-button";
+import { Badge } from "@/components/ui/badge";
import {
Dialog,
DialogContent,
@@ -82,6 +83,7 @@ import {
import { useThread } from "./messages/context";
import { ModeHoverGuide } from "./mode-hover-guide";
import { Tooltip } from "./tooltip";
+import { useIframeSkill } from "@/hooks/use-iframe-skill";
type InputMode = "flash" | "thinking" | "pro" | "ultra";
@@ -453,10 +455,13 @@ export function InputBox({
// height和padding都为0来隐藏
!effectiveIsFocused && "invisible h-[0px] p-[0px] opacity-0 translate-y-2 pointer-events-none"
)}>
+ {/* ========== 左侧工具栏 ========== */}
-
-
- {/*
+ {/* [已禁用] 模式选择器触发器 (flash/thinking/pro/ultra) */}
+ {/*
+
*/}
-
-
+ {/* Skill 选择按钮 (iframe 与宿主页通信) */}
+
+ {/* [已禁用] 模式选择下拉菜单内容 */}
+ {/*
{t.inputBox.mode}
@@ -626,6 +633,7 @@ export function InputBox({
+ {/* [已禁用] 推理强度选择器 (minimal/low/medium/high) */}
{supportReasoningEffort && context.mode !== "flash" && (
@@ -737,8 +745,10 @@ export function InputBox({
)}
+ {/* ========== 右侧工具栏 ========== */}
-
@@ -768,13 +778,14 @@ export function InputBox({
))}
-
+ */}
+ {/* 占位符 */}
{/* 移动出来 */}
);
}
-
+// 快速选择skillbutton
function SuggestionList() {
const { t } = useI18n();
const { textInput } = usePromptInputController();
+ const { sendSelectSkill } = useIframeSkill();
+
const handleSuggestionClick = useCallback(
- (prompt: string | undefined) => {
- if (!prompt) return;
- textInput.setInput(prompt);
+ (suggestion: { prompt: string; skill_id?: string }) => {
+ // 如果有 skill_id,发送给宿主页
+ if (suggestion.skill_id) {
+ sendSelectSkill(suggestion.skill_id);
+ return;
+ }
+ // 原有逻辑
+ if (!suggestion.prompt) return;
+ textInput.setInput(suggestion.prompt);
setTimeout(() => {
const textarea = document.querySelector(
"textarea[name='message']",
);
if (textarea) {
- const selStart = prompt.indexOf("[");
- const selEnd = prompt.indexOf("]");
+ const selStart = suggestion.prompt.indexOf("[");
+ const selEnd = suggestion.prompt.indexOf("]");
if (selStart !== -1 && selEnd !== -1) {
textarea.setSelectionRange(selStart, selEnd + 1);
textarea.focus();
@@ -872,7 +891,7 @@ function SuggestionList() {
}
}, 500);
},
- [textInput],
+ [textInput, sendSelectSkill],
);
return (
@@ -889,7 +908,7 @@ function SuggestionList() {
key={suggestion.suggestion}
icon={suggestion.icon}
suggestion={suggestion.suggestion}
- onClick={() => handleSuggestionClick(suggestion.prompt)}
+ onClick={() => handleSuggestionClick(suggestion)}
/>
))}
@@ -905,7 +924,7 @@ function SuggestionList() {
!("type" in suggestion) && (
handleSuggestionClick(suggestion.prompt)}
+ onClick={() => handleSuggestionClick(suggestion)}
>
{suggestion.icon && }
{suggestion.suggestion}
@@ -919,14 +938,14 @@ function SuggestionList() {
);
}
-
+// 上传附件
function AddAttachmentsButton({ className }: { className?: string }) {
const { t } = useI18n();
const attachments = usePromptInputAttachments();
return (
attachments.openFileDialog()}
>
);
}
-
+// 启动iframeSkillDialog
function IframeSkillDialogButton({ className }: { className?: string }) {
const { t } = useI18n();
- const attachments = usePromptInputAttachments();
- return (
-
- attachments.openFileDialog()}
- >
+ const { selectedSkill, openSkillDialog, clearSkill } = useIframeSkill();
-
-
-
+ return (
+
+
+
+
+
+
+ {selectedSkill && (
+
+ {selectedSkill.title}
+
+
+ )}
+
);
}
diff --git a/frontend/src/core/i18n/locales/en-US.ts b/frontend/src/core/i18n/locales/en-US.ts
index f1d879ad..5ef4e4e9 100644
--- a/frontend/src/core/i18n/locales/en-US.ts
+++ b/frontend/src/core/i18n/locales/en-US.ts
@@ -107,26 +107,31 @@ export const enUS: Translations = {
suggestion: "Paper Writing",
prompt: "Write an academic paper about [topic], including abstract, introduction, body and references.",
icon: PenLineIcon,
+ skill_id: "paper-writing",
},
{
suggestion: "Report Generation",
prompt: "Analyze [topic] in depth and generate a well-structured research report.",
icon: MicroscopeIcon,
+ skill_id: "report-generation",
},
{
suggestion: "Copywriting",
prompt: "Create a complete planning proposal and promotional copy for [project/event].",
icon: ShapesIcon,
+ skill_id: "planning-copywriting",
},
{
suggestion: "PPT Generation",
prompt: "Generate a PPT presentation outline and content about [topic].",
icon: GraduationCapIcon,
+ skill_id: "ppt-generation",
},
{
suggestion: "Document Processing",
prompt: "Process [document] with reading, summarizing, translating or format conversion.",
icon: CompassIcon,
+ skill_id: "document-processing",
},
],
suggestionsCreate: [
diff --git a/frontend/src/core/i18n/locales/types.ts b/frontend/src/core/i18n/locales/types.ts
index 5e28dd59..2d55b061 100644
--- a/frontend/src/core/i18n/locales/types.ts
+++ b/frontend/src/core/i18n/locales/types.ts
@@ -86,6 +86,7 @@ export interface Translations {
suggestion: string;
prompt: string;
icon: LucideIcon;
+ skill_id?: string;
}[];
suggestionsCreate: (
| {
diff --git a/frontend/src/core/i18n/locales/zh-CN.ts b/frontend/src/core/i18n/locales/zh-CN.ts
index bcef133b..6fee3e05 100644
--- a/frontend/src/core/i18n/locales/zh-CN.ts
+++ b/frontend/src/core/i18n/locales/zh-CN.ts
@@ -103,26 +103,31 @@ export const zhCN: Translations = {
suggestion: "论文写作",
prompt: "撰写一篇关于[主题]的学术论文,包含摘要、引言、正文和参考文献。",
icon: PenLineIcon,
+ skill_id: "1",
},
{
suggestion: "报告生成",
prompt: "深入分析[主题],生成一份结构清晰的调研报告。",
icon: MicroscopeIcon,
+ skill_id: "2",
},
{
suggestion: "策划文案",
prompt: "为[项目/活动]撰写一份完整的策划方案和宣传文案。",
icon: ShapesIcon,
+ skill_id: "3",
},
{
suggestion: "PPT生成",
prompt: "生成一个关于[主题]的PPT演示文稿大纲和内容。",
icon: GraduationCapIcon,
+ skill_id: "4",
},
{
suggestion: "文档处理",
prompt: "对[文档]进行阅读、总结、翻译或格式转换等处理。",
icon: CompassIcon,
+ skill_id: "5",
},
],
suggestionsCreate: [
diff --git a/frontend/src/hooks/use-iframe-skill.ts b/frontend/src/hooks/use-iframe-skill.ts
new file mode 100644
index 00000000..c6bd1938
--- /dev/null
+++ b/frontend/src/hooks/use-iframe-skill.ts
@@ -0,0 +1,61 @@
+import { useState, useEffect, useCallback } from 'react';
+import { useSearchParams } from 'next/navigation';
+
+// 消息类型常量
+const MESSAGE_TYPES = {
+ SELECT_SKILL: 'selectSkill',
+ OPEN_SKILL_DIALOG: 'openSkillDialog',
+} as const;
+
+// Skill 数据类型
+interface SkillData {
+ skill_id: string;
+ title: string;
+}
+
+// Hook 返回类型
+interface UseIframeSkillReturn {
+ selectedSkill: SkillData | null;
+ sendSelectSkill: (skill_id: string) => void;
+ openSkillDialog: () => void;
+ clearSkill: () => void;
+}
+
+export function useIframeSkill(): UseIframeSkillReturn {
+ const searchParams = useSearchParams();
+ const skillIdFromQuery = searchParams.get('skill_id');
+ const titleFromQuery = searchParams.get('title');
+
+ const [selectedSkill, setSelectedSkill] = useState(null);
+
+ // 监听 query 参数变化
+ useEffect(() => {
+ console.log('[useIframeSkill] Query params changed - skill_id:', skillIdFromQuery, 'title:', titleFromQuery);
+ if (skillIdFromQuery && titleFromQuery) {
+ const skill = { skill_id: skillIdFromQuery, title: titleFromQuery };
+ console.log('[useIframeSkill] Setting skill from URL:', skill);
+ setSelectedSkill(skill);
+ }
+ }, [skillIdFromQuery, titleFromQuery]);
+
+ // 发送选择预定义 skill
+ const sendSelectSkill = useCallback((skill_id: string) => {
+ const message = { type: MESSAGE_TYPES.SELECT_SKILL, skill_id };
+ console.log('[useIframeSkill] sendSelectSkill:', message);
+ window.parent.postMessage(message, '*');
+ }, []);
+
+ // 打开 skill 选择对话框
+ const openSkillDialog = useCallback(() => {
+ const message = { type: MESSAGE_TYPES.OPEN_SKILL_DIALOG, openSkillDialog: true };
+ console.log('[useIframeSkill] openSkillDialog:', message);
+ window.parent.postMessage(message, '*');
+ }, []);
+
+ // 清除选中
+ const clearSkill = useCallback(() => {
+ setSelectedSkill(null);
+ }, []);
+
+ return { selectedSkill, sendSelectSkill, openSkillDialog, clearSkill };
+}
\ No newline at end of file