blob: ea56aa848f510b88e78ee51e920acb95cfd4f97a [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">
Autoformatter4962f152025-05-06 17:24:20 +0000114 ${selector !== "(full page)"
115 ? `Taking screenshot of element: ${selector}`
116 : `Taking full page screenshot`}
Philip Zeyliger33d282f2025-05-03 04:01:54 +0000117 </div>
118 <div slot="result">
119 ${hasResult
120 ? html`
121 <div class="screenshot-container">
122 ${!this.imageLoaded && !this.loadError
Autoformatter4962f152025-05-06 17:24:20 +0000123 ? html`<div class="loading-indicator">
124 Loading screenshot...
125 </div>`
Philip Zeyliger33d282f2025-05-03 04:01:54 +0000126 : ""}
127 ${this.loadError
Autoformatter4962f152025-05-06 17:24:20 +0000128 ? html`<div class="error-message">
129 Failed to load screenshot
130 </div>`
Philip Zeyliger33d282f2025-05-03 04:01:54 +0000131 : html`
132 <img
133 class="screenshot"
134 src="${screenshotUrl}"
135 @load=${() => (this.imageLoaded = true)}
136 @error=${() => (this.loadError = true)}
137 ?hidden=${!this.imageLoaded}
138 />
139 ${this.imageLoaded
Autoformatter4962f152025-05-06 17:24:20 +0000140 ? html`<div class="screenshot-info">
141 Screenshot ID: ${screenshotId}
142 </div>`
Philip Zeyliger33d282f2025-05-03 04:01:54 +0000143 : ""}
144 `}
145 </div>
146 `
147 : ""}
148 </div>
149 </sketch-tool-card>
150 `;
151 }
152}
153
154declare global {
155 interface HTMLElementTagNameMap {
156 "sketch-tool-card-screenshot": SketchToolCardScreenshot;
157 }
158}