mac: bundle web chat assets
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
import "@mariozechner/mini-lit/dist/CodeBlock.js";
|
||||
import { createRef, ref } from "lit/directives/ref.js";
|
||||
import { FileCode2 } from "lucide";
|
||||
import "../../components/ConsoleBlock.js";
|
||||
import { Diff } from "@mariozechner/mini-lit/dist/Diff.js";
|
||||
import { html } from "lit";
|
||||
import { i18n } from "../../utils/i18n.js";
|
||||
import { renderCollapsibleHeader, renderHeader } from "../renderer-registry.js";
|
||||
import { ArtifactPill } from "./ArtifactPill.js";
|
||||
// Helper to extract text from content blocks
|
||||
function getTextOutput(result) {
|
||||
if (!result)
|
||||
return "";
|
||||
return (result.content
|
||||
?.filter((c) => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("\n") || "");
|
||||
}
|
||||
// Helper to determine language for syntax highlighting
|
||||
function getLanguageFromFilename(filename) {
|
||||
if (!filename)
|
||||
return "text";
|
||||
const ext = filename.split(".").pop()?.toLowerCase();
|
||||
const languageMap = {
|
||||
js: "javascript",
|
||||
jsx: "javascript",
|
||||
ts: "typescript",
|
||||
tsx: "typescript",
|
||||
html: "html",
|
||||
css: "css",
|
||||
scss: "scss",
|
||||
json: "json",
|
||||
py: "python",
|
||||
md: "markdown",
|
||||
svg: "xml",
|
||||
xml: "xml",
|
||||
yaml: "yaml",
|
||||
yml: "yaml",
|
||||
sh: "bash",
|
||||
bash: "bash",
|
||||
sql: "sql",
|
||||
java: "java",
|
||||
c: "c",
|
||||
cpp: "cpp",
|
||||
cs: "csharp",
|
||||
go: "go",
|
||||
rs: "rust",
|
||||
php: "php",
|
||||
rb: "ruby",
|
||||
swift: "swift",
|
||||
kt: "kotlin",
|
||||
r: "r",
|
||||
};
|
||||
return languageMap[ext || ""] || "text";
|
||||
}
|
||||
export class ArtifactsToolRenderer {
|
||||
constructor(artifactsPanel) {
|
||||
this.artifactsPanel = artifactsPanel;
|
||||
}
|
||||
render(params, result, isStreaming) {
|
||||
const state = result ? (result.isError ? "error" : "complete") : isStreaming ? "inprogress" : "complete";
|
||||
// Create refs for collapsible sections
|
||||
const contentRef = createRef();
|
||||
const chevronRef = createRef();
|
||||
// Helper to get command labels
|
||||
const getCommandLabels = (command) => {
|
||||
const labels = {
|
||||
create: { streaming: i18n("Creating artifact"), complete: i18n("Created artifact") },
|
||||
update: { streaming: i18n("Updating artifact"), complete: i18n("Updated artifact") },
|
||||
rewrite: { streaming: i18n("Rewriting artifact"), complete: i18n("Rewrote artifact") },
|
||||
get: { streaming: i18n("Getting artifact"), complete: i18n("Got artifact") },
|
||||
delete: { streaming: i18n("Deleting artifact"), complete: i18n("Deleted artifact") },
|
||||
logs: { streaming: i18n("Getting logs"), complete: i18n("Got logs") },
|
||||
};
|
||||
return labels[command] || { streaming: i18n("Processing artifact"), complete: i18n("Processed artifact") };
|
||||
};
|
||||
// Helper to render header text with inline artifact pill
|
||||
const renderHeaderWithPill = (labelText, filename) => {
|
||||
if (filename) {
|
||||
return html `<span>${labelText} ${ArtifactPill(filename, this.artifactsPanel)}</span>`;
|
||||
}
|
||||
return html `<span>${labelText}</span>`;
|
||||
};
|
||||
// Error handling
|
||||
if (result?.isError) {
|
||||
const command = params?.command;
|
||||
const filename = params?.filename;
|
||||
const labels = command
|
||||
? getCommandLabels(command)
|
||||
: { streaming: i18n("Processing artifact"), complete: i18n("Processed artifact") };
|
||||
const headerText = labels.streaming;
|
||||
// For create/update/rewrite errors, show code block + console/error
|
||||
if (command === "create" || command === "update" || command === "rewrite") {
|
||||
const content = params?.content || "";
|
||||
const { old_str, new_str } = params || {};
|
||||
const isDiff = command === "update";
|
||||
const diffContent = old_str !== undefined && new_str !== undefined ? Diff({ oldText: old_str, newText: new_str }) : "";
|
||||
const isHtml = filename?.endsWith(".html");
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300 space-y-3">
|
||||
${isDiff ? diffContent : content ? html `<code-block .code=${content} language=${getLanguageFromFilename(filename)}></code-block>` : ""}
|
||||
${isHtml
|
||||
? html `<console-block .content=${getTextOutput(result) || i18n("An error occurred")} variant="error"></console-block>`
|
||||
: html `<div class="text-sm text-destructive">${getTextOutput(result) || i18n("An error occurred")}</div>`}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
}
|
||||
// For other errors, just show error message
|
||||
return {
|
||||
content: html `
|
||||
<div class="space-y-3">
|
||||
${renderHeader(state, FileCode2, headerText)}
|
||||
<div class="text-sm text-destructive">${getTextOutput(result) || i18n("An error occurred")}</div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
}
|
||||
// Full params + result
|
||||
if (result && params) {
|
||||
const { command, filename, content } = params;
|
||||
const labels = command
|
||||
? getCommandLabels(command)
|
||||
: { streaming: i18n("Processing artifact"), complete: i18n("Processed artifact") };
|
||||
const headerText = labels.complete;
|
||||
// GET command: show code block with file content
|
||||
if (command === "get") {
|
||||
const fileContent = getTextOutput(result) || i18n("(no output)");
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300">
|
||||
<code-block .code=${fileContent} language=${getLanguageFromFilename(filename)}></code-block>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
}
|
||||
// LOGS command: show console block
|
||||
if (command === "logs") {
|
||||
const logs = getTextOutput(result) || i18n("(no output)");
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300">
|
||||
<console-block .content=${logs}></console-block>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
}
|
||||
// CREATE/UPDATE/REWRITE: always show code block, + console block for .html files
|
||||
if (command === "create" || command === "rewrite") {
|
||||
const codeContent = content || "";
|
||||
const isHtml = filename?.endsWith(".html");
|
||||
const logs = getTextOutput(result) || "";
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300 space-y-3">
|
||||
${codeContent ? html `<code-block .code=${codeContent} language=${getLanguageFromFilename(filename)}></code-block>` : ""}
|
||||
${isHtml && logs ? html `<console-block .content=${logs}></console-block>` : ""}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
}
|
||||
if (command === "update") {
|
||||
const isHtml = filename?.endsWith(".html");
|
||||
const logs = getTextOutput(result) || "";
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300 space-y-3">
|
||||
${Diff({ oldText: params.old_str || "", newText: params.new_str || "" })}
|
||||
${isHtml && logs ? html `<console-block .content=${logs}></console-block>` : ""}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
}
|
||||
// For DELETE, just show header
|
||||
return {
|
||||
content: html `
|
||||
<div class="space-y-3">
|
||||
${renderHeader(state, FileCode2, renderHeaderWithPill(headerText, filename))}
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
}
|
||||
// Params only (streaming or waiting for result)
|
||||
if (params) {
|
||||
const { command, filename, content, old_str, new_str } = params;
|
||||
// If no command yet
|
||||
if (!command) {
|
||||
return { content: renderHeader(state, FileCode2, i18n("Preparing artifact...")), isCustom: false };
|
||||
}
|
||||
const labels = getCommandLabels(command);
|
||||
const headerText = labels.streaming;
|
||||
// Render based on command type
|
||||
switch (command) {
|
||||
case "create":
|
||||
case "rewrite":
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300">
|
||||
${content
|
||||
? html `<code-block .code=${content} language=${getLanguageFromFilename(filename)}></code-block>`
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
case "update":
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300">
|
||||
${old_str !== undefined && new_str !== undefined
|
||||
? Diff({ oldText: old_str, newText: new_str })
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
case "get":
|
||||
case "logs":
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
|
||||
<div ${ref(contentRef)} class="max-h-0 overflow-hidden transition-all duration-300"></div>
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
default:
|
||||
return {
|
||||
content: html `
|
||||
<div>
|
||||
${renderHeader(state, FileCode2, renderHeaderWithPill(headerText, filename))}
|
||||
</div>
|
||||
`,
|
||||
isCustom: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
// No params or result yet
|
||||
return { content: renderHeader(state, FileCode2, i18n("Preparing artifact...")), isCustom: false };
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=artifacts-tool-renderer.js.map
|
||||
Reference in New Issue
Block a user