blob: 4c34d0c2d68afca8f52ff967032b3be02587df4e [file] [log] [blame]
Philip Zeyliger33d282f2025-05-03 04:01:54 +00001import { css, html, LitElement } from "lit";
2import { customElement, property, state } from "lit/decorators.js";
3import { ToolCall } from "../types";
4
5@customElement("sketch-tool-card-screenshot")
6export class SketchToolCardScreenshot extends LitElement {
7 @property()
8 toolCall: ToolCall;
9
10 @property()
11 open: boolean;
12
13 @state()
14 imageLoaded: boolean = false;
15
16 @state()
17 loadError: boolean = false;
18
19 static styles = css`
20 .summary-text {
21 font-style: italic;
22 padding: 0.5em;
23 }
24
25 .screenshot-container {
26 margin: 10px 0;
27 display: flex;
28 flex-direction: column;
29 align-items: center;
30 }
31
32 .screenshot {
33 max-width: 100%;
34 max-height: 500px;
35 border-radius: 4px;
36 box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
37 border: 1px solid #ddd;
38 }
39
40 .loading-indicator {
41 margin: 20px;
42 color: #666;
43 font-style: italic;
44 }
45
46 .error-message {
47 color: #d32f2f;
48 font-style: italic;
49 margin: 10px 0;
50 }
51
52 .screenshot-info {
53 margin-top: 8px;
54 font-size: 12px;
55 color: #666;
56 }
57
58 .selector-info {
59 padding: 4px 8px;
60 background-color: #f5f5f5;
61 border-radius: 4px;
62 font-family: monospace;
63 margin: 5px 0;
64 display: inline-block;
65 }
66 `;
67
68 constructor() {
69 super();
70 }
71
72 connectedCallback() {
73 super.connectedCallback();
74 }
75
76 disconnectedCallback() {
77 super.disconnectedCallback();
78 }
79
80 render() {
81 // Parse the input to get selector
82 let selector = "";
83 try {
84 if (this.toolCall?.input) {
85 const input = JSON.parse(this.toolCall.input);
86 selector = input.selector || "(full page)";
87 }
88 } catch (e) {
89 console.error("Error parsing screenshot input:", e);
90 }
91
92 // Get the screenshot ID from the result
93 let screenshotId = "";
94 let hasResult = false;
95 if (this.toolCall?.result_message?.tool_result) {
96 try {
97 const result = JSON.parse(this.toolCall.result_message.tool_result);
98 screenshotId = result.id;
99 hasResult = true;
100 } catch (e) {
101 console.error("Error parsing screenshot result:", e);
102 }
103 }
104
105 // Construct the URL for the screenshot (using relative URL without leading slash)
106 const screenshotUrl = screenshotId ? `screenshot/${screenshotId}` : "";
107
108 return html`
109 <sketch-tool-card .open=${this.open} .toolCall=${this.toolCall}>
110 <span slot="summary" class="summary-text">
111 Screenshot of ${selector}
112 </span>
113 <div slot="input" class="selector-info">
114 ${selector !== "(full page)" ? `Taking screenshot of element: ${selector}` : `Taking full page screenshot`}
115 </div>
116 <div slot="result">
117 ${hasResult
118 ? html`
119 <div class="screenshot-container">
120 ${!this.imageLoaded && !this.loadError
121 ? html`<div class="loading-indicator">Loading screenshot...</div>`
122 : ""}
123 ${this.loadError
124 ? html`<div class="error-message">Failed to load screenshot</div>`
125 : html`
126 <img
127 class="screenshot"
128 src="${screenshotUrl}"
129 @load=${() => (this.imageLoaded = true)}
130 @error=${() => (this.loadError = true)}
131 ?hidden=${!this.imageLoaded}
132 />
133 ${this.imageLoaded
134 ? html`<div class="screenshot-info">Screenshot ID: ${screenshotId}</div>`
135 : ""}
136 `}
137 </div>
138 `
139 : ""}
140 </div>
141 </sketch-tool-card>
142 `;
143 }
144}
145
146declare global {
147 interface HTMLElementTagNameMap {
148 "sketch-tool-card-screenshot": SketchToolCardScreenshot;
149 }
150}