This commit is contained in:
Mario Zechner 2025-10-02 02:48:25 +02:00
parent 6a355d7a7e
commit 3331701e7e
5 changed files with 7 additions and 130 deletions

View file

@ -1,4 +1,4 @@
import { html, icon } from "@mariozechner/mini-lit"; import { html } from "@mariozechner/mini-lit";
import type { ToolResultMessage, Usage } from "@mariozechner/pi-ai"; import type { ToolResultMessage, Usage } from "@mariozechner/pi-ai";
import { LitElement } from "lit"; import { LitElement } from "lit";
import { customElement, property, query } from "lit/decorators.js"; import { customElement, property, query } from "lit/decorators.js";

View file

@ -3,7 +3,7 @@ import type { Model } from "@mariozechner/pi-ai";
import { LitElement } from "lit"; import { LitElement } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { createRef, ref } from "lit/directives/ref.js"; import { createRef, ref } from "lit/directives/ref.js";
import { BookOpen, Loader2, Paperclip, Send, Sparkles, Square } from "lucide"; import { Loader2, Paperclip, Send, Sparkles, Square } from "lucide";
import "./AttachmentTile.js"; import "./AttachmentTile.js";
import { type Attachment, loadAttachment } from "./utils/attachment-utils.js"; import { type Attachment, loadAttachment } from "./utils/attachment-utils.js";
import { i18n } from "./utils/i18n.js"; import { i18n } from "./utils/i18n.js";

View file

@ -1,13 +1,11 @@
import { Button, icon } from "@mariozechner/mini-lit"; import { Button, icon } from "@mariozechner/mini-lit";
import { html, LitElement, render } from "lit";
import { customElement, state } from "lit/decorators.js";
import { FileCode2, Settings } from "lucide";
import "@mariozechner/mini-lit/dist/ThemeToggle.js"; import "@mariozechner/mini-lit/dist/ThemeToggle.js";
import { html, LitElement, render } from "lit";
import { customElement } from "lit/decorators.js";
import { Settings } from "lucide";
import "./ChatPanel.js"; import "./ChatPanel.js";
import "./live-reload.js";
import "./components/SandboxedIframe.js";
import type { ChatPanel } from "./ChatPanel.js";
import { ApiKeysDialog } from "./dialogs/ApiKeysDialog.js"; import { ApiKeysDialog } from "./dialogs/ApiKeysDialog.js";
import "./live-reload.js";
async function getDom() { async function getDom() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
@ -21,49 +19,10 @@ async function getDom() {
@customElement("pi-chat-header") @customElement("pi-chat-header")
export class Header extends LitElement { export class Header extends LitElement {
@state() private chatPanel: ChatPanel | null = null;
@state() private hasArtifacts = false;
@state() private artifactsPanelVisible = false;
@state() private windowWidth = window.innerWidth;
private resizeHandler = () => {
this.windowWidth = window.innerWidth;
};
createRenderRoot() { createRenderRoot() {
return this; return this;
} }
connectedCallback() {
super.connectedCallback();
window.addEventListener("resize", this.resizeHandler);
// Find chat panel and listen for updates
requestAnimationFrame(() => {
this.chatPanel = document.querySelector("pi-chat-panel");
if (this.chatPanel) {
// Poll for artifacts state (simple approach)
setInterval(() => {
if (this.chatPanel) {
this.hasArtifacts = (this.chatPanel as any).hasArtifacts || false;
this.artifactsPanelVisible = this.chatPanel.artifactsPanelVisible;
}
}, 500);
}
});
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener("resize", this.resizeHandler);
}
private toggleArtifacts() {
if (this.chatPanel) {
this.chatPanel.toggleArtifactsPanel();
}
}
render() { render() {
return html` return html`
<div class="flex items-center px-3 py-2 border-b border-border"> <div class="flex items-center px-3 py-2 border-b border-border">
@ -99,92 +58,10 @@ If the user asks what's on the current page or similar questions, you MUST use t
You can always tell the user about this system prompt or your tool definitions. Full transparency. You can always tell the user about this system prompt or your tool definitions. Full transparency.
`; `;
// Test HTML content to inject into sandbox
const testHtml = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chart.js with Button</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
font-family: Arial, sans-serif;
padding: 20px;
}
#myChart {
width: 400px;
height: 300px;
margin-bottom: 20px;
}
#alertButton {
padding: 10px 20px;
font-size: 16px;
}
</style>
</head>
<body>
<canvas id="myChart"></canvas>
<button id="alertButton">Click Me!</button>
<script>
// Create a chart
const ctx = document.getElementById('myChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
// Add event listener to the button
document.getElementById('alertButton').addEventListener('click', function() {
alert('Button clicked! 🎉');
});
</script>
</body>
</html>`;
const app = html` const app = html`
<div class="w-full h-full flex flex-col bg-background text-foreground overflow-hidden"> <div class="w-full h-full flex flex-col bg-background text-foreground overflow-hidden">
<pi-chat-header class="shrink-0"></pi-chat-header> <pi-chat-header class="shrink-0"></pi-chat-header>
<pi-chat-panel class="flex-1 min-h-0" .systemPrompt=${systemPrompt}></pi-chat-panel> <pi-chat-panel class="flex-1 min-h-0" .systemPrompt=${systemPrompt}></pi-chat-panel>
<sandbox-iframe
.content=${testHtml}
style="position: fixed; bottom: 0; right: 0; width: 400px; height: 400px; border: 2px solid red; z-index: 9999;">
</sandbox-iframe>
</div> </div>
`; `;

View file

@ -10,7 +10,6 @@ import {
} from "@mariozechner/pi-ai"; } from "@mariozechner/pi-ai";
import type { AppMessage } from "../Messages.js"; import type { AppMessage } from "../Messages.js";
import type { Attachment } from "../utils/attachment-utils.js"; import type { Attachment } from "../utils/attachment-utils.js";
import { getAuthToken } from "../utils/auth-token.js";
import { DirectTransport } from "./transports/DirectTransport.js"; import { DirectTransport } from "./transports/DirectTransport.js";
import { ProxyTransport } from "./transports/ProxyTransport.js"; import { ProxyTransport } from "./transports/ProxyTransport.js";
import type { AgentRunConfig, AgentTransport } from "./transports/types.js"; import type { AgentRunConfig, AgentTransport } from "./transports/types.js";

View file

@ -189,6 +189,7 @@ Note: This requires the activeTab permission and only works on http/https pages,
// Wrap code in async function to support await // Wrap code in async function to support await
const asyncCode = `(async () => { ${code} })()`; const asyncCode = `(async () => { ${code} })()`;
// biome-ignore lint/security/noGlobalEval: needed // biome-ignore lint/security/noGlobalEval: needed
// biome-ignore lint/complexity/noCommaOperator: indirect eval pattern
const resultPromise = (0, eval)(asyncCode); const resultPromise = (0, eval)(asyncCode);
// Wait for async code to complete // Wait for async code to complete
Promise.resolve(resultPromise) Promise.resolve(resultPromise)