Files
omniai-web/src/features/workbench/WorkbenchPromptPreview.tsx
T

88 lines
2.5 KiB
TypeScript
Raw Normal View History

import { FileTextOutlined, SoundOutlined } from "@ant-design/icons";
import type { PromptMentionItem, PromptMentionTokenRange, ReferenceItem } from "./workbenchConstants";
import { renderPromptPreviewNodes, getPromptMentionTokenRanges } from "./workbenchMentionUtils";
export { getPromptMentionTokenRanges };
export function findPromptMentionRangeInside(index: number, ranges: PromptMentionTokenRange[]) {
return ranges.find((range) => index > range.start && index < range.end);
}
export function findPromptMentionRangeOverlap(start: number, end: number, ranges: PromptMentionTokenRange[]) {
return ranges.find((range) => start < range.end && end > range.start);
}
export function ReferenceInlinePreview({
item,
}: {
item: Pick<ReferenceItem, "kind" | "name" | "previewUrl">;
}) {
if ((item.kind === "image" || item.kind === "video") && item.previewUrl) {
return item.kind === "video" ? (
<video src={item.previewUrl} muted playsInline />
) : (
<img src={item.previewUrl} alt={item.name} loading="lazy" />
);
}
return item.kind === "audio" ? <SoundOutlined /> : <FileTextOutlined />;
}
export function ReferencePreview({
item,
label,
}: {
item: Pick<ReferenceItem, "kind" | "name" | "previewUrl">;
label?: string;
}) {
if ((item.kind === "image" || item.kind === "video") && item.previewUrl) {
return item.kind === "video" ? (
<video src={item.previewUrl} muted playsInline />
) : (
<img src={item.previewUrl} alt={item.name} loading="lazy" />
);
}
return (
<span className="wb-composer__ref-icon">
{item.kind === "audio" ? <SoundOutlined /> : <FileTextOutlined />}
{label ? <span>{label}</span> : null}
</span>
);
}
export function PromptPreviewLayer({
text,
items,
onTokenPointerDown,
}: {
text: string;
items: PromptMentionItem[];
onTokenPointerDown?: (index: number) => void;
}) {
const nodes = renderPromptPreviewNodes(text, items);
if (nodes.length === 0) return null;
return (
<div
className="wb-composer__highlight"
aria-hidden="true"
onPointerDown={(event) => {
const target =
event.target instanceof Element
? event.target.closest<HTMLElement>(".wb-composer__mention-inline-chip")
: null;
if (!target) return;
event.preventDefault();
event.stopPropagation();
const tokenEnd = Number(target.dataset.tokenEnd);
if (Number.isFinite(tokenEnd)) {
onTokenPointerDown?.(tokenEnd);
}
}}
>
{nodes}
</div>
);
}