mirror of
https://github.com/basketikun/infinite-canvas.git
synced 2026-08-05 17:04:27 +08:00
feat: add canvas resource mention references
This commit is contained in:
@@ -7,7 +7,9 @@ import { ChevronRight, Image as ImageIcon, Music2, RefreshCw, Star, Video } from
|
||||
import { canvasThemes } from "@/lib/canvas-theme";
|
||||
import { formatBytes } from "@/lib/image-utils";
|
||||
import { useThemeStore } from "@/stores/use-theme-store";
|
||||
import { CanvasResourceMentionTextarea } from "./canvas-resource-mention-textarea";
|
||||
import { CanvasNodeType, type CanvasNodeData, type Position } from "../types";
|
||||
import type { CanvasResourceReference } from "../utils/canvas-resource-references";
|
||||
|
||||
type ResizeCorner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
||||
const selectionBlue = "#2f80ff";
|
||||
@@ -23,6 +25,8 @@ type CanvasNodeProps = {
|
||||
editRequestNonce?: number;
|
||||
showPanel: boolean;
|
||||
showImageInfo: boolean;
|
||||
resourceLabel?: CanvasResourceReference;
|
||||
mentionReferences?: CanvasResourceReference[];
|
||||
renderPanel?: (node: CanvasNodeData) => ReactNode;
|
||||
renderNodeContent?: (node: CanvasNodeData) => ReactNode;
|
||||
batchCount?: number;
|
||||
@@ -57,6 +61,7 @@ type NodeContentRendererProps = {
|
||||
renderNodeContent?: (node: CanvasNodeData) => ReactNode;
|
||||
onContentChange: (nodeId: string, content: string) => void;
|
||||
onStopEditing: () => void;
|
||||
mentionReferences: CanvasResourceReference[];
|
||||
onRetry?: (node: CanvasNodeData) => void;
|
||||
onGenerateImage?: (node: CanvasNodeData) => void;
|
||||
onToggleBatch?: () => void;
|
||||
@@ -74,6 +79,8 @@ export const CanvasNode = React.memo(function CanvasNode({
|
||||
editRequestNonce = 0,
|
||||
showPanel,
|
||||
showImageInfo,
|
||||
resourceLabel,
|
||||
mentionReferences = [],
|
||||
renderPanel,
|
||||
renderNodeContent,
|
||||
batchCount = 0,
|
||||
@@ -291,6 +298,7 @@ export const CanvasNode = React.memo(function CanvasNode({
|
||||
batchOpening={batchOpening}
|
||||
batchRecovering={batchRecovering}
|
||||
renderNodeContent={renderNodeContent}
|
||||
mentionReferences={mentionReferences}
|
||||
onContentChange={onContentChange}
|
||||
onStopEditing={() => setIsEditingContent(false)}
|
||||
onRetry={onRetry}
|
||||
@@ -301,6 +309,7 @@ export const CanvasNode = React.memo(function CanvasNode({
|
||||
</div>
|
||||
|
||||
{showImageInfo && hasImageContent ? <ImageInfoBar node={data} /> : null}
|
||||
{resourceLabel ? <ResourceLabelBadge reference={resourceLabel} /> : null}
|
||||
|
||||
{!hasImageContent && !hasVideoContent && !hasAudioContent ? <div className="pointer-events-none absolute inset-x-0 bottom-0 h-12" style={{ background: `linear-gradient(to top, ${theme.canvas.background}66, transparent)` }} /> : null}
|
||||
|
||||
@@ -366,7 +375,7 @@ function ErrorContent({ node, theme, onRetry }: Pick<NodeContentRendererProps, "
|
||||
);
|
||||
}
|
||||
|
||||
function TextContent({ node, theme, isEditingContent, textareaRef, onContentChange, onStopEditing, onGenerateImage }: NodeContentRendererProps) {
|
||||
function TextContent({ node, theme, isEditingContent, textareaRef, mentionReferences, onContentChange, onStopEditing, onGenerateImage }: NodeContentRendererProps) {
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col overflow-hidden pt-8">
|
||||
<button
|
||||
@@ -386,12 +395,13 @@ function TextContent({ node, theme, isEditingContent, textareaRef, onContentChan
|
||||
生图
|
||||
</button>
|
||||
{isEditingContent ? (
|
||||
<textarea
|
||||
<CanvasResourceMentionTextarea
|
||||
ref={textareaRef}
|
||||
className="thin-scrollbar block h-full w-full resize-none overflow-y-auto whitespace-pre-wrap break-words border-none bg-transparent pl-4 pr-14 pt-0 pb-4 m-0 font-mono leading-relaxed outline-none select-text appearance-none"
|
||||
style={{ fontSize: `${node.metadata?.fontSize || 14}px`, color: theme.node.text }}
|
||||
value={node.metadata?.content || ""}
|
||||
onChange={(event) => onContentChange(node.id, event.target.value)}
|
||||
references={mentionReferences}
|
||||
onChange={(value) => onContentChange(node.id, value)}
|
||||
onBlur={onStopEditing}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Escape") onStopEditing();
|
||||
@@ -413,6 +423,14 @@ function TextContent({ node, theme, isEditingContent, textareaRef, onContentChan
|
||||
);
|
||||
}
|
||||
|
||||
function ResourceLabelBadge({ reference }: { reference: CanvasResourceReference }) {
|
||||
return (
|
||||
<span className={`pointer-events-none absolute right-2 top-2 z-30 rounded-md px-1.5 py-0.5 text-[10px] font-medium ${reference.active ? "bg-[#2f80ff] text-white shadow-sm" : "bg-black/35 text-white/75"}`}>
|
||||
{reference.label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function ImageNodeContent(props: NodeContentRendererProps) {
|
||||
if (!props.node.metadata?.content && props.isBatchRoot) {
|
||||
const content =
|
||||
|
||||
Reference in New Issue
Block a user