mac: bundle web chat assets
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
import hljs from "highlight.js";
|
||||
import { html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { createRef, ref } from "lit/directives/ref.js";
|
||||
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
||||
import { RefreshCw } from "lucide";
|
||||
import { RUNTIME_MESSAGE_ROUTER } from "../../components/sandbox/RuntimeMessageRouter.js";
|
||||
import { i18n } from "../../utils/i18n.js";
|
||||
import "../../components/SandboxedIframe.js";
|
||||
import { ArtifactElement } from "./ArtifactElement.js";
|
||||
import "./Console.js";
|
||||
import { icon } from "@mariozechner/mini-lit";
|
||||
import { Button } from "@mariozechner/mini-lit/dist/Button.js";
|
||||
import { CopyButton } from "@mariozechner/mini-lit/dist/CopyButton.js";
|
||||
import { DownloadButton } from "@mariozechner/mini-lit/dist/DownloadButton.js";
|
||||
import { PreviewCodeToggle } from "@mariozechner/mini-lit/dist/PreviewCodeToggle.js";
|
||||
let HtmlArtifact = class HtmlArtifact extends ArtifactElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.filename = "";
|
||||
this.runtimeProviders = [];
|
||||
this._content = "";
|
||||
this.logs = [];
|
||||
// Refs for DOM elements
|
||||
this.sandboxIframeRef = createRef();
|
||||
this.consoleRef = createRef();
|
||||
this.viewMode = "preview";
|
||||
}
|
||||
setViewMode(mode) {
|
||||
this.viewMode = mode;
|
||||
}
|
||||
getHeaderButtons() {
|
||||
const toggle = new PreviewCodeToggle();
|
||||
toggle.mode = this.viewMode;
|
||||
toggle.addEventListener("mode-change", (e) => {
|
||||
this.setViewMode(e.detail);
|
||||
});
|
||||
const copyButton = new CopyButton();
|
||||
copyButton.text = this._content;
|
||||
copyButton.title = i18n("Copy HTML");
|
||||
copyButton.showText = false;
|
||||
// Generate standalone HTML with all runtime code injected for download
|
||||
const sandbox = this.sandboxIframeRef.value;
|
||||
const sandboxId = `artifact-${this.filename}`;
|
||||
const downloadContent = sandbox?.prepareHtmlDocument(sandboxId, this._content, this.runtimeProviders || [], {
|
||||
isHtmlArtifact: true,
|
||||
isStandalone: true, // Skip runtime bridge and navigation interceptor for standalone downloads
|
||||
}) || this._content;
|
||||
return html `
|
||||
<div class="flex items-center gap-2">
|
||||
${toggle}
|
||||
${Button({
|
||||
variant: "ghost",
|
||||
size: "sm",
|
||||
onClick: () => {
|
||||
this.logs = [];
|
||||
this.executeContent(this._content);
|
||||
},
|
||||
title: i18n("Reload HTML"),
|
||||
children: icon(RefreshCw, "sm"),
|
||||
})}
|
||||
${copyButton}
|
||||
${DownloadButton({ content: downloadContent, filename: this.filename, mimeType: "text/html", title: i18n("Download HTML") })}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
set content(value) {
|
||||
const oldValue = this._content;
|
||||
this._content = value;
|
||||
if (oldValue !== value) {
|
||||
// Reset logs when content changes
|
||||
this.logs = [];
|
||||
this.requestUpdate();
|
||||
// Execute content in sandbox if it exists
|
||||
if (this.sandboxIframeRef.value && value) {
|
||||
this.executeContent(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
executeContent(html) {
|
||||
const sandbox = this.sandboxIframeRef.value;
|
||||
if (!sandbox)
|
||||
return;
|
||||
// Configure sandbox URL provider if provided (for browser extensions)
|
||||
if (this.sandboxUrlProvider) {
|
||||
sandbox.sandboxUrlProvider = this.sandboxUrlProvider;
|
||||
}
|
||||
const sandboxId = `artifact-${this.filename}`;
|
||||
// Create consumer for console messages
|
||||
const consumer = {
|
||||
handleMessage: async (message) => {
|
||||
if (message.type === "console") {
|
||||
// Create new array reference for Lit reactivity
|
||||
this.logs = [
|
||||
...this.logs,
|
||||
{
|
||||
type: message.method === "error" ? "error" : "log",
|
||||
text: message.text,
|
||||
},
|
||||
];
|
||||
this.requestUpdate(); // Re-render to show console
|
||||
}
|
||||
},
|
||||
};
|
||||
// Inject window.complete() call at the end of the HTML to signal when page is loaded
|
||||
// HTML artifacts don't time out - they call complete() when ready
|
||||
let modifiedHtml = html;
|
||||
if (modifiedHtml.includes("</html>")) {
|
||||
modifiedHtml = modifiedHtml.replace("</html>", "<script>if (window.complete) window.complete();</script></html>");
|
||||
}
|
||||
else {
|
||||
// If no closing </html> tag, append the script
|
||||
modifiedHtml += "<script>if (window.complete) window.complete();</script>";
|
||||
}
|
||||
// Load content - this handles sandbox registration, consumer registration, and iframe creation
|
||||
sandbox.loadContent(sandboxId, modifiedHtml, this.runtimeProviders, [consumer]);
|
||||
}
|
||||
get content() {
|
||||
return this._content;
|
||||
}
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
// Unregister sandbox when element is removed from DOM
|
||||
const sandboxId = `artifact-${this.filename}`;
|
||||
RUNTIME_MESSAGE_ROUTER.unregisterSandbox(sandboxId);
|
||||
}
|
||||
firstUpdated() {
|
||||
// Execute initial content
|
||||
if (this._content && this.sandboxIframeRef.value) {
|
||||
this.executeContent(this._content);
|
||||
}
|
||||
}
|
||||
updated(changedProperties) {
|
||||
super.updated(changedProperties);
|
||||
// If we have content but haven't executed yet (e.g., during reconstruction),
|
||||
// execute when the iframe ref becomes available
|
||||
if (this._content && this.sandboxIframeRef.value && this.logs.length === 0) {
|
||||
this.executeContent(this._content);
|
||||
}
|
||||
}
|
||||
getLogs() {
|
||||
if (this.logs.length === 0)
|
||||
return i18n("No logs for {filename}").replace("{filename}", this.filename);
|
||||
return this.logs.map((l) => `[${l.type}] ${l.text}`).join("\n");
|
||||
}
|
||||
render() {
|
||||
return html `
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="flex-1 overflow-hidden relative">
|
||||
<!-- Preview container - always in DOM, just hidden when not active -->
|
||||
<div class="absolute inset-0 flex flex-col" style="display: ${this.viewMode === "preview" ? "flex" : "none"}">
|
||||
<sandbox-iframe class="flex-1" ${ref(this.sandboxIframeRef)}></sandbox-iframe>
|
||||
${this.logs.length > 0
|
||||
? html `<artifact-console .logs=${this.logs} ${ref(this.consoleRef)}></artifact-console>`
|
||||
: ""}
|
||||
</div>
|
||||
|
||||
<!-- Code view - always in DOM, just hidden when not active -->
|
||||
<div class="absolute inset-0 overflow-auto bg-background" style="display: ${this.viewMode === "code" ? "block" : "none"}">
|
||||
<pre class="m-0 p-4 text-xs"><code class="hljs language-html">${unsafeHTML(hljs.highlight(this._content, { language: "html" }).value)}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
property()
|
||||
], HtmlArtifact.prototype, "filename", void 0);
|
||||
__decorate([
|
||||
property({ attribute: false })
|
||||
], HtmlArtifact.prototype, "runtimeProviders", void 0);
|
||||
__decorate([
|
||||
property({ attribute: false })
|
||||
], HtmlArtifact.prototype, "sandboxUrlProvider", void 0);
|
||||
__decorate([
|
||||
state()
|
||||
], HtmlArtifact.prototype, "viewMode", void 0);
|
||||
HtmlArtifact = __decorate([
|
||||
customElement("html-artifact")
|
||||
], HtmlArtifact);
|
||||
export { HtmlArtifact };
|
||||
//# sourceMappingURL=HtmlArtifact.js.map
|
||||
Reference in New Issue
Block a user