diff --git a/packages/drawnix/src/components/ai-input-bar/AIInputBar.tsx b/packages/drawnix/src/components/ai-input-bar/AIInputBar.tsx index 4aaa2f2d..3b28e664 100644 --- a/packages/drawnix/src/components/ai-input-bar/AIInputBar.tsx +++ b/packages/drawnix/src/components/ai-input-bar/AIInputBar.tsx @@ -19,7 +19,7 @@ import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react' import { Send, Check, ImagePlus } from 'lucide-react'; import { useBoard } from '@plait-board/react-board'; import { SelectedContentPreview } from '../shared/SelectedContentPreview'; -import { getSelectedElements, ATTACHED_ELEMENT_CLASS_NAME, getRectangleByElements } from '@plait/core'; +import { getSelectedElements, ATTACHED_ELEMENT_CLASS_NAME, getRectangleByElements, PlaitBoard, getViewportOrigination } from '@plait/core'; import { useI18n } from '../../i18n'; import { TaskStatus } from '../../types/task.types'; import { taskQueueService } from '../../services/task-queue-service'; @@ -31,6 +31,7 @@ import { SizeDropdown } from './SizeDropdown'; import { PromptHistoryPopover } from './PromptHistoryPopover'; import { usePromptHistory } from '../../hooks/usePromptHistory'; import { getDefaultImageModel, IMAGE_MODELS, getModelConfig, getDefaultSizeForModel } from '../../constants/model-config'; +import { BUILT_IN_TOOLS, DEFAULT_TOOL_CONFIG } from '../../constants/built-in-tools'; import { initializeMCP, setCanvasBoard, setBoard, mcpRegistry } from '../../mcp'; import { initializeLongVideoChainService } from '../../services/long-video-chain-service'; import { gridImageService } from '../../services/photo-wall'; @@ -49,6 +50,7 @@ import type { WorkflowRetryContext, PostProcessingStatus } from '../../types/cha import { workflowCompletionService } from '../../services/workflow-completion-service'; import { BoardTransforms } from '@plait/core'; import { WorkZoneTransforms } from '../../plugins/with-workzone'; +import { ToolTransforms } from '../../plugins/with-tool'; import type { PlaitWorkZone } from '../../types/workzone.types'; /** @@ -533,6 +535,53 @@ export const AIInputBar: React.FC = React.memo(({ className }) inputRef.current?.focus(); }, []); + // 处理打开提示词工具(香蕉提示词)- 复用工具箱的逻辑 + const handleOpenPromptTool = useCallback(() => { + const board = SelectionWatcherBoardRef.current; + if (!board) { + console.warn('[AIInputBar] Board not ready for prompt tool'); + return; + } + + // 从内置工具列表中获取香蕉提示词工具配置 + const tool = BUILT_IN_TOOLS.find(t => t.id === 'banana-prompt'); + if (!tool) { + console.warn('[AIInputBar] Banana prompt tool not found'); + return; + } + + // 计算画布中心位置(与 ToolboxDrawer 相同的逻辑) + const boardContainerRect = PlaitBoard.getBoardContainer(board).getBoundingClientRect(); + const focusPoint = [ + boardContainerRect.width / 2, + boardContainerRect.height / 2, + ]; + const zoom = board.viewport.zoom; + const origination = getViewportOrigination(board); + const centerX = origination![0] + focusPoint[0] / zoom; + const centerY = origination![1] + focusPoint[1] / zoom; + + // 工具尺寸 + const width = tool.defaultWidth || DEFAULT_TOOL_CONFIG.defaultWidth; + const height = tool.defaultHeight || DEFAULT_TOOL_CONFIG.defaultHeight; + + // 插入到画布(中心对齐) + ToolTransforms.insertTool( + board, + tool.id, + tool.url, + [centerX - width / 2, centerY - height / 2], + { width, height }, + { + name: tool.name, + category: tool.category, + permissions: tool.permissions, + } + ); + + console.log('[AIInputBar] Prompt tool inserted to canvas'); + }, []); + // 处理上传按钮点击 const handleUploadClick = useCallback(() => { fileInputRef.current?.click(); @@ -1386,6 +1435,7 @@ export const AIInputBar: React.FC = React.memo(({ className }) {/* Main input container - flex-column-reverse to expand upward */} diff --git a/packages/drawnix/src/components/inspiration-board/InspirationBoard.tsx b/packages/drawnix/src/components/inspiration-board/InspirationBoard.tsx index 561544a8..eb324bcd 100644 --- a/packages/drawnix/src/components/inspiration-board/InspirationBoard.tsx +++ b/packages/drawnix/src/components/inspiration-board/InspirationBoard.tsx @@ -6,6 +6,7 @@ import React, { useState, useCallback } from 'react'; import { ChevronLeftIcon, ChevronRightIcon } from 'tdesign-icons-react'; +import { Lightbulb } from 'lucide-react'; import { InspirationCard } from './InspirationCard'; import { INSPIRATION_TEMPLATES, ITEMS_PER_PAGE } from './constants'; import type { InspirationBoardProps } from './types'; @@ -14,6 +15,7 @@ import './inspiration-board.scss'; export const InspirationBoard: React.FC = ({ isCanvasEmpty, onSelectPrompt, + onOpenPromptTool, visible = true, className = '', }) => { @@ -57,10 +59,24 @@ export const InspirationBoard: React.FC = ({
- {/* 头部:标题 + 切换按钮 */} + {/* 头部:标题 + 提示词按钮 + 切换按钮 */}

灵感创意

+ {/* 提示词工具按钮 */} + {onOpenPromptTool && ( + + )} + {hasMultiplePages && (
diff --git a/packages/drawnix/src/components/inspiration-board/inspiration-board.scss b/packages/drawnix/src/components/inspiration-board/inspiration-board.scss index a7e402b6..354bac13 100644 --- a/packages/drawnix/src/components/inspiration-board/inspiration-board.scss +++ b/packages/drawnix/src/components/inspiration-board/inspiration-board.scss @@ -41,6 +41,34 @@ $animation-duration: 0.3s; font-size: 14px; font-weight: 600; color: var(--td-text-color-primary); + flex: 1; // 占据剩余空间,把右侧按钮推到最右边 + } + + // 提示词工具按钮 + &__prompt-btn { + display: flex; + align-items: center; + gap: 4px; + padding: 4px 10px; + + border: none; + border-radius: 6px; + cursor: pointer; + + font-size: 12px; + font-weight: 500; + transition: all 0.2s ease; + margin-right: 8px; + + + + &:active { + transform: scale(0.97); + } + + svg { + flex-shrink: 0; + } } &__pagination { diff --git a/packages/drawnix/src/components/inspiration-board/types.ts b/packages/drawnix/src/components/inspiration-board/types.ts index 946e1383..e0500273 100644 --- a/packages/drawnix/src/components/inspiration-board/types.ts +++ b/packages/drawnix/src/components/inspiration-board/types.ts @@ -44,6 +44,8 @@ export interface InspirationBoardProps { isCanvasEmpty: boolean; /** 选择提示词回调 */ onSelectPrompt: (prompt: string) => void; + /** 打开提示词工具回调 */ + onOpenPromptTool?: () => void; /** 外部控制显示(可选) */ visible?: boolean; /** 自定义类名 */