mirror of
https://github.com/earendil-works/pi.git
synced 2026-06-18 15:54:04 +08:00
fix(web-ui): sandbox svg artifact previews closes #3552
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Render SVG artifact previews through a blob-backed image instead of injecting untrusted SVG markup into the page DOM ([#3552](https://github.com/badlogic/pi-mono/issues/3552))
|
||||
|
||||
## [0.68.1] - 2026-04-22
|
||||
|
||||
## [0.68.0] - 2026-04-20
|
||||
|
||||
@@ -13,11 +13,17 @@ export class SvgArtifact extends ArtifactElement {
|
||||
@property() override filename = "";
|
||||
|
||||
private _content = "";
|
||||
@state() private previewUrl = "";
|
||||
|
||||
override get content(): string {
|
||||
return this._content;
|
||||
}
|
||||
override set content(value: string) {
|
||||
if (this._content === value) {
|
||||
return;
|
||||
}
|
||||
this._content = value;
|
||||
this.updatePreviewUrl();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
@@ -31,6 +37,21 @@ export class SvgArtifact extends ArtifactElement {
|
||||
this.viewMode = mode;
|
||||
}
|
||||
|
||||
private revokePreviewUrl() {
|
||||
if (this.previewUrl) {
|
||||
URL.revokeObjectURL(this.previewUrl);
|
||||
this.previewUrl = "";
|
||||
}
|
||||
}
|
||||
|
||||
private updatePreviewUrl() {
|
||||
this.revokePreviewUrl();
|
||||
if (!this._content) {
|
||||
return;
|
||||
}
|
||||
this.previewUrl = URL.createObjectURL(new Blob([this._content], { type: "image/svg+xml" }));
|
||||
}
|
||||
|
||||
public getHeaderButtons() {
|
||||
const toggle = new PreviewCodeToggle();
|
||||
toggle.mode = this.viewMode;
|
||||
@@ -52,14 +73,34 @@ export class SvgArtifact extends ArtifactElement {
|
||||
`;
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (this._content && !this.previewUrl) {
|
||||
this.updatePreviewUrl();
|
||||
}
|
||||
}
|
||||
|
||||
override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.revokePreviewUrl();
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="flex-1 overflow-auto">
|
||||
${
|
||||
this.viewMode === "preview"
|
||||
? html`<div class="h-full flex items-center justify-center">
|
||||
${unsafeHTML(this.content.replace(/<svg(\s|>)/i, (_m, p1) => `<svg class="w-full h-full"${p1}`))}
|
||||
? html`<div class="h-full flex items-center justify-center p-4">
|
||||
${
|
||||
this.previewUrl
|
||||
? html`<img
|
||||
class="max-w-full max-h-full w-full h-full object-contain"
|
||||
src="${this.previewUrl}"
|
||||
alt="${this.filename}"
|
||||
/>`
|
||||
: ""
|
||||
}
|
||||
</div>`
|
||||
: html`<pre class="m-0 p-4 text-xs"><code class="hljs language-xml">${unsafeHTML(
|
||||
hljs.highlight(this.content, { language: "xml", ignoreIllegals: true }).value,
|
||||
|
||||
Reference in New Issue
Block a user