1import{g as xe}from"./vendor-asset.js";import{a as ke,i as j,b as Ce}from"./vendor-device.js";import{T as D,l as Se,u as Ee}from"./main.js";import{M as V,s as Me}from"./vendor-toast.js";import{g as L}from"./vendor-i18n.js";import{p as Le}from"./vendor-html-to-markdown.js";import{g as U}from"./vendor-inapp.js";import"./vendor-storage.js";import"./vendor-dom.js";import"./vendor-idle.js";var Te=Object.defineProperty,Ae=(a,e,t)=>e in a?Te(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t,o=(a,e,t)=>Ae(a,typeof e!="symbol"?e+"":e,t);const O={loadingAriaLabel:"Loading",errorPrefix:"Error:",missingApiUrlError:"The api-url attribute is required. Please provide a valid API URL.",poweredBy:"Powered by",poweredByLinkLabel:"Cloudflare AI Search",placeholder:"Search...",searchButtonLabel:"Search",searchInputAriaLabel:"Search input",searchResultsAriaLabel:"Search results",emptyStateTitle:"Start Searching",emptyStateDescription:"Enter a query to search for results",modalEmptyStateDescription:"Start typing to search",noResultsTitle:"No Results Found",noResultsDescription:'No results found for "{query}"',modalNoResultsTitle:"No results found",modalNoResultsDescription:'No results for "{query}"',resultsCount:"Found {n} result",resultsCountPlural:"Found {n} results",resultsCountOverflow:"Showing {n} of {total} results",modalResultsCount:"{n} result",modalResultsCountPlural:"{n} results",modalResultsCountZero:"0 results",modalResultsCountError:"Error",seeMoreResults:"See more results",groupOther:"Other",favoriteResults:"Favorites",recentResults:"Recent",addFavorite:"Add to favorites",removeFavorite:"Remove from favorites",navigateHint:"Navigate",selectHint:"Select",closeHint:"Close",chatTitle:"Chat",chatPlaceholder:"Type a message...",chatInputAriaLabel:"Chat message input",sendButtonLabel:"Send",sendButtonAriaLabel:"Send message",chatEmptyTitle:"Start a Conversation",chatEmptyDescription:"Send a message to begin chatting",userAvatar:"U",assistantAvatar:"AI",unknownError:"Unknown error",openChatAriaLabel:"Open chat",clearHistoryAriaLabel:"Clear history",minimizeAriaLabel:"Minimize",closeAriaLabel:"Close",historyTitle:"History",newChatButton:"New Chat",clearChatButton:"Clear Chat",toggleSidebarTitle:"Toggle sidebar",deleteChatTitle:"Delete chat",noChatsYet:"No chats yet",yesterday:"Yesterday",justNow:"Just now",minuteAgo:"{n} minute ago",minutesAgo:"{n} minutes ago",hourAgo:"{n} hour ago",hoursAgo:"{n} hours ago",loadingMessages:["Searching...","Digging through results...","Scanning the knowledge base...","Finding the best matches...","Sifting through the data...","Almost there...","Looking far and wide...","Connecting the dots...","Rummaging through pages...","Hunting down answers..."]};function g(a){if(!a||typeof a!="object")return O;const e={...O};for(const t of Object.keys(a)){const s=a[t];if(s!=null){if(t==="loadingMessages"){Array.isArray(s)&&s.length>0&&(e.loadingMessages=s.filter(i=>typeof i=="string"),e.loadingMessages.length===0&&(e.loadingMessages=O.loadingMessages));continue}typeof s=="string"&&(e[t]=s)}}return e}function y(a,e={}){return a.replace(/\{(\w+)\}/g,(t,s)=>Object.hasOwn(e,s)?String(e[s]):t)}function T(a,e){if(!a)return null;try{const t=JSON.parse(a);if(t===null||typeof t!="object"||Array.isArray(t))throw new Error("translations must be a JSON object");return t}catch{return null}}const H=2500;function F(a,e){let t;function s(...i){clearTimeout(t),t=setTimeout(()=>{a(...i)},e)}return s.cancel=()=>clearTimeout(t),s}function c(a){const e=document.createElement("div");return e.textContent=a,e.innerHTML}function K(a){try{return decodeURI(a)}catch{return a}}function _(a){return new DOMParser().parseFromString(a,"text/html").documentElement.textContent||""}function Ie(a,e){const t=g(e),s=new Date(a),i=new Date().getTime()-s.getTime();if(i<6e4)return t.justNow;if(i<36e5){const r=Math.floor(i/6e4),n=r===1?t.minuteAgo:t.minutesAgo;return y(n,{n:r})}if(i<864e5){const r=Math.floor(i/36e5),n=r===1?t.hourAgo:t.hoursAgo;return y(n,{n:r})}return s.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function Q(a){return new Date(a).toLocaleDateString(void 0,{month:"short",day:"numeric"})}function J(a="id"){return`${a}-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}function m(a,e){return a!==null?a:e}function b(a,e){return a===null?e:a==="true"||a===""}function x(a,e){if(a===null)return e;const t=Number.parseInt(a,10);return Number.isNaN(t)?e:t}function Y(a){return typeof a!="string"||!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(a)?"":`<span class="result-icon" part="result-icon result-icon-${a}" aria-hidden="true"></span>`}function G(a,e){if(!(a===null||a===""))try{const t=JSON.parse(a);if(t===null||typeof t!="object"||Array.isArray(t))throw new Error("chat-query-rewrite must be a JSON object");const s=t,i={};return typeof s.enabled=="boolean"&&(i.enabled=s.enabled),typeof s.model=="string"&&(i.model=s.model),typeof s.rewritePrompt=="string"&&(i.rewritePrompt=s.rewritePrompt),i}catch{return}}function f(a,e){return new CustomEvent(a,{detail:e,bubbles:!0,composed:!0,cancelable:!0})}function Z(a,e,t="Other"){const s=new Map;for(const i of a){const r=i.metadata?.[e],n=r==null||String(r).trim()===""?t:String(r),l=s.get(n);l?l.push(i):s.set(n,[i])}return[...s].map(([i,r])=>({key:i,results:r}))}function W(a,e){let t=0;return a.map((s,i)=>` 2 <div class="result-group" role="group" aria-labelledby="result-group-label-${i}"> 3 <div class="result-group-header" id="result-group-label-${i}" role="presentation">
3${c(s.key)}</div> 4 ${s.results.map(r=>e(r,t++)).join("")} 5 </div> 6 `).join("")}function A(a){if(!a)throw new Error("API URL is required");return new He(a)}const ze="@cf/meta/llama-3.3-70b-instruct-fp8-fast",$e=`You rewrite a multi-turn chat into a single standalone search query for a retrieval system. 7 8Inputs: the full conversation in \`messages\`. The final user message is the one to answer; earlier messages are context only. 9 10Rules: 11- Output ONLY the rewritten query as plain text. No preamble, no quotes, no markdown, no explanation. 12- Resolve pronouns and references (it, that, they, the second one, the previous one, etc.) using prior turns. 13- Inline any entities, names, versions, products, or constraints from earlier turns that the final message depends on. 14- Preserve the user's original language and terminology. Do not translate. 15- Do not invent facts, sources, dates, or details not present in the conversation. 16- If the final user message is already fully self-contained, return it unchanged (modulo trivial cleanup). 17- Drop greetings, thanks, and meta questions about the assistant itself; keep only the information need. 18- Keep it concise \u2014 a search query, not a sentence. Aim for under 200 characters when possible. 19 20Return only the rewritten query.`;function Re(a){let e="message";const t=[];for(const s of a.split(` 21`)){const i=s.endsWith("\r")?s.slice(0,-1):s;if(i===""||i.startsWith(":"))continue;const r=i.indexOf(":"),n=r===-1?i:i.slice(0,r);let l=r===-1?"":i.slice(r+1);l.startsWith(" ")&&(l=l.slice(1)),n==="event"?e=l:n==="data"&&t.push(l)}return t.length===0?null:{event:e,data:t.join(` 22`)}}function S(a){return a!==null&&typeof a=="object"&&!Array.isArray(a)}function X(...a){const e={};for(const t of a)if(t)for(const[s,i]of Object.entries(t)){const r=e[s];S(r)&&S(i)?e[s]=X(r,i):e[s]=i}return e}function qe(a,e){if(!S(e))return a;const t=new URLSearchParams;for(const[h,d]of Object.entries(e))d!=null&&t.append(h,String(d));const s=t.toString();if(!s)return a;const i=a.indexOf("#"),r=i===-1?a:a.slice(0,i),n=i===-1?"":a.slice(i),l=r.includes("?")?"&":"?";return`${r}${l}${s}${n}`}function Be(a){if(!S(a))return{};const e={};for(const[t,s]of Object.entries(a))s!=null&&(e[t]=String(s));return e}function Oe(a){return S(a)?a:void 0}class He{constructor(e){o(this,"activeRequests",new Map),o(this,"baseUrl"),this.baseUrl=e.replace(/\/$/,"")}request(e,t,s,i){const r=t==="search"?"snippet-search":"snippet-chat-completions",n=qe(`${this.baseUrl}/${t}`,i?.queryParams);return fetch(n,{method:"POST",body:JSON.stringify(X(Oe(i?.body),e)),headers:{...Be(i?.headers),"Content-Type":"application/json",Accept:e.stream?"text/event-stream":"application/json","cf-ai-search-source":r},signal:s})}async search(e,t={}){const s=this.generateRequestId(),i=new AbortController,r=t.signal||i.signal;this.registerRequest(s,i);try{const n=await this.request({messages:[{role:"user",content:e}],stream:!1,ai_search_options:{retrieval:{metadata_only:!0,max_num_results:t.maxResults??30}}},"search",r,t.request);if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);if(!n.body)throw new Error("Response body is empty");const l=await n.json();if(l.success&&l.result)return l.result.chunks.map(h=>({type:"result",id:h.id,title:_(h.item.metadata?.title),description:h.item.metadata?.description?_(h.item.metadata?.description):"",timestamp:h.item.timestamp??void 0,url:h.item.key,image:h.item.metadata?.image||void 0,metadata:{...h.item.metadata,instance_id:h.instance_id}}));throw l.success===!1?new Error(l.error):new Error("Unknown error")}finally{this.unregisterRequest(s)}}async*searchStream(e,t={}){const s=this.generateRequestId(),i=new AbortController,r=t.signal||i.signal;this.registerRequest(s,i);const n=await this.request({messages:[{role:"user",content:e}],stream:!0,...t.maxResults!==void 0&&{max_num_results:t.maxResults}},"ai-search",r,t.request);if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);if(!n.body)throw new Error("Response body is empty");let l="";const h=n.body.getReader(),d=new TextDecoder;for(;;){const{done:u,value:p}=await h.read();if(u)break;const v=d.decode(p,{stream:!0});l+=v}yield{type:"result",id:"",title:"",description:l.replaceAll("data: ","").trim().split(` 23 24`).map(u=>JSON.parse(u)).map(u=>u.response).join(""),url:"",metadata:{}}}async*chat(e,t){const s=new AbortController,i=t?.signal||s.signal,r=t?.stream??!0,n={messages:[...t?.history??[],{role:"user",content:e}],stream:r};if(t?.queryRewrite){const h=typeof t.queryRewrite=="object"?t.queryRewrite:{};n.ai_search_options={query_rewrite:{enabled:!0,model:h.model??ze,rewrite_prompt:h.rewritePrompt??$e}}}const l=await this.request(n,"chat/completions",i);if(!l.ok)throw new Error(`HTTP error! status: ${l.status}`);if(!l.body)throw new Error("Response body is empty");if(!r){yield{type:"text",message:(await l.json()).choices.map(h=>h.message.content).join("")};return}yield*this.parseChatStream(l.body)}async*parseChatStream(e){const t=e.getReader(),s=new TextDecoder;let i="";const r=n=>{const l=Re(n);if(!l||l.event==="chunks")return null;if(l.data==="[DONE]")return"done";try{const h=JSON.parse(l.data).choices?.[0]?.delta?.content;if(typeof h=="string"&&h.length>0)return{type:"text",message:h}}catch{}return null};try{for(;;){const{done:n,value:l}=await t.read();if(n)break;i+=s.decode(l,{stream:!0});let h=i.indexOf(` 25 26`);for(;h!==-1;){const d=i.slice(0,h);i=i.slice(h+2);const u=r(d);if(u==="done")return;u&&(yield u),h=i.indexOf(` 27 28`)}}if(i+=s.decode(),i.trim().length>0){const n=r(i);n&&n!=="done"&&(yield n)}}catch(n){if(n.name==="AbortError")return;throw n}finally{t.releaseLock()}}cancelRequest(e){const t=this.activeRequests.get(e);
28t&&(t.controller.abort(),this.unregisterRequest(e))}cancelAllRequests(){for(const[e]of this.activeRequests)this.cancelRequest(e)}registerRequest(e,t){this.activeRequests.set(e,{id:e,controller:t,timestamp:Date.now()})}unregisterRequest(e){this.activeRequests.delete(e)}generateRequestId(){return`req-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}}const Pe="0.0.43",Ne=`<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w3.org/2000/svg" aria-label="Cloudflare" role="img"> 29 <path fill="#f38020" d="m280.8395,183.31456c11,-26 -4,-38 -19,-38l-148,-2c-4,0 -4,-6 1,-7l150,-2c17,-1 37,-15 43,-33c0,0 10,-21 9,-24a97,97 0 0 0 -187,-11c-38,-25 -78,9 -69,46c-48,3 -65,46 -60,72c0,1 1,2 3,2l274,0c1,0 3,-1 3,-3z"/> 30 <path fill="#faae40" d="m330.8395,81.31456c-4,0 -6,-1 -7,1l-5,21c-5,16 3,30 20,31l32,2c4,0 4,6 -1,7l-33,1c-36,4 -46,39 -46,39c0,2 0,3 2,3l113,0l3,-2a81,81 0 0 0 -78,-103"/> 31</svg>`,je="https://workers.cloudflare.com/product/ai-search",I=`Powered by <a href="${je}" target="_blank" rel="noopener noreferrer">Cloudflare AI Search ${Ne}</a>`,De=2e4,Ve=20,Ue="/stats";function ee(){return typeof document<"u"&&typeof window<"u"}class te{constructor(e,t={}){o(this,"baseUrl"),o(this,"endpoint"),o(this,"snippetVersion"),o(this,"flushIntervalMs"),o(this,"maxBufferSize"),o(this,"buffer",[]),o(this,"flushTimer",null),o(this,"destroyed",!1),o(this,"boundUnloadHandler"),o(this,"boundVisibilityHandler"),this.baseUrl=e.replace(/\/$/,""),this.endpoint=t.endpoint??Ue,this.snippetVersion=t.snippetVersion??Pe,this.flushIntervalMs=t.flushIntervalMs??De,this.maxBufferSize=Math.max(1,t.maxBufferSize??Ve),this.boundUnloadHandler=()=>this.flushBeacon(),this.boundVisibilityHandler=()=>{typeof document<"u"&&document.visibilityState==="hidden"&&this.flushBeacon()},ee()&&(window.addEventListener("pagehide",this.boundUnloadHandler),document.addEventListener("visibilitychange",this.boundVisibilityHandler))}trackSearch(e,t){this.track({inputQuery:e,snippetVersion:this.snippetVersion,totalResult:t})}trackClick(e,t,s,i){this.track({inputQuery:e,snippetVersion:this.snippetVersion,totalResult:t,clickedResultId:s,clickPosition:i,clickViewMore:!1})}trackViewMore(e,t){this.track({inputQuery:e,snippetVersion:this.snippetVersion,totalResult:t,clickViewMore:!0})}track(e){if(!this.destroyed){if(this.buffer.push(e),this.buffer.length>=this.maxBufferSize){this.flush();return}this.scheduleFlush()}}flush(){const e=this.drainBuffer();if(e.length===0)return;const t=JSON.stringify({events:e});fetch(this.buildUrl(),{method:"POST",headers:{"Content-Type":"application/json"},body:t,keepalive:!0}).catch(s=>{})}flushBeacon(){const e=this.drainBuffer();if(e.length===0)return;const t=JSON.stringify({events:e}),s=this.buildUrl();if(typeof navigator<"u"&&typeof navigator.sendBeacon=="function")try{const i=new Blob([t],{type:"application/json"});if(navigator.sendBeacon(s,i))return}catch{}typeof fetch<"u"&&fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:t,keepalive:!0}).catch(()=>{})}destroy(){this.destroyed||(this.destroyed=!0,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),ee()&&(window.removeEventListener("pagehide",this.boundUnloadHandler),document.removeEventListener("visibilitychange",this.boundVisibilityHandler)),this.flushBeacon())}scheduleFlush(){this.flushTimer!==null||this.destroyed||(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush()},this.flushIntervalMs))}drainBuffer(){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length===0)return[];const e=this.buffer;return this.buffer=[],e}buildUrl(){const e=this.endpoint.startsWith("/")?this.endpoint:`/${this.endpoint}`;return`${this.baseUrl}${e}`}}const se=` 32/* Chat container */ 33.chat-container { 34 display: flex; 35 flex-direction: column; 36 height: 100%; 37 overflow-y: auto; 38} 39 40/* Messages area */ 41.chat-messages { 42 flex: 1; 43 overflow-y: auto; 44 overflow-x: hidden; 45 padding: var(--search-snippet-spacing-md); 46 display: flex; 47 flex-direction: column; 48 gap: var(--search-snippet-spacing-md); 49} 50 51.chat-messages::-webkit-scrollbar {
52 width: 8px; 53} 54 55.chat-messages::-webkit-scrollbar-track { 56 background: var(--search-snippet-surface); 57} 58 59.chat-messages::-webkit-scrollbar-thumb { 60 background: var(--search-snippet-border-color); 61 border-radius: var(--search-snippet-border-radius); 62} 63 64.chat-messages::-webkit-scrollbar-thumb:hover { 65 background: var(--search-snippet-text-secondary); 66} 67 68/* Message */ 69.chat-message { 70 display: flex; 71 gap: var(--search-snippet-spacing-sm); 72 max-width: 85%; 73 animation: slideIn var(--search-snippet-animation-duration) ease-out; 74 animation-fill-mode: both; 75} 76 77@keyframes slideIn { 78 from { 79 opacity: 0; 80 transform: translateY(10px); 81 } 82 to { 83 opacity: 1; 84 transform: translateY(0); 85 } 86} 87 88.chat-message-user { 89 align-self: flex-end; 90 flex-direction: row-reverse; 91} 92 93.chat-message-assistant { 94 align-self: flex-start; 95} 96 97.chat-message-system { 98 align-self: center; 99 max-width: 100%; 100} 101 102/* Message avatar */ 103.chat-message-avatar { 104 width: 32px; 105 height: 32px; 106 border-radius: 50%; 107 display: flex; 108 align-items: center; 109 justify-content: center; 110 flex-shrink: 0; 111 font-size: var(--search-snippet-font-size-sm); 112 font-weight: var(--search-snippet-font-weight-bold); 113 background: var(--search-snippet-primary-color); 114 color: white; 115} 116 117.chat-message-assistant .chat-message-avatar { 118 background: var(--search-snippet-surface); 119 color: var(--search-snippet-text-color); 120 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 121} 122 123/* Message content */ 124.chat-message-content { 125 flex: 1; 126 display: flex; 127 flex-direction: column; 128 gap: var(--search-snippet-spacing-xs); 129 max-width: 100%; 130} 131 132.chat-message-content ol, .chat-message-content ul { 133 margin-inline-start: 16px; 134} 135 136.chat-message-content ol li, .chat-message-content ul li { 137 padding-inline-start: 0; 138} 139 140.chat-message-bubble { 141 padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md); 142 border-radius: var(--search-snippet-border-radius); 143 word-wrap: break-word; 144 overflow-wrap: break-word; 145 /* Isolate layout cost of bubble height changes during streaming so 146 siblings don't reflow. */ 147 contain: layout style; 148} 149 150.chat-message-user .chat-message-bubble { 151 background: var(--search-snippet-user-message-bg); 152 color: var(--search-snippet-user-message-text); 153 border-top-right-radius: var(--search-snippet-spacing-xs); 154} 155 156.chat-message-assistant .chat-message-bubble { 157 background: var(--search-snippet-assistant-message-bg); 158 color: var(--search-snippet-assistant-message-text); 159 border-top-left-radius: var(--search-snippet-spacing-xs); 160 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 161} 162 163.chat-message-system .chat-message-bubble { 164 background: var(--search-snippet-system-message-bg); 165 color: var(--search-snippet-system-message-text); 166 text-align: center; 167 font-size: var(--search-snippet-font-size-sm); 168 padding: var(--search-snippet-spacing-xs) var(--search-snippet-spacing-md); 169} 170 171.chat-message-text { 172 font-size: var(--search-snippet-font-size-base); 173 line-height: 1.5; 174 white-space: wrap; 175} 176.chat-message-text li{ 177 padding-inline-start: var(--search-snippet-spacing-md); 178} 179 180.chat-message-metadata { 181 display: flex; 182 align-items: center; 183 gap: var(--search-snippet-spacing-sm); 184 font-size: var(--search-snippet-font-size-sm); 185 color: var(--search-snippet-text-secondary); 186} 187 188.chat-message-user .chat-message-metadata { 189 justify-content: flex-end; 190} 191 192.chat-message-time { 193 opacity: 0.7; 194} 195 196/* Streaming indicator */ 197.chat-streaming { 198 display: flex; 199 align-items: center; 200 gap: var(--search-snippet-spacing-xs); 201} 202 203.chat-streaming-dot { 204 width: 8px; 205 height: 8px; 206 border-radius: 50%; 207 background: currentColor; 208 animation: pulse 1.4s ease-in-out infinite; 209} 210 211.chat-streaming-dot:nth-child(2) { 212 animation-delay: 0.2s; 213} 214 215.chat-streaming-dot:nth-child(3) { 216 animation-delay: 0.4s; 217} 218 219@keyframes pulse { 220 0%, 80%, 100% { 221 opacity: 0.3; 222 transform: scale(0.8); 223 } 224 40% { 225 opacity: 1; 226 transform: scale(1); 227 } 228} 229 230.chat-streaming .loading-text { 231 margin-left: var(--search-snippet-spacing-xs); 232} 233 234/* Input area */ 235.chat-input-area { 236 padding: var(--search-snippet-spacing-md); 237 border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 238 background: var(--search-snippet-surface); 239} 240 241.chat-input-wrapper { 242 display: flex; 243 gap: var(--search-snippet-spacing-sm); 244 align-items: flex-end; 245} 246 247.chat-input { 248 flex: 1; 249 min-height: var(--search-snippet-input-height); 250 max-height: 120px; 251 padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md); 252 font-family: var(--search-snippet-font-family); 253 font-size: var(--search-snippet-font-size-base); 254 line-height: var(--search-snippet-line-height); 255 color: var(--search-snippet-text-color); 256 background: var(--search-snippet-background); 257 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 258 border-radius: var(--search-snippet-border-radius); 259 outline: none; 260 resize: vertical; 261 transition: var(--search-snippet-transition); 262} 263 264.chat-input:focus { 265 border-color: var(--search-snippet-primary-color); 266 box-shadow: 0 0 0 3px var(--search-snippet-focus-ring); 267} 268 269.chat-input::placeholder { 270 color: var(--search-snippet-text-secondary); 271} 272 273.chat-input:disabled { 274 background: var(--search-snippet-surface);
275 cursor: not-allowed; 276 opacity: 0.6; 277} 278 279.chat-send-button { 280 flex-shrink: 0; 281 height: var(--search-snippet-input-height); 282 padding: 0 var(--search-snippet-spacing-lg); 283} 284 285.chat-send-button:disabled { 286 opacity: 0.6; 287 cursor: not-allowed; 288} 289 290/* Empty chat state */ 291.chat-empty { 292 display: flex; 293 flex-direction: column; 294 align-items: center; 295 justify-content: center; 296 padding: var(--search-snippet-spacing-xxl); 297 gap: var(--search-snippet-spacing-md); 298 color: var(--search-snippet-text-secondary); 299 text-align: center; 300 height: 100%; 301} 302 303.chat-empty-icon { 304 width: 64px; 305 height: 64px; 306 opacity: 0.5; 307} 308 309.chat-empty-title { 310 font-size: var(--search-snippet-font-size-lg); 311 font-weight: var(--search-snippet-font-weight-medium); 312 color: var(--search-snippet-text-color); 313} 314 315.chat-empty-description { 316 font-size: var(--search-snippet-font-size-sm); 317} 318 319/* Code blocks in messages */ 320.chat-message-bubble pre { 321 background: var(--search-snippet-surface); 322 padding: var(--search-snippet-spacing-sm); 323 border-radius: var(--search-snippet-border-radius); 324 overflow-x: auto; 325 font-family: var(--search-snippet-font-family-mono); 326 font-size: var(--search-snippet-font-size-sm); 327 margin: var(--search-snippet-spacing-xs) 0; 328} 329 330.chat-message-bubble code { 331 font-family: var(--search-snippet-font-family-mono); 332 font-size: 0.9em; 333 background: var(--search-snippet-surface); 334 padding: 2px 4px; 335 border-radius: var(--search-snippet-border-radius); 336} 337 338.chat-message-bubble pre code { 339 background: none; 340 padding: 0; 341} 342 343/* Links in messages */ 344.chat-message-bubble a { 345 color: var(--search-snippet-primary-color); 346 text-decoration: underline; 347} 348 349.chat-message-bubble a:hover { 350 text-decoration: none; 351} 352`,z=` 353:host { 354 /* Colors - Light Mode */ 355 --search-snippet-primary-color: #2563eb; 356 --search-snippet-primary-hover: #0f51dfff; 357 --search-snippet-background: #ffffff; 358 --search-snippet-surface: #f8f9fa; 359 --search-snippet-text-color: #212529; 360 --search-snippet-text-secondary: #6c757d; 361 --search-snippet-text-description: #495057; 362 --search-snippet-border-color: #dee2e6; 363 --search-snippet-hover-background: #f1f3f5; 364 --search-snippet-focus-ring: #0066cc40; 365 --search-snippet-error-color: #dc3545; 366 --search-snippet-error-background: #f8d7da; 367 --search-snippet-success-color: #28a745; 368 --search-snippet-success-background: #d4edda; 369 --search-snippet-warning-color: #ffc107; 370 --search-snippet-warning-background: #fff3cd; 371 372 /* Message Colors */ 373 --search-snippet-user-message-bg: #0066cc; 374 --search-snippet-user-message-text: #ffffff; 375 --search-snippet-assistant-message-bg: #f1f3f5; 376 --search-snippet-assistant-message-text: #212529; 377 --search-snippet-system-message-bg: #fff3cd; 378 --search-snippet-system-message-text: #856404; 379 380 /* Typography */ 381 --search-snippet-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 382 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 383 'Segoe UI Emoji', 'Segoe UI Symbol'; 384 --search-snippet-font-family-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 385 --search-snippet-font-size-base: 14px; 386 --search-snippet-font-size-sm: 12px; 387 --search-snippet-font-size-lg: 16px; 388 --search-snippet-font-size-xl: 18px; 389 --search-snippet-line-height: 1.5; 390 --search-snippet-font-weight-normal: 400; 391 --search-snippet-font-weight-medium: 500; 392 --search-snippet-font-weight-bold: 600; 393 394 /* Spacing */ 395 --search-snippet-spacing-xs: 4px; 396 --search-snippet-spacing-sm: 8px; 397 --search-snippet-spacing-md: 12px; 398 --search-snippet-spacing-lg: 16px; 399 --search-snippet-spacing-xl: 24px; 400 --search-snippet-spacing-xxl: 32px; 401 402 /* Sizing */ 403 --search-snippet-width: 100%; 404 --search-snippet-max-width: 100%; 405 --search-snippet-min-width: 320px; 406 --search-snippet-max-height: 600px; 407 --search-snippet-input-height: 44px; 408 --search-snippet-button-height: 36px; 409 --search-snippet-icon-size: 20px; 410 411 /* Border */ 412 --search-snippet-border-width: 1px; 413 --search-snippet-border-radius: 18px; 414 415 /* Shadows */ 416 --search-snippet-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); 417 --search-snippet-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); 418 --search-snippet-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15); 419 --search-snippet-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.2); 420 --search-snippet-shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06); 421 422 /* Animation */ 423 --search-snippet-transition-fast: 150ms ease; 424 --search-snippet-transition: 200ms ease; 425 --search-snippet-transition-slow: 300ms ease; 426 --search-snippet-animation-duration: 0.2s; 427 428 /* Z-index */ 429 --search-snippet-z-dropdown: 1000; 430 --search-snippet-z-modal: 1050; 431 --search-snippet-z-popover: 1060; 432 --search-snippet-z-tooltip: 1070; 433 434 /* Layout */ 435 display: block; 436 width: var(--search-snippet-width); 437 max-width: var(--search-snippet-max-width); 438 min-width: var(--search-snippet-min-width); 439 font-family: var(--search-snippet-font-family); 440 font-size: var(--search-snippet-font-size-base); 441 line-height: var(--search-snippet-line-height); 442 color: var(--search-snippet-text-color); 443 444 445 /* Search */ 446 --search-snippet-icon-size: 20px; 447 --search-snippet-icon-margin-left: 6px; 448 --search-snippet-result-icon-size: 20px; 449 --search-snippet-result-icon-color: var(--search-snippet-text-secondary); 450 --search-snippet-result-icon-active-color: var(--search-snippet-primary-color); 451 --search-snippet-result-item-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); 452 453 /* Chat Bubble */ 454 --chat-bubble-button-shadow: 0 8px 24px rgba(0, 0, 0, 0.2); 455 --chat-bubble-window-shadow: 0 8px 24px rgba(0, 0, 0, 0.2); 456 --chat-bubble-button-size: 60px; 457 --chat-bubble-button-radius: 50%; 458 --chat-bubble-button-icon-size: 28px; 459 --chat-bubble-button-icon-color: white; 460 --chat-bubble-button-bottom: 20px; 461 --chat-bubble-button-right: 20px; 462 --chat-bubble-button-z-index: 9999; 463 --chat-bubble-position: fixed; 464 465 466} 467 468:host(:not([theme="dark"])) { 469 /* Colors - Light Mode */ 470 --search-snippet-primary-color: #2563eb; 471 --search-snippet-primary-hover: #0f51dfff; 472 --search-snippet-background: #ffffff; 473 --search-snippet-surface: #f8f9fa; 474 --search-snippet-text-color: #212529; 475 --search-snippet-text-secondary: #6c757d; 476 --search-snippet-text-description: #495057; 477 --search-snippet-border-color: #dee2e6; 478 --search-snippet-hover-background: #f1f3f5; 479 --search-snippet-focus-ring: #0066cc40; 480 --search-snippet-error-color: #dc3545; 481 --search-snippet-error-background: #f8d7da; 482 --search-snippet-success-color: #28a745; 483 --search-snippet-success-background: #d4edda; 484 --search-snippet-warning-color: #ffc107; 485 --search-snippet-warning-background: #fff3cd; 486 487 /* Message Colors */ 488 --search-snippet-user-message-bg: #0066cc; 489 --search-snippet-user-message-text: #ffffff; 490 --search-snippet-assistant-message-bg: #f1f3f5; 491 --search-snippet-assistant-message-text: #212529; 492 --search-snippet-system-message-bg: #fff3cd; 493 --search-snippet-system-message-text: #856404; 494} 495 496/* Dark Mode */ 497@media (prefers-color-scheme: dark) { 498 :host(:not([theme="light"])) { 499 --search-snippet-primary-color: #2563eb; 500 --search-snippet-primary-hover: #0f51dfff; 501 --search-snippet-background: #1a1b1e; 502 --search-snippet-surface: #25262b; 503 --search-snippet-text-color: #c1c2c5; 504 --search-snippet-text-secondary: #909296; 505 --search-snippet-text-description: #adb5bd; 506 --search-snippet-border-color: #373a40; 507 --search-snippet-hover-background: #2c2e33; 508 --search-snippet-focus-ring: #4dabf740; 509 --search-snippet-error-color: #ff6b6b; 510 --search-snippet-error-background: #3d1f1f; 511 --search-snippet-success-color: #51cf66; 512 --search-snippet-success-background: #1f3d24; 513 --search-snippet-warning-color: #ffd43b; 514 --search-snippet-warning-background: #3d3419; 515 516 --search-snippet-user-message-bg: #4dabf7; 517 --search-snippet-user-message-text: #1a1b1e; 518 --search-snippet-assistant-message-bg: #2c2e33; 519 --search-snippet-assistant-message-text: #c1c2c5; 520 --search-snippet-system-message-bg: #3d3419; 521 --search-snippet-system-message-text: #ffd43b; 522 color-scheme: dark; 523 } 524} 525 526/* Auto theme support */ 527:host([theme="light"]) { 528 color-scheme: light; 529} 530 531 532/* Base reset */ 533* { 534 box-sizing: border-box; 535 margin: 0; 536 padding: 0; 537} 538 539/* Metadata-driven result icons are hidden until an external ::part() rule displays them. */ 540.result-icon { 541 display: none; 542 flex: 0 0 var(--search-snippet-result-icon-size); 543 width: var(--search-snippet-result-icon-size); 544 height: var(--search-snippet-result-icon-size); 545 color: var(--search-snippet-result-icon-color); 546} 547 548a:hover > .result-icon, 549a:focus-visible > .result-icon, 550a.active > .result-icon { 551 color: var(--search-snippet-result-icon-active-color); 552} 553 554/* Container */ 555.container { 556 background: var(--search-snippet-background); 557 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 558 border-radius: var(--search-snippet-border-radius); 559 box-shadow: var(--search-snippet-shadow); 560 overflow: hidden; 561 display: flex; 562 flex-direction: column; 563} 564 565/* Header */ 566.header { 567 padding: var(--search-snippet-spacing-md); 568 border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 569 background: var(--search-snippet-surface); 570 display: flex; 571 align-items: center; 572 justify-content: space-between; 573 gap: var(--search-snippet-spacing-md); 574} 575 576.header-title { 577 font-size: var(--search-snippet-font-size-lg);
578 font-weight: var(--search-snippet-font-weight-bold); 579 color: var(--search-snippet-text-color); 580} 581 582/* Input */ 583.input-wrapper { 584 position: relative; 585 display: flex; 586 align-items: center; 587 gap: var(--search-snippet-spacing-sm); 588} 589 590.input { 591 width: 100%; 592 height: var(--search-snippet-input-height); 593 padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md); 594 font-family: var(--search-snippet-font-family); 595 font-size: var(--search-snippet-font-size-base); 596 line-height: var(--search-snippet-line-height); 597 color: var(--search-snippet-text-color); 598 background: var(--search-snippet-background); 599 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 600 border-radius: var(--search-snippet-border-radius); 601 outline: none; 602 transition: var(--search-snippet-transition); 603} 604 605.input:focus { 606 border-color: var(--search-snippet-primary-color); 607 box-shadow: 0 0 0 3px var(--search-snippet-focus-ring); 608} 609 610.input::placeholder { 611 color: var(--search-snippet-text-secondary); 612} 613 614.input:disabled { 615 background: var(--search-snippet-surface); 616 cursor: not-allowed; 617 opacity: 0.6; 618} 619 620/* Button */ 621.button { 622 height: var(--search-snippet-button-height); 623 padding: 0 var(--search-snippet-spacing-lg); 624 font-family: var(--search-snippet-font-family); 625 font-size: var(--search-snippet-font-size-base); 626 font-weight: var(--search-snippet-font-weight-medium); 627 color: #ffffff; 628 background: var(--search-snippet-primary-color); 629 border: none; 630 border-radius: var(--search-snippet-border-radius); 631 cursor: pointer; 632 outline: none; 633 transition: var(--search-snippet-transition); 634 display: inline-flex; 635 align-items: center; 636 justify-content: center; 637 gap: var(--search-snippet-spacing-sm); 638 white-space: nowrap; 639} 640 641.button:hover:not(:disabled) { 642 background: var(--search-snippet-primary-hover); 643} 644 645.button:focus-visible { 646 box-shadow: 0 0 0 3px var(--search-snippet-focus-ring); 647} 648 649.button:disabled { 650 opacity: 0.6; 651 cursor: not-allowed; 652} 653 654.button-secondary { 655 background: var(--search-snippet-surface); 656 color: var(--search-snippet-text-color); 657 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 658} 659 660.button-secondary:hover:not(:disabled) { 661 background: var(--search-snippet-hover-background); 662} 663 664/* Content area */ 665.content { 666 flex: 1; 667 overflow-y: auto; 668 overflow-x: hidden; 669 padding: var(--search-snippet-spacing-md); 670} 671 672/* Scrollbar styling */ 673.content::-webkit-scrollbar {
674 width: 8px; 675} 676 677.content::-webkit-scrollbar-track { 678 background: var(--search-snippet-surface); 679} 680 681.content::-webkit-scrollbar-thumb { 682 background: var(--search-snippet-border-color); 683 border-radius: var(--search-snippet-border-radius); 684} 685 686.content::-webkit-scrollbar-thumb:hover { 687 background: var(--search-snippet-text-secondary); 688} 689 690/* Loading spinner */ 691.loading { 692 display: inline-block; 693 width: var(--search-snippet-icon-size); 694 height: var(--search-snippet-icon-size); 695 border: 2px solid currentColor; 696 border-top-color: transparent; 697 border-radius: 50%; 698 animation: spin 0.6s linear infinite; 699} 700 701@keyframes spin { 702 to { transform: rotate(360deg); } 703} 704 705/* Loading message animation */ 706@keyframes loading-message-in { 707 from { 708 opacity: 0; 709 transform: translateY(8px); 710 } 711 to { 712 opacity: 1; 713 transform: translateY(0); 714 } 715} 716 717.loading-text { 718 font-size: var(--search-snippet-font-size-sm); 719 color: var(--search-snippet-text-secondary); 720} 721 722.loading-text-animate { 723 animation: loading-message-in 0.3s ease-out; 724} 725 726/* Error message */ 727.error { 728 padding: var(--search-snippet-spacing-md); 729 color: var(--search-snippet-error-color); 730 background: var(--search-snippet-error-background); 731 border-radius: var(--search-snippet-border-radius); 732 font-size: var(--search-snippet-font-size-sm); 733} 734 735/* Empty state */ 736.empty { 737 padding: var(--search-snippet-spacing-xl); 738 text-align: center; 739 color: var(--search-snippet-text-secondary); 740} 741 742/* Accessibility */ 743.sr-only { 744 position: absolute; 745 width: 1px; 746 height: 1px; 747 padding: 0; 748 margin: -1px; 749 overflow: hidden; 750 clip: rect(0, 0, 0, 0); 751 white-space: nowrap; 752 border-width: 0; 753} 754 755/* Focus visible polyfill */ 756.focus-visible:focus { 757 outline: 2px solid var(--search-snippet-primary-color); 758 outline-offset: 2px; 759} 760 761/* Powered by branding - block style (for sidebars) */ 762.powered-by { 763 display: flex; 764 align-items: center; 765 justify-content: center; 766 gap: var(--search-snippet-spacing-xs); 767 padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md); 768 font-size: var(--search-snippet-font-size-sm); 769 color: var(--search-snippet-text-secondary); 770 background: var(--search-snippet-surface); 771 border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 772 margin-top: auto; 773 flex-shrink: 0; 774} 775 776.powered-by svg { 777 width: 16px; 778 height: 16px; 779 flex-shrink: 0; 780} 781 782.powered-by a, 783.powered-by-inline a { 784 color: var(--search-snippet-text-secondary); 785 text-decoration: none; 786 transition: color var(--search-snippet-transition-fast); 787 display: inline-flex; 788 align-items: center; 789 gap: 4px; 790} 791 792.powered-by a:hover, 793.powered-by-inline a:hover { 794 color: var(--search-snippet-primary-color); 795} 796 797/* Powered by branding - inline style (for headers/subtle placement) */ 798.powered-by-inline { 799 font-size: var(--search-snippet-font-size-sm); 800 color: var(--search-snippet-text-secondary); 801 padding: var(--search-snippet-spacing-xs) 0; 802 text-align: center; 803} 804`,Fe=/^[a-z][a-z0-9+.-]*:/i,Ke=new Set(["http:","https:","mailto:","tel:"]);function $(a){if(typeof a!="string")return"";const e=a.replace(/^[\s\u0000-\u001f\u007f]+|[\s\u0000-\u001f\u007f]+$/g,"");if(e==="")return"";if(!Fe.test(e))return e;let t;try{t=new URL(e)}catch{return""}return Ke.has(t.protocol)?e:""}function _e(a){let e=a;e=Qe(e),e=e.replace(/```([\s\S]*?)```/g,(n,l)=>`<pre><code>${l.trim()}</code></pre>`);const t=e.split(` 805`),s=[];let i=!1,r="";for(let n=0;n<t.length;n++){const l=t[n],h=l.match(/^(#{1,6})\s+(.+)$/);if(h){const p=h[1].length,v=h[2];s.push(`<h${p}>${E(v)}</h${p}>`);continue}if(l.match(/^---+$/)){s.push("<hr />");continue}if(l.match(/^>\s+/)){const p=l.replace(/^>\s+/,"");s.push(`<blockquote>${E(p)}</blockquote>`);continue}const d=l.match(/^[-*]\s+(.+)$/);if(d){(!i||r!=="ul")&&(i&&s.push(`</${r}>`),s.push("<ul>"),i=!0,r="ul"),s.push(`<li>${E(d[1])}</li>`);continue}const u=l.match(/^\d+\.\s+(.+)$/);if(u){(!i||r!=="ol")&&(i&&s.push(`</${r}>`),s.push("<ol>"),i=!0,r="ol"),s.push(`<li>${E(u[1])}</li>`);continue}if(i&&(s.push(`</${r}>`),i=!1,r=""),l.trim()===""){s.push("<br />");continue}s.push(`<p>${E(l)}</p>`)}return i&&s.push(`</${r}>`),s.join(` 806`)}function E(a){let e=a;return e=e.replace(/`([^`]+)`/g,"<code>$1</code>"),e=e.replace(/\*\*\*(.+?)\*\*\*/g,"<strong><em>$1</em></strong>"),e=e.replace(/___(.+?)___/g,"<strong><em>$1</em></strong>"),e=e.replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>"),e=e.replace(/__(.+?)__/g,"<strong>$1</strong>"),e=e.replace(/\*(.+?)\*/g,"<em>$1</em>"),e=e.replace(/_(.+?)_/g,"<em>$1</em>"),e=e.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(t,s,i)=>{const r=$(i);return r?`<a href="${r}" target="_blank" rel="noopener noreferrer">${s}</a>`:s}),e}function Qe(a){const e={"&":"&","<":"<",">":">",'"':""","'":"'"};return a.replace(/[&<>"']/g,t=>e[t]||t)}const Je=64;class ie{constructor(e,t,s){o(this,"container"),o(this,"client"),o(this,"props"),o(this,"translations"),o(this,"inputElement",null),o(this,"messagesContainer",null),o(this,"sendButton",null),o(this,"messages",[]),o(this,"isStreaming",!1),o(this,"currentStreamingMessageId",null),o(this,"currentChatAbortController",null),o(this,"loadingMessageInterval",null),o(this,"loadingMessageIndex",0),o(this,"pendingScrollFrame",null),o(this,"handleInputResize",null),o(this,"handleInputKeydown",null),o(this,"handleSendClick",null),this.container=e,this.client=t,this.props=s,this.translations=g(s.translations),this.render(),this.attachEventListeners()}render(){const e=this.translations;this.container.innerHTML=` 807 <div class="chat-container"> 808 <div class="chat-messages"> 809 ${this.renderEmptyStateHTML()} 810 </div> 811 <div class="chat-input-area"> 812 <div class="chat-input-wrapper"> 813 <textarea 814 class="chat-input" 815 placeholder="${c(this.props.placeholder||e.chatPlaceholder)}" 816 aria-label="${c(e.chatInputAriaLabel)}" 817 style="height: 40px;" 818 rows="1" 819 ></textarea> 820 <button class="button chat-send-button" aria-label="${c(e.sendButtonAriaLabel)}">
821 <span>${c(e.sendButtonLabel)}</span> 822 </button> 823 </div> 824 </div> 825 </div> 826 `,this.messagesContainer=this.container.querySelector(".chat-messages"),this.inputElement=this.container.querySelector(".chat-input"),this.sendButton=this.container.querySelector(".chat-send-button")}renderEmptyStateHTML(){const e=this.translations;return` 827 <div class="chat-empty"> 828 <svg class="chat-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 829 <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path> 830 </svg> 831 <div class="chat-empty-title">${c(e.chatEmptyTitle)}</div> 832 <div class="chat-empty-description"> 833 ${c(e.chatEmptyDescription)} 834 </div> 835 </div> 836 `}attachEventListeners(){!this.inputElement||!this.sendButton||(this.handleInputResize=e=>{const t=e.target;t.style.height="auto",t.style.height=`${t.scrollHeight}px`},this.inputElement.addEventListener("input",this.handleInputResize),this.handleInputKeydown=e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),this.handleSendMessage())},this.inputElement.addEventListener("keydown",this.handleInputKeydown),this.handleSendClick=()=>{this.handleSendMessage()},this.sendButton.addEventListener("click",this.handleSendClick))}async handleSendMessage(){if(!this.inputElement||this.isStreaming)return;const e=this.inputElement.value.trim();e.length!==0&&(this.inputElement.value="",this.inputElement.style.height="auto",await this.sendMessage(e))}async sendMessage(e){const t=this.messages.map(h=>({role:h.role,content:h.content})),s=this.resolveQueryRewriteOption(t),i={id:J("msg"),role:"user",content:e,timestamp:Date.now()};this.addMessage(i),this.renderMessages(!0),this.setStreamingState(!0);const r=J("msg"),n={id:r,role:"assistant",content:"",timestamp:Date.now()};this.addMessage(n),this.currentStreamingMessageId=r,this.renderMessages(!0);const l=new AbortController;this.currentChatAbortController=l;try{const h=this.client.chat(e,{history:t,queryRewrite:s,signal:l.signal});let d="";for await(const p of h)if(p.type==="text"&&p.message)d+=p.message,this.updateStreamingMessage(r,d);else if(p.type==="error"){this.showErrorInMessage(r,p.message||this.translations.unknownError);break}const u=this.messages.findIndex(p=>p.id===r);u!==-1&&(this.messages[u].content=d),this.container.dispatchEvent(f("message",{message:n}))}catch(h){this.showErrorInMessage(r,h.message),this.container.dispatchEvent(f("error",{error:{message:h.message,code:"CHAT_ERROR"}}))}finally{this.currentChatAbortController===l&&(this.currentChatAbortController=null),this.setStreamingState(!1),this.renderMessages(),this.currentStreamingMessageId=null}}resolveQueryRewriteOption(e){const t=this.props.chatQueryRewrite;return t?.enabled===!1||e.length===0?!1:t&&(t.model!==void 0||t.rewritePrompt!==void 0)?{model:t.model,rewritePrompt:t.rewritePrompt}:!0}addMessage(e){this.messages.push(e),this.renderMessages()}updateStreamingMessage(e,t){const s=this.messages.findIndex(i=>i.id===e);s!==-1&&(this.messages[s].content=t,this.updateStreamingMessageDOM(e,t)||this.renderMessages(!0))}updateStreamingMessageDOM(e,t){if(!this.messagesContainer)return!1;const s=this.messagesContainer.querySelector(`[data-message-id="${CSS.escape(e)}"]`);if(!s)return!1;const i=s.querySelector(".chat-message-bubble");if(!i)return!1;const r=this.isNearBottom();let n=i.querySelector(".chat-message-text");if(!n){const l=document.createElement("div");l.className="chat-message-text";const h=i.querySelector(".chat-streaming");h?i.insertBefore(l,h):i.appendChild(l),n=l}return n.textContent=t,r&&this.scheduleScrollToBottom(),!0}showErrorInMessage(e,t){const s=this.messages.findIndex(i=>i.id===e);s!==-1&&(this.messages[s].content=`${this.translations.errorPrefix} ${t}`,this.renderMessages())}renderMessages(e=!1){if(!this.messagesContainer)return;if(this.messages.length===0){this.messagesContainer.innerHTML=this.renderEmptyStateHTML();return}const t=this.messages.map(s=>this.renderMessage(s,e&&s.id===this.currentStreamingMessageId)).join("");this.messagesContainer.innerHTML=t,this.scheduleScrollToBottom()}renderMessage(e,t=!1){const s=this.translations,i=`chat-message-${e.role}`,r=e.role==="user"?s.userAvatar:s.assistantAvatar,n=s.loadingMessages[this.loadingMessageIndex]??"",l=e.content?t?c(e.content):_e(e.content):"";return` 837 <div class="chat-message ${i}" data-message-id="${c(e.id)}"> 838 <div class="chat-message-avatar">${c(r)}</div> 839 <div class="chat-message-content"> 840 <div class="chat-message-bubble"> 841 ${l?`<div class="chat-message-text">${l}</div>`:""} 842 ${t?`<div class="chat-streaming"><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="loading-text">${c(n)}</span></div>`:""} 843 </div> 844 <div class="chat-message-metadata">
845 <span class="chat-message-time">${c(Ie(e.timestamp,this.translations))}</span> 846 </div> 847 </div> 848 </div> 849 `}isNearBottom(){const e=this.messagesContainer;return e?e.scrollHeight-e.scrollTop-e.clientHeight<Je:!0}scheduleScrollToBottom(){this.messagesContainer&&this.pendingScrollFrame===null&&(this.pendingScrollFrame=requestAnimationFrame(()=>{this.pendingScrollFrame=null;const e=this.messagesContainer;e&&(e.scrollTop=e.scrollHeight)}))}setStreamingState(e){this.isStreaming=e,this.inputElement&&(this.inputElement.disabled=e),this.sendButton&&(this.sendButton.disabled=e,this.sendButton.innerHTML=e?'<div class="loading"></div>':`<span>${c(this.translations.sendButtonLabel)}</span>`),e?this.startLoadingMessages():this.clearLoadingMessages()}startLoadingMessages(){this.clearLoadingMessages();const e=this.translations.loadingMessages;this.loadingMessageIndex=Math.floor(Math.random()*e.length),this.loadingMessageInterval=setInterval(()=>{const t=this.translations.loadingMessages;this.loadingMessageIndex=(this.loadingMessageIndex+1)%t.length,this.isStreaming&&(this.updateLoadingTextDOM(t[this.loadingMessageIndex]??"")||this.renderMessages(!0))},H)}updateLoadingTextDOM(e){if(!this.messagesContainer||!this.currentStreamingMessageId)return!1;const t=this.messagesContainer.querySelector(`[data-message-id="${CSS.escape(this.currentStreamingMessageId)}"]`);if(!t)return!1;const s=t.querySelector(".chat-streaming .loading-text");return s?(s.textContent=e,!0):!1}clearLoadingMessages(){this.loadingMessageInterval&&(clearInterval(this.loadingMessageInterval),this.loadingMessageInterval=null)}getMessages(){return[...this.messages]}clearMessages(){this.currentChatAbortController&&(this.currentChatAbortController.abort(),this.currentChatAbortController=null),this.isStreaming&&(this.setStreamingState(!1),this.currentStreamingMessageId=null),this.pendingScrollFrame!==null&&(cancelAnimationFrame(this.pendingScrollFrame),this.pendingScrollFrame=null),this.messages=[],this.renderMessages()}setMessages(e){this.messages=[...e],this.renderMessages()}setProps(e){this.props=e,this.translations=g(e.translations),this.detachEventListeners(),this.render(),this.attachEventListeners(),this.renderMessages(this.isStreaming),this.isStreaming&&this.setStreamingState(!0)}detachEventListeners(){this.inputElement&&(this.handleInputResize&&this.inputElement.removeEventListener("input",this.handleInputResize),this.handleInputKeydown&&this.inputElement.removeEventListener("keydown",this.handleInputKeydown)),this.sendButton&&this.handleSendClick&&this.sendButton.removeEventListener("click",this.handleSendClick),this.handleInputResize=null,this.handleInputKeydown=null,this.handleSendClick=null}destroy(){this.currentChatAbortController&&(this.currentChatAbortController.abort(),this.currentChatAbortController=null),this.clearLoadingMessages(),this.pendingScrollFrame!==null&&(cancelAnimationFrame(this.pendingScrollFrame),this.pendingScrollFrame=null),this.isStreaming&&this.client.cancelAllRequests(),this.inputElement&&(this.handleInputResize&&this.inputElement.removeEventListener("input",this.handleInputResize),this.handleInputKeydown&&this.inputElement.removeEventListener("keydown",this.handleInputKeydown)),this.sendButton&&this.handleSendClick&&this.sendButton.removeEventListener("click",this.handleSendClick),this.handleInputResize=null,this.handleInputKeydown=null,this.handleSendClick=null}}const re="chat-bubble-snippet";class Ye extends HTMLElement{constructor(){super(),o(this,"shadow"),o(this,"client",null),o(this,"chatView",null),o(this,"container",null),o(this,"isExpanded",!1),o(this,"isMinimized",!1),o(this,"translationsOverride",null),o(this,"resolvedTranslations",g(null)),o(this,"chatQueryRewriteOverride",null),o(this,"handleBubbleClick",null),o(this,"handleCloseClick",null),o(this,"handleMinimizeClick",null),o(this,"handleClearClick",null),this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["api-url","placeholder","theme","hide-branding","translations","chat-query-rewrite"]}connectedCallback(){this.syncTranslationsFromAttribute(),this.render(),this.initializeClient(),this.dispatchEvent(f("ready",void 0))}disconnectedCallback(){this.cleanup()}attributeChangedCallback(e,t,s){t!==s&&(e==="api-url"?this.initializeClient():e==="theme"?this.updateTheme(s):e==="translations"&&(this.syncTranslationsFromAttribute(),this.isConnected&&this.rerenderAfterTranslationsChange()))}get translations(){return this.translationsOverride}get chatQueryRewrite(){return this.chatQueryRewriteOverride}set chatQueryRewrite(e){this.chatQueryRewriteOverride=e??null,this.chatView&&this.chatView.setProps(this.getProps())}set translations(e){this.translationsOverride=e??null,this.resolvedTranslations=g(this.translationsOverride),this.isConnected&&this.rerenderAfterTranslationsChange()}syncTranslationsFromAttribute(){if(this.translationsOverride){this.resolvedTranslations=g(this.translationsOverride);return}const e=T(this.getAttribute("translations"),"ChatBubbleSnippet");this.resolvedTranslations=g(e)}rerenderAfterTranslationsChange(){const e=this.isExpanded,t=this.isMinimized;this.removeEventListeners();const s=this.chatView?this.shadow.querySelector(".chat-content"):null;s?.parentNode&&s.parentNode.removeChild(s),this.render(),e&&(this.shadow.querySelector(".bubble-button")?.classList.add("hidden"),this.shadow.querySelector(".chat-window")?.classList.add("expanded"),t&&this.shadow.querySelector(".chat-window")?.classList.add("minimized"));const i=this.shadow.querySelector(".chat-window");if(this.chatView&&s&&i){const r=i.querySelector(".chat-content");r?i.replaceChild(s,r):i.appendChild(s),this.chatView.setProps(this.getProps())}else e&&this.initializeChatView()}getProps(){const e=this.resolvedTranslations;return{apiUrl:m(this.getAttribute("api-url"),""),placeholder:m(this.getAttribute("placeholder"),e.chatPlaceholder),theme:m(this.getAttribute("theme"),"auto"),hideBranding:b(this.getAttribute("hide-branding"),!1),translations:this.translationsOverride??void 0,chatQueryRewrite:this.resolveChatQueryRewrite()}}resolveChatQueryRewrite(){return this.chatQueryRewriteOverride!==null?this.chatQueryRewriteOverride:G(this.getAttribute("chat-query-rewrite"),"ChatBubbleSnippet")}initializeClient(){const e=this.getProps();if(!e.apiUrl){this.client=null;return}try{this.client=A(e.apiUrl)}catch{}}render(){const e=document.createElement("style");e.textContent=`${z} 850${se} 851${this.getBubbleStyles()}`,this.container=document.createElement("div"),this.container.className="
851chat-bubble-widget",this.container.innerHTML=this.getBaseHTML(),this.shadow.innerHTML="",this.shadow.appendChild(e),this.shadow.appendChild(this.container),this.attachEventListeners()}getBubbleStyles(){return` 852 .chat-bubble-widget { 853 position: var(--chat-bubble-position); 854 bottom: var(--chat-bubble-button-bottom); 855 right: var(--chat-bubble-button-right); 856 z-index: var(--chat-bubble-button-z-index); 857 font-family: var(--search-snippet-font-family); 858 font-size: var(--search-snippet-font-size-base); 859 } 860 861 .bubble-button { 862 width: var(--chat-bubble-button-size); 863 height: var(--chat-bubble-button-size); 864 border-radius: var(--chat-bubble-button-radius); 865 background: var(--search-snippet-primary-color); 866 border: none; 867 cursor: pointer; 868 box-shadow: var(--chat-bubble-button-shadow); 869 display: flex; 870 align-items: center; 871 justify-content: center; 872 transition: all 0.3s ease; 873 position: relative; 874 } 875 876 .bubble-button:hover { 877 background: var(--search-snippet-primary-hover); 878 transform: scale(1.05); 879 } 880 881 .bubble-button svg { 882 width: var(--chat-bubble-button-icon-size); 883 height: var(--chat-bubble-button-icon-size); 884 color: var(--chat-bubble-button-icon-color); 885 } 886 887 .bubble-button.hidden { 888 opacity: 0; 889 pointer-events: none; 890 transform: scale(0); 891 } 892 893 .chat-window { 894 position: absolute; 895 bottom: 0; 896 right: 0; 897 width: 380px; 898 height: 500px; 899 background: var(--search-snippet-background); 900 border-radius: var(--search-snippet-border-radius); 901 box-shadow: var(--chat-bubble-window-shadow); 902 display: flex; 903 flex-direction: column; 904 opacity: 0; 905 transform: scale(0.8) translateY(20px); 906 transform-origin: bottom right; 907 transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); 908 pointer-events: none; 909 overflow: hidden; 910 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 911 } 912 913 .chat-window.expanded { 914 opacity: 1; 915 transform: scale(1) translateY(0); 916 pointer-events: auto; 917 } 918 919 .chat-window.minimized { 920 height: 58px; 921 overflow: hidden; 922 } 923 924 .chat-header { 925 background: var(--search-snippet-surface); 926 padding: var(--search-snippet-spacing-md); 927 border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 928 display: flex; 929 align-items: center; 930 justify-content: space-between; 931 flex-shrink: 0; 932 } 933 934 .chat-header-title { 935 font-weight: var(--search-snippet-font-weight-bold); 936 color: var(--search-snippet-text-color); 937 display: flex; 938 align-items: center; 939 gap: var(--search-snippet-spacing-sm); 940 font-size: var(--search-snippet-font-size-lg); 941 } 942 943 .chat-header-title svg { 944 width: 20px; 945 height: 20px; 946 } 947 948 .chat-header-actions { 949 display: flex; 950 gap: var(--search-snippet-spacing-xs); 951 } 952 953 .icon-button { 954 width: 32px; 955 height: 32px; 956 border: none; 957 background: transparent; 958 border-radius: var(--search-snippet-border-radius); 959 cursor: pointer; 960 display: flex; 961 align-items: center; 962 justify-content: center; 963 transition: background var(--search-snippet-transition-fast); 964 color: var(--search-snippet-text-color); 965 } 966 967 .icon-button:hover { 968 background: var(--search-snippet-hover-background); 969 } 970 971 .icon-button svg { 972 width: 18px; 973 height: 18px; 974 } 975 976 .chat-content { 977 flex: 1; 978 overflow: hidden; 979 display: flex; 980 flex-direction: column; 981 } 982 983 @media (max-width: 480px) { 984 .chat-window { 985 width: calc(100vw - 40px); 986 max-width: 400px; 987 } 988 } 989 `}getBaseHTML(){const e=this.getProps(),t=this.resolvedTranslations,s=e.hideBranding?"":`<div class="powered-by">${I}</div>`;return` 990 <button class="bubble-button" aria-label="${c(t.openChatAriaLabel)}"> 991 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 992 <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path> 993 </svg> 994 </button> 995 <div class="chat-window"> 996 <div class="chat-header"> 997 <div class="chat-header-title"> 998 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 999 <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path> 1000 </svg>
1001 <span>${c(t.chatTitle)}</span> 1002 </div> 1003 <div class="chat-header-actions"> 1004 <button class="icon-button clear-button" aria-label="${c(t.clearHistoryAriaLabel)}"> 1005 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1006 <polyline points="3 6 5 6 21 6"></polyline> 1007 <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path> 1008 </svg> 1009 </button> 1010 <button class="icon-button minimize-button" aria-label="${c(t.minimizeAriaLabel)}"> 1011 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1012 <line x1="5" y1="12" x2="19" y2="12"></line> 1013 </svg> 1014 </button> 1015 <button class="icon-button close-button" aria-label="${c(t.closeAriaLabel)}"> 1016 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1017 <line x1="18" y1="6" x2="6" y2="18"></line> 1018 <line x1="6" y1="6" x2="18" y2="18"></line> 1019 </svg> 1020 </button> 1021 </div> 1022 </div> 1023 <div class="chat-content"></div> 1024 ${s} 1025 </div> 1026 `}attachEventListeners(){const e=this.shadow.querySelector(".bubble-button"),t=this.shadow.querySelector(".close-button"),s=this.shadow.querySelector(".minimize-button"),i=this.shadow.querySelector(".clear-button");this.handleBubbleClick=()=>this.toggleChat(),this.handleCloseClick=()=>this.closeChat(),this.handleMinimizeClick=()=>this.toggleMinimize(),this.handleClearClick=()=>this.clearChat(),e?.addEventListener("click",this.handleBubbleClick),t?.addEventListener("click",this.handleCloseClick),s?.addEventListener("click",this.handleMinimizeClick),i?.addEventListener("click",this.handleClearClick)}removeEventListeners(){const e=this.shadow.querySelector(".bubble-button"),t=this.shadow.querySelector(".close-button"),s=this.shadow.querySelector(".minimize-button"),i=this.shadow.querySelector(".clear-button");this.handleBubbleClick&&e?.removeEventListener("click",this.handleBubbleClick),this.handleCloseClick&&t?.removeEventListener("click",this.handleCloseClick),this.handleMinimizeClick&&s?.removeEventListener("click",this.handleMinimizeClick),this.handleClearClick&&i?.removeEventListener("click",this.handleClearClick),this.handleBubbleClick=null,this.handleCloseClick=null,this.handleMinimizeClick=null,this.handleClearClick=null}toggleChat(){this.isExpanded=!this.isExpanded;const e=this.shadow.querySelector(".bubble-button"),t=this.shadow.querySelector(".chat-window");this.isExpanded?(e?.classList.add("hidden"),t?.classList.add("expanded"),this.initializeChatView()):(e?.classList.remove("hidden"),t?.classList.remove("expanded"))}closeChat(){this.isExpanded=!1,this.isMinimized=!1;const e=this.shadow.querySelector(".bubble-button"),t=this.shadow.querySelector(".chat-window");e?.classList.remove("hidden"),t?.classList.remove("expanded","minimized")}toggleMinimize(){this.isMinimized=!this.isMinimized;const e=this.shadow.querySelector(".chat-window");this.isMinimized?e?.classList.add("minimized"):e?.classList.remove("minimized")}initializeChatView(){if(this.chatView)return;const e=this.shadow.querySelector(".chat-content");if(!e)return;if(!this.client){const s=this.resolvedTranslations;e.innerHTML=` 1027 <div style="padding: 16px; color: var(--search-snippet-error-color, #ef4444); font-family: var(--search-snippet-font-family, sans-serif); font-size: var(--search-snippet-font-size-base, 14px);"> 1028 <strong>${c(s.errorPrefix)}</strong> ${c(s.missingApiUrlError)} 1029 </div> 1030 `;return}const t=this.getProps();this.chatView=new ie(e,this.client,t)}updateTheme(e){(e==="light"||e==="dark"?e:null)===null&&this.hasAttribute("theme")&&this.getAttribute("theme")!=="auto"&&this.removeAttribute("theme")}cleanup(){this.removeEventListeners(),this.client&&this.client.cancelAllRequests(),this.chatView&&this.chatView.destroy()}clearChat(){this.chatView?.clearMessages()}async sendMessage(e){this.chatView&&await this.chatView.sendMessage(e)}getMessages(){return this.chatView?.getMessages()||[]}}customElements.get(re)||customElements.define(re,Ye);const ae="chat-page-snippet",ne="chat-page-sessions";class oe extends HTMLElement{constructor(){super(),o(this,"shadow"),o(this,"client",null),o(this,"chatView",null),o(this,"container",null),o(this,"sessions",[]),o(this,"currentSessionId",null),o(this,"sidebarCollapsed",!1),o(this,"translationsOverride",null),o(this,"resolvedTranslations",g(null)),o(this,"chatQueryRewriteOverride",null),o(this,"handleClearClick",null),o(this,"handleNewChatClick",null),o(this,"handleToggleSidebarClick",null),o(this,"handleChatListClick",null),o(this,"handleMessageEvent",null),this.shadow=this.attachShadow({mode:"open"}),this.loadSessions()}static get observedAttributes(){return["api-url","placeholder","theme","hide-branding","translations","chat-query-rewrite"]}connectedCallback(){this.syncTranslationsFromAttribute(),this.render(),this.initializeClient(),this.setupView(),this.dispatchEvent(f("ready",void 0))}disconnectedCallback(){this.saveCurrentSession(),this.cleanup()}attributeChangedCallback(e,t,s){t!==s&&(e==="api-url"?(this.initializeClient(),this.setupView()):e==="theme"?this.updateTheme(s):e==="translations"&&(this.syncTranslationsFromAttribute(),this.isConnected&&this.rerenderAfterTranslationsChange()))}get translations(){return this.translationsOverride}get chatQueryRewrite(){return this.chatQueryRewriteOverride}set chatQueryRewrite(e){this.chatQueryRewriteOverride=e??null,this.chatView&&this.chatView.setProps(this.getProps())}set translations(e){this.translationsOverride=e??null,this.resolvedTranslations=g(this.translationsOverride),this.refreshDefaultSessionTitles(),this.isConnected&&this.rerenderAfterTranslationsChange()}syncTranslationsFromAttribute(){if(this.translationsOverride){this.resolvedTranslations=g(this.translationsOverride),this.refreshDefaultSessionTitles();return}const e=T(this.getAttribute("translations"),"ChatPageSnippet");this.resolvedTranslations=g(e),this.refreshDefaultSessionTitles()}refreshDefaultSessionTitles(){if(this.sessions.length===0)return;const e=this.resolvedTranslations.newChatButton;let t=!1;for(const s of this.sessions)s.titleIsDefault&&s.title!==e&&(s.title=e,t=!0);t&&this.saveSessions()}rerenderAfterTranslationsChange(){this.removeEventListeners();const e=this.chatView?this.shadow.querySelector(".container"):null;e?.parentNode&&e.parentNode.removeChild(e),this.render(),this.attachEventListeners(),this.renderChatList();const t=this.shadow.querySelector(".chat-page-content");
1030if(this.chatView&&e&&t){const s=t.querySelector(".container");s?t.replaceChild(e,s):t.appendChild(e),this.chatView.setProps(this.getProps()),this.handleMessageEvent=()=>{this.saveCurrentSession(),this.updateSessionTitle(),this.renderChatList()},e.addEventListener("message",this.handleMessageEvent)}}getProps(){const e=this.resolvedTranslations;return{apiUrl:m(this.getAttribute("api-url"),""),placeholder:m(this.getAttribute("placeholder"),e.chatPlaceholder),theme:m(this.getAttribute("theme"),"auto"),hideBranding:b(this.getAttribute("hide-branding"),!1),translations:this.translationsOverride??void 0,chatQueryRewrite:this.resolveChatQueryRewrite()}}resolveChatQueryRewrite(){return this.chatQueryRewriteOverride!==null?this.chatQueryRewriteOverride:G(this.getAttribute("chat-query-rewrite"),"ChatPageSnippet")}initializeClient(){const e=this.getProps();if(!e.apiUrl){this.client=null;return}try{this.client=A(e.apiUrl)}catch{}}render(){const e=document.createElement("style");e.textContent=`${z} 1031${se} 1032${this.getPageStyles()}`,this.container=document.createElement("div"),this.container.className="chat-page-container",this.container.innerHTML=this.getBaseHTML(),this.shadow.innerHTML="",this.shadow.appendChild(e),this.shadow.appendChild(this.container),this.attachEventListeners()}getPageStyles(){return` 1033 :host { 1034 display: block; 1035 width: 100%; 1036 height: 100vh; 1037 } 1038 1039 .chat-page-container { 1040 display: flex; 1041 height: 100%; 1042 background: var(--search-snippet-background); 1043 } 1044 1045 /* Sidebar styles */ 1046 .chat-sidebar { 1047 width: 280px; 1048 min-width: 280px; 1049 background: var(--search-snippet-surface); 1050 border-right: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1051 display: flex; 1052 flex-direction: column; 1053 transition: var(--search-snippet-transition); 1054 overflow: hidden; 1055 } 1056 1057 .chat-sidebar.collapsed { 1058 width: 0; 1059 min-width: 0; 1060 border-right: none; 1061 } 1062 1063 .sidebar-header { 1064 padding: var(--search-snippet-spacing-lg); 1065 border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1066 display: flex; 1067 align-items: center; 1068 justify-content: space-between; 1069 flex-shrink: 0; 1070 height: 69px; 1071 } 1072 1073 .sidebar-title { 1074 font-size: var(--search-snippet-font-size-lg); 1075 font-weight: var(--search-snippet-font-weight-bold); 1076 color: var(--search-snippet-text-color); 1077 } 1078 1079 .new-chat-button { 1080 width: 100%; 1081 height: var(--search-snippet-button-height); 1082 margin: var(--search-snippet-spacing-md) var(--search-snippet-spacing-lg); 1083 padding: 0 var(--search-snippet-spacing-lg); 1084 font-family: var(--search-snippet-font-family); 1085 font-size: var(--search-snippet-font-size-base); 1086 font-weight: var(--search-snippet-font-weight-medium); 1087 color: #fff; 1088 background: var(--search-snippet-primary-color); 1089 border: none; 1090 border-radius: var(--search-snippet-border-radius); 1091 cursor: pointer; 1092 outline: none; 1093 transition: var(--search-snippet-transition); 1094 display: inline-flex; 1095 align-items: center; 1096 justify-content: center; 1097 gap: var(--search-snippet-spacing-sm); 1098 box-sizing: border-box; 1099 width: calc(100% - var(--search-snippet-spacing-lg) * 2); 1100 } 1101 1102 .new-chat-button:hover { 1103 opacity: 0.9; 1104 } 1105 1106 .new-chat-button svg { 1107 width: 16px; 1108 height: 16px; 1109 } 1110 1111 .chat-list { 1112 flex: 1; 1113 overflow-y: auto; 1114 padding: var(--search-snippet-spacing-sm); 1115 } 1116 1117 .chat-list-item { 1118 display: flex; 1119 align-items: center; 1120 padding: var(--search-snippet-spacing-md) var(--search-snippet-spacing-lg); 1121 margin-bottom: var(--search-snippet-spacing-xs); 1122 border-radius: var(--search-snippet-border-radius); 1123 cursor: pointer; 1124 transition: var(--search-snippet-transition); 1125 gap: var(--search-snippet-spacing-sm); 1126 } 1127 1128 .chat-list-item:hover { 1129 background: var(--search-snippet-hover-background); 1130 } 1131 1132 .chat-list-item.active { 1133 background: var(--search-snippet-hover-background); 1134 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1135 } 1136 1137 .chat-list-item-content { 1138 flex: 1; 1139 min-width: 0; 1140 } 1141 1142 .chat-list-item-title { 1143 font-size: var(--search-snippet-font-size-base);
1144 font-weight: var(--search-snippet-font-weight-medium); 1145 color: var(--search-snippet-text-color); 1146 white-space: nowrap; 1147 overflow: hidden; 1148 text-overflow: ellipsis; 1149 } 1150 1151 .chat-list-item-date { 1152 font-size: var(--search-snippet-font-size-sm); 1153 color: var(--search-snippet-text-secondary); 1154 margin-top: 2px; 1155 } 1156 1157 .chat-list-item-delete { 1158 opacity: 0; 1159 background: none; 1160 border: none; 1161 padding: var(--search-snippet-spacing-xs); 1162 cursor: pointer; 1163 color: var(--search-snippet-text-secondary); 1164 border-radius: var(--search-snippet-border-radius-sm); 1165 transition: var(--search-snippet-transition); 1166 display: flex; 1167 align-items: center; 1168 justify-content: center; 1169 } 1170 1171 .chat-list-item:hover .chat-list-item-delete { 1172 opacity: 1; 1173 } 1174 1175 .chat-list-item-delete:hover { 1176 background: var(--search-snippet-error-background, rgba(239, 68, 68, 0.1)); 1177 color: var(--search-snippet-error-color, #ef4444); 1178 } 1179 1180 .chat-list-item-delete svg { 1181 width: 14px; 1182 height: 14px; 1183 } 1184 1185 .chat-list-empty { 1186 padding: var(--search-snippet-spacing-xl); 1187 text-align: center; 1188 color: var(--search-snippet-text-secondary); 1189 font-size: var(--search-snippet-font-size-sm); 1190 } 1191 1192 /* Main content area */ 1193 .chat-main { 1194 flex: 1; 1195 display: flex; 1196 flex-direction: column; 1197 min-width: 0; 1198 } 1199 1200 .chat-page-header { 1201 background: var(--search-snippet-surface); 1202 padding: var(--search-snippet-spacing-lg); 1203 border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1204 display: flex; 1205 align-items: center; 1206 justify-content: space-between; 1207 flex-shrink: 0; 1208 } 1209 1210 .chat-page-header-left { 1211 display: flex; 1212 align-items: center; 1213 gap: var(--search-snippet-spacing-md); 1214 } 1215 1216 .toggle-sidebar-button { 1217 width: 36px; 1218 height: 36px; 1219 padding: 0; 1220 font-family: var(--search-snippet-font-family); 1221 color: var(--search-snippet-text-color); 1222 background: var(--search-snippet-background); 1223 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1224 border-radius: var(--search-snippet-border-radius); 1225 cursor: pointer; 1226 outline: none; 1227 transition: var(--search-snippet-transition); 1228 display: inline-flex; 1229 align-items: center; 1230 justify-content: center; 1231 } 1232 1233 .toggle-sidebar-button:hover { 1234 background: var(--search-snippet-hover-background); 1235 } 1236 1237 .toggle-sidebar-button svg { 1238 width: 18px; 1239 height: 18px; 1240 } 1241 1242 .chat-page-header-title { 1243 font-size: var(--search-snippet-font-size-xl); 1244 font-weight: var(--search-snippet-font-weight-bold); 1245 color: var(--search-snippet-text-color); 1246 display: flex; 1247 align-items: center; 1248 gap: var(--search-snippet-spacing-md); 1249 } 1250 1251 .chat-page-header-title svg { 1252 width: 28px; 1253 height: 28px; 1254 } 1255 1256 .chat-page-header-actions { 1257 display: flex; 1258 gap: var(--search-snippet-spacing-sm); 1259 } 1260 1261 .header-button { 1262 height: var(--search-snippet-button-height); 1263 padding: 0 var(--search-snippet-spacing-lg); 1264 font-family: var(--search-snippet-font-family); 1265 font-size: var(--search-snippet-font-size-base); 1266 font-weight: var(--search-snippet-font-weight-medium); 1267 color: var(--search-snippet-text-color); 1268 background: var(--search-snippet-background); 1269 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1270 border-radius: var(--search-snippet-border-radius); 1271 cursor: pointer; 1272 outline: none; 1273 transition: var(--search-snippet-transition); 1274 display: inline-flex; 1275 align-items: center; 1276 justify-content: center; 1277 gap: var(--search-snippet-spacing-sm); 1278 } 1279 1280 .header-button:hover { 1281 background: var(--search-snippet-hover-background); 1282 } 1283 1284 .header-button svg { 1285 width: 16px; 1286 height: 16px; 1287 } 1288 1289 .chat-page-content { 1290 flex: 1; 1291 overflow: hidden; 1292 display: flex; 1293 flex-direction: column; 1294 width: 100%; 1295 } 1296 1297 .container { 1298 border: none; 1299 box-shadow: none; 1300 height: 100%; 1301 width: 100%; 1302 background: var(--search-snippet-background); 1303 border-radius: 0; 1304 } 1305 `}getBaseHTML(){const e=this.getProps(),t=this.resolvedTranslations,s=e.hideBranding?"":`<div class="powered-by">${I}</div>`;return` 1306 <div class="chat-sidebar"> 1307 <div class="sidebar-header">
1308 <span class="sidebar-title">${c(t.historyTitle)}</span> 1309 </div> 1310 <button class="new-chat-button"> 1311 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1312 <path d="M12 5v14M5 12h14"></path> 1313 </svg> 1314 ${c(t.newChatButton)} 1315 </button> 1316 <div class="chat-list"></div> 1317 ${s} 1318 </div> 1319 <div class="chat-main"> 1320 <div class="chat-page-header"> 1321 <div class="chat-page-header-left"> 1322 <button class="toggle-sidebar-button" title="${c(t.toggleSidebarTitle)}"> 1323 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1324 <path d="M3 12h18M3 6h18M3 18h18"></path> 1325 </svg> 1326 </button> 1327 <div class="chat-page-header-title"> 1328 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1329 <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path> 1330 </svg> 1331 <span>${c(t.chatTitle)}</span> 1332 </div> 1333 </div> 1334 <div class="chat-page-header-actions"> 1335 <button class="header-button clear-button"> 1336 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1337 <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path> 1338 </svg> 1339 ${c(t.clearChatButton)} 1340 </button> 1341 </div> 1342 </div> 1343 <div class="chat-page-content"> 1344 <div class="container"></div> 1345 </div> 1346 </div> 1347 `}attachEventListeners(){const e=this.shadow.querySelector(".clear-button"),t=this.shadow.querySelector(".new-chat-button"),s=this.shadow.querySelector(".toggle-sidebar-button"),i=this.shadow.querySelector(".chat-list");this.handleClearClick=()=>this.clearCurrentChat(),this.handleNewChatClick=()=>this.createNewChat(),this.handleToggleSidebarClick=()=>this.toggleSidebar(),this.handleChatListClick=r=>this.onChatListClick(r),e?.addEventListener("click",this.handleClearClick),t?.addEventListener("click",this.handleNewChatClick),s?.addEventListener("click",this.handleToggleSidebarClick),i?.addEventListener("click",this.handleChatListClick)}removeEventListeners(){const e=this.shadow.querySelector(".clear-button"),t=this.shadow.querySelector(".new-chat-button"),s=this.shadow.querySelector(".toggle-sidebar-button"),i=this.shadow.querySelector(".chat-list"),r=this.shadow.querySelector(".container");this.handleClearClick&&e?.removeEventListener("click",this.handleClearClick),this.handleNewChatClick&&t?.removeEventListener("click",this.handleNewChatClick),this.handleToggleSidebarClick&&s?.removeEventListener("click",this.handleToggleSidebarClick),this.handleChatListClick&&i?.removeEventListener("click",this.handleChatListClick),this.handleMessageEvent&&r&&r.removeEventListener("message",this.handleMessageEvent),this.handleClearClick=null,this.handleNewChatClick=null,this.handleToggleSidebarClick=null,this.handleChatListClick=null,this.handleMessageEvent=null}setupView(){const e=this.shadow.querySelector(".container");if(!this.client){if(e){const s=this.resolvedTranslations;e.innerHTML=` 1348 <div style="padding: 16px; color: var(--search-snippet-error-color, #ef4444); font-family: var(--search-snippet-font-family, sans-serif); font-size: var(--search-snippet-font-size-base, 14px);"> 1349 <strong>${c(s.errorPrefix)}</strong> ${c(s.missingApiUrlError)} 1350 </div> 1351 `}return}if(!e)return;const t=this.getProps();if(this.chatView=new ie(e,this.client,t),this.sessions.length===0)this.createNewChat();else{const s=this.sessions[0];this.switchToSession(s.id)}this.handleMessageEvent=()=>{this.saveCurrentSession(),this.updateSessionTitle(),this.renderChatList()},e.addEventListener("message",this.handleMessageEvent),this.renderChatList()}generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}loadSessions(){try{const e=localStorage.getItem(ne);e&&(this.sessions=JSON.parse(e),this.sessions.sort((t,s)=>s.updatedAt-t.updatedAt))}catch{}}saveSessions(){try{localStorage.setItem(ne,JSON.stringify(this.sessions))}catch{}}saveCurrentSession(){if(!this.currentSessionId||!this.chatView)return;const e=this.sessions.findIndex(t=>t.id===this.currentSessionId);e!==-1&&(this.sessions[e].messages=this.chatView.getMessages(),this.sessions[e].updatedAt=Date.now(),this.saveSessions())}updateSessionTitle(){if(!this.currentSessionId)return;const e=this.sessions.find(s=>s.id===this.currentSessionId);if(!e||e.messages.length===0||!(e.titleIsDefault??e.title===this.resolvedTranslations.newChatButton))return;const t=e.messages.find(s=>s.role==="user");t&&(e.title=t.content.slice(0,50)+(t.content.length>50?"...":""),e.titleIsDefault=!1,this.saveSessions())}createNewChat(){this.saveCurrentSession();const e={id:this.generateSessionId(),title:this.resolvedTranslations.newChatButton,messages:[],createdAt:Date.now(),updatedAt:Date.now(),titleIsDefault:!0};this.sessions.unshift(e),this.currentSessionId=e.id,this.saveSessions(),this.chatView?.clearMessages(),this.renderChatList()}switchToSession(e){if(e===this.currentSessionId)return;this.saveCurrentSession();const t=this.sessions.find(s=>s.id===e);t&&this.chatView&&(this.currentSessionId=e,this.chatView.setMessages(t.messages),this.renderChatList())}deleteSession(e){const t=this.sessions.findIndex(s=>s.id===e);t!==-1&&(this.sessions.splice(t,1),this.saveSessions(),e===this.currentSessionId&&(this.sessions.length>0?this.switchToSession(this.sessions[0].id):this.createNewChat()),this.renderChatList())}clearCurrentChat(){if(!this.currentSessionId)return;const e=this.sessions.find(t=>
1351t.id===this.currentSessionId);e&&(e.messages=[],e.title=this.resolvedTranslations.newChatButton,e.titleIsDefault=!0,e.updatedAt=Date.now(),this.saveSessions()),this.chatView?.clearMessages(),this.renderChatList()}toggleSidebar(){this.sidebarCollapsed=!this.sidebarCollapsed,this.shadow.querySelector(".chat-sidebar")?.classList.toggle("collapsed",this.sidebarCollapsed)}onChatListClick(e){const t=e.target,s=t.closest(".chat-list-item-delete");if(s){e.stopPropagation();const r=s.getAttribute("data-session-id");r&&this.deleteSession(r);return}const i=t.closest(".chat-list-item");if(i){const r=i.getAttribute("data-session-id");r&&this.switchToSession(r)}}renderChatList(){const e=this.shadow.querySelector(".chat-list");if(!e)return;const t=this.resolvedTranslations;if(this.sessions.length===0){e.innerHTML=`<div class="chat-list-empty">${this.escapeHTML(t.noChatsYet)}</div>`;return}e.innerHTML=this.sessions.map(s=>this.renderChatListItem(s)).join("")}renderChatListItem(e){const t=e.id===this.currentSessionId,s=this.formatDate(e.updatedAt),i=this.resolvedTranslations.deleteChatTitle;return` 1352 <div class="chat-list-item ${t?"active":""}" data-session-id="${e.id}"> 1353 <div class="chat-list-item-content"> 1354 <div class="chat-list-item-title">${this.escapeHTML(e.title)}</div> 1355 <div class="chat-list-item-date">${s}</div> 1356 </div> 1357 <button class="chat-list-item-delete" data-session-id="${e.id}" title="${this.escapeHTML(i)}"> 1358 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1359 <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path> 1360 </svg> 1361 </button> 1362 </div> 1363 `}formatDate(e){const t=new Date(e),s=new Date().getTime()-t.getTime(),i=Math.floor(s/(1e3*60*60*24));return i===0?t.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit"}):i===1?this.resolvedTranslations.yesterday:i<7?t.toLocaleDateString(void 0,{weekday:"long"}):t.toLocaleDateString(void 0,{month:"short",day:"numeric"})}escapeHTML(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}updateTheme(e){(e==="light"||e==="dark"?e:null)===null&&this.hasAttribute("theme")&&this.getAttribute("theme")!=="auto"&&this.removeAttribute("theme")}cleanup(){this.removeEventListeners(),this.client&&this.client.cancelAllRequests(),this.chatView&&this.chatView.destroy()}clearChat(){this.clearCurrentChat()}async sendMessage(e){this.chatView&&(await this.chatView.sendMessage(e),this.saveCurrentSession())}getMessages(){return this.chatView?.getMessages()||[]}getSessions(){return[...this.sessions]}getCurrentSession(){return this.sessions.find(e=>e.id===this.currentSessionId)||null}}customElements.get(ae)||customElements.define(ae,oe);const Ge=` 1364/* Search view states */ 1365.search-view { 1366 transition: var(--search-snippet-transition-slow); 1367 background: var(--search-snippet-background); 1368 border-radius: var(--search-snippet-border-radius); 1369 padding: 0px; 1370} 1371 1372.search-view-collapsed { 1373 max-height: 60px; 1374} 1375 1376.search-view-expanded { 1377 max-height: var(--search-snippet-max-height); 1378} 1379 1380 1381.search-icon { 1382 width: var(--search-snippet-icon-size); 1383 height: var(--search-snippet-icon-size); 1384 margin-left: var(--search-snippet-icon-margin-left); 1385 color: var(--search-snippet-text-color); 1386} 1387 1388/* Search input wrapper */ 1389.search-input-wrapper { 1390 display: grid; 1391 grid-template-columns: auto 1fr auto; 1392 align-items: center; 1393 gap: var(--search-snippet-spacing-sm); 1394 overflow: hidden; 1395 transition: max-width var(--search-snippet-transition-slow), 1396 opacity var(--search-snippet-transition); 1397 padding: var(--search-snippet-spacing-sm); 1398 border-radius: var(--search-snippet-border-radius); 1399 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1400} 1401 1402 1403 1404.search-input { 1405 flex: 1; 1406 border: none; 1407 outline: none; 1408 background: transparent; 1409 color: var(--search-snippet-text-color); 1410 font-size: var(--search-snippet-font-size-base); 1411 font-weight: var(--search-snippet-font-weight-medium); 1412 box-shadow: none; 1413 padding: 0; 1414} 1415 1416.search-input::placeholder { 1417 color: var(--search-snippet-text-secondary); 1418} 1419 1420.search-view:has(.search-input:not(:placeholder-shown)) .search-input-wrapper, .search-view:has(.search-input:not(:placeholder-shown)) { 1421 border-bottom-left-radius: 0; 1422 border-bottom-right-radius: 0; 1423} 1424 1425.search-view:focus-within { 1426 border-color: var(--search-snippet-primary-color); 1427 box-shadow: inset 0 0 0 3px var(--search-snippet-focus-ring); 1428} 1429 1430.search-view:has(.search-input:not(:placeholder-shown)) .search-content { 1431 max-height: 600px; 1432 opacity: 1; 1433 overflow-y: auto; 1434 padding: 8px; 1435} 1436 1437.search-submit-button { 1438 flex-shrink: 0; 1439 position: relative; 1440 border-radius: max(var(--search-snippet-button-min-border-radius, 4px), calc(var(--search-snippet-border-radius) - var(--search-snippet-spacing-sm))) 1441} 1442 1443.search-loading-indicator { 1444 position: absolute; 1445 inset: 0; 1446 display: flex; 1447 align-items: center; 1448 justify-content: center; 1449 visibility: hidden; 1450} 1451 1452.search-loading-indicator .loading { 1453 width: 16px; 1454 height: 16px; 1455} 1456 1457.search-submit-button.is-loading .search-submit-label { 1458 visibility: hidden; 1459} 1460 1461.search-submit-button.is-loading .search-loading-indicator { 1462 visibility: visible; 1463} 1464 1465/* Search content */ 1466.search-content { 1467 max-height: 0; 1468 opacity: 0; 1469 transition: max-height var(--search-snippet-transition-slow), 1470 opacity var(--search-snippet-transition); 1471 position: absolute; 1472 width: 100%; 1473 background: var(--search-snippet-background); 1474 border-bottom-left-radius: var(--search-snippet-border-radius); 1475 border-bottom-right-radius: var(--search-snippet-border-radius); 1476 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1477 border-top: none; 1478} 1479 1480.search-content::-webkit-scrollbar {
1481 width: 8px; 1482 height: 100px; 1483} 1484 1485.search-content::-webkit-scrollbar-track { 1486 background: var(--search-snippet-surface); 1487 1488} 1489 1490.search-content::-webkit-scrollbar-thumb { 1491 background: var(--search-snippet-border-color); 1492 border-radius: var(--search-snippet-border-radius); 1493} 1494 1495.search-content::-webkit-scrollbar-thumb:hover { 1496 background: var(--search-snippet-text-secondary); 1497} 1498 1499.container { 1500 overflow: unset; 1501 position: relative; 1502 border: none; 1503} 1504 1505.container:has(.search-input:not(:placeholder-shown)) { 1506 border-bottom-left-radius: 0; 1507 border-bottom-right-radius: 0; 1508} 1509 1510 1511/* Override header for search mode */ 1512 1513/* Search results */ 1514.search-results { 1515 display: flex; 1516 flex-direction: column; 1517 gap: var(--search-snippet-spacing-sm); 1518} 1519 1520.result-group { 1521 display: flex; 1522 flex-direction: column; 1523 gap: var(--search-snippet-spacing-sm); 1524} 1525 1526.result-group + .result-group { 1527 margin-top: var(--search-snippet-spacing-md); 1528} 1529 1530.result-group-header { 1531 padding: var(--search-snippet-spacing-xs) 0; 1532 color: var(--search-snippet-text-secondary); 1533 font-size: var(--search-snippet-font-size-sm); 1534 font-weight: 600; 1535 text-transform: uppercase; 1536 letter-spacing: 0.05em; 1537} 1538 1539a.search-result-item { 1540 display: flex; 1541 flex-direction: row; 1542 align-items: flex-start; 1543 gap: var(--search-snippet-spacing-md); 1544 padding: var(--search-snippet-spacing-md); 1545 background: var(--search-snippet-surface); 1546 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1547 border-radius: var(--search-snippet-border-radius); 1548 cursor: pointer; 1549 transition: var(--search-snippet-transition); 1550 text-decoration: none; 1551 color: inherit; 1552} 1553
1554/* Image thumbnail container */ 1555.search-result-image-container { 1556 flex-shrink: 0; 1557 width: 64px; 1558 height: 64px; 1559 border-radius: calc(var(--search-snippet-border-radius) - 4px); 1560 overflow: hidden; 1561 position: relative; 1562} 1563 1564.search-result-image { 1565 width: 100%; 1566 height: 100%; 1567 object-fit: contain; 1568 opacity: 0; 1569 transition: opacity var(--search-snippet-transition); 1570} 1571 1572.search-result-image.loaded { 1573 opacity: 1; 1574} 1575 1576/* Loading shimmer */ 1577.search-result-image-loading { 1578 position: absolute; 1579 inset: 0; 1580 background: linear-gradient( 1581 90deg, 1582 var(--search-snippet-surface) 25%, 1583 var(--search-snippet-border-color) 50%, 1584 var(--search-snippet-surface) 75% 1585 ); 1586 background-size: 200% 100%; 1587 animation: search-image-shimmer 1.5s infinite; 1588} 1589 1590@keyframes search-image-shimmer { 1591 0% { background-position: 200% 0; } 1592 100% { background-position: -200% 0; } 1593} 1594 1595/* Placeholder icon */ 1596.search-result-image-placeholder { 1597 position: absolute; 1598 inset: 0; 1599 display: flex; 1600 align-items: center; 1601 justify-content: center; 1602 color: var(--search-snippet-text-secondary); 1603 opacity: 0.5; 1604} 1605 1606.search-result-image-placeholder svg { 1607 width: 24px; 1608 height: 24px; 1609} 1610 1611/* Content wrapper */ 1612.search-result-content { 1613 flex: 1; 1614 min-width: 0; 1615} 1616 1617a.search-result-item:hover { 1618 background: var(--search-snippet-hover-background); 1619 border-color: var(--search-snippet-primary-color); 1620 transform: translateY(-1px); 1621 box-shadow: var(--search-snippet-result-item-shadow); 1622} 1623 1624a.search-result-item:focus-visible { 1625 outline: 2px solid var(--search-snippet-primary-color); 1626 outline-offset: 2px; 1627} 1628 1629.search-result-title { 1630 font-size: var(--search-snippet-font-size-base); 1631 font-weight: var(--search-snippet-font-weight-medium); 1632 color: var(--search-snippet-text-color); 1633 margin-bottom: var(--search-snippet-spacing-xs); 1634 display: -webkit-box; 1635 -webkit-line-clamp: 2; 1636 -webkit-box-orient: vertical; 1637 overflow: hidden; 1638} 1639 1640.search-result-snippet { 1641 font-size: var(--search-snippet-font-size-sm); 1642 color: var(--search-snippet-text-description); 1643 line-height: 1.6; 1644 display: -webkit-box; 1645 -webkit-line-clamp: 3; 1646 -webkit-box-orient: vertical; 1647 overflow: hidden; 1648} 1649 1650.search-result-metadata { 1651 display: flex; 1652 align-items: center; 1653 gap: var(--search-snippet-spacing-sm); 1654 margin-top: var(--search-snippet-spacing-xs); 1655 min-width: 0; 1656} 1657 1658.search-result-url { 1659 font-size: var(--search-snippet-font-size-sm); 1660 color: var(--search-snippet-primary-color); 1661 text-decoration: none; 1662 display: block; 1663 flex: 1; 1664 min-width: 0; 1665 overflow: hidden; 1666 text-overflow: ellipsis; 1667 white-space: nowrap; 1668} 1669 1670.search-result-url-empty { 1671 visibility: hidden; 1672} 1673 1674.search-result-date { 1675 font-size: 12px; 1676 font-weight: var(--search-snippet-font-weight-medium); 1677 color: var(--search-snippet-text-secondary); 1678 text-align: right; 1679 flex-shrink: 0; 1680} 1681 1682.search-result-url:hover { 1683 text-decoration: underline; 1684} 1685 1686/* Search header */ 1687.search-header { 1688 display: flex; 1689 align-items: center; 1690 justify-content: space-between; 1691 margin-bottom: var(--search-snippet-spacing-md); 1692 padding-bottom: var(--search-snippet-spacing-sm); 1693 border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1694} 1695 1696.search-count { 1697 font-size: var(--search-snippet-font-size-sm); 1698 color: var(--search-snippet-text-secondary); 1699} 1700 1701/* Search footer */ 1702.search-footer { 1703 padding: var(--search-snippet-spacing-md); 1704 padding-bottom: var(--search-snippet-spacing-xs); 1705 display: flex; 1706 align-items: center; 1707 justify-content: center; 1708 gap: var(--search-snippet-spacing-sm); 1709} 1710 1711/* See more link */ 1712.search-see-more { 1713 display: inline-flex; 1714 align-items: center; 1715 gap: var(--search-snippet-spacing-xs); 1716 font-size: var(--search-snippet-font-size-sm); 1717 color: var(--search-snippet-primary-color); 1718 text-decoration: none; 1719 font-weight: var(--search-snippet-font-weight-medium); 1720 transition: color var(--search-snippet-transition-fast); 1721} 1722 1723.search-see-more:hover { 1724 text-decoration: underline; 1725} 1726 1727/* Loading state for search */ 1728.search-loading { 1729 display: flex; 1730 flex-direction: column; 1731 align-items: center; 1732 justify-content: center; 1733 padding: var(--search-snippet-spacing-xxl); 1734 gap: var(--search-snippet-spacing-md); 1735 color: var(--search-snippet-text-secondary); 1736} 1737 1738/* Empty search state */ 1739.search-empty { 1740 display: flex; 1741 flex-direction: column; 1742 align-items: center; 1743 justify-content: center; 1744 padding: var(--search-snippet-spacing-xxl); 1745 gap: var(--search-snippet-spacing-md); 1746 color: var(--search-snippet-text-secondary); 1747 text-align: center; 1748} 1749 1750.search-empty-icon { 1751 width: 64px; 1752 height: 64px; 1753 opacity: 0.5; 1754} 1755 1756.search-empty-title { 1757 font-size: var(--search-snippet-font-size-lg);
1758 font-weight: var(--search-snippet-font-weight-medium); 1759 color: var(--search-snippet-text-color); 1760} 1761 1762.search-empty-description { 1763 font-size: var(--search-snippet-font-size-sm); 1764} 1765 1766/* Highlight matching text */ 1767.search-highlight { 1768 background: var(--search-snippet-warning-background); 1769 color: var(--search-snippet-warning-color); 1770 padding: 1px 2px; 1771 border-radius: 2px; 1772 font-weight: var(--search-snippet-font-weight-medium); 1773} 1774`,le="search-bar-snippet",ce=10,he=50;class Ze extends HTMLElement{constructor(){super(),o(this,"shadow"),o(this,"client",null),o(this,"stats",null),o(this,"container",null),o(this,"inputElement",null),o(this,"resultsContainer",null),o(this,"searchButton",null),o(this,"debouncedSearch",null),o(this,"currentSearchController",null),o(this,"loadingMessageInterval",null),o(this,"loadingMessageIndex",0),o(this,"translationsOverride",null),o(this,"resolvedTranslations",g(null)),o(this,"lastSearchQuery",""),o(this,"lastSearchTotal",0),o(this,"handleInputChange",null),o(this,"handleInputKeydownEnter",null),o(this,"handleInputKeydownEscape",null),o(this,"handleSearchButtonClick",null),o(this,"handleResultClick",null),o(this,"handleSeeMoreClick",null),this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["api-url","placeholder","max-results","max-render-results","debounce-ms","theme","hide-branding","show-url","show-date","hide-thumbnails","see-more","disable-analytics","request-options","translations"]}connectedCallback(){this.syncTranslationsFromAttribute(),this.initializeClient(),this.render(),this.dispatchEvent(f("ready",void 0))}disconnectedCallback(){this.cleanup()}attributeChangedCallback(e,t,s){t!==s&&(e==="api-url"||e==="disable-analytics"?this.initializeClient():e==="theme"?this.updateTheme(s):e==="translations"&&(this.syncTranslationsFromAttribute(),this.isConnected&&this.rerender()))}get translations(){return this.translationsOverride}set translations(e){this.translationsOverride=e??null,this.resolvedTranslations=g(this.translationsOverride),this.isConnected&&this.rerender()}rerender(){const e=this.inputElement?.value??"";this.render(),e&&this.inputElement&&(this.inputElement.value=e,e.trim().length>0&&this.performSearch(e.trim()))}syncTranslationsFromAttribute(){if(this.translationsOverride){this.resolvedTranslations=g(this.translationsOverride);return}const e=T(this.getAttribute("translations"),"SearchBarSnippet");this.resolvedTranslations=g(e)}getProps(){const e=this.resolvedTranslations;return{apiUrl:m(this.getAttribute("api-url"),""),placeholder:m(this.getAttribute("placeholder"),e.placeholder),maxResults:x(this.getAttribute("max-results"),he),maxRenderResults:x(this.getAttribute("max-render-results"),ce),debounceMs:x(this.getAttribute("debounce-ms"),300),theme:m(this.getAttribute("theme"),"auto"),hideBranding:b(this.getAttribute("hide-branding"),!1),showUrl:b(this.getAttribute("show-url"),!1),showDate:b(this.getAttribute("show-date"),!1),hideThumbnails:b(this.getAttribute("hide-thumbnails"),!1),seeMore:m(this.getAttribute("see-more"),""),groupBy:m(this.getAttribute("group-by"),""),disableAnalytics:b(this.getAttribute("disable-analytics"),!1),translations:this.translationsOverride??void 0}}getRequestOptions(){const e=this.getAttribute("request-options");if(e)try{const t=JSON.parse(e);if(t===null||typeof t!="object"||Array.isArray(t))throw new Error("request-options must be a JSON object");return t}catch{return}}initializeClient(){const e=this.getProps();if(!e.apiUrl){this.client=null,this.destroyStatsClient(),this.showMissingApiUrlError();return}try{this.client=A(e.apiUrl),this.destroyStatsClient(),e.disableAnalytics||(this.stats=new te(e.apiUrl))}catch{}}destroyStatsClient(){this.stats&&(this.stats.destroy(),this.stats=null)}render(){const e=this.getProps(),t=this.resolvedTranslations,s=r=>this.performSearch(r);this.debouncedSearch=F(s,e.debounceMs||400);const i=document.createElement("style");i.textContent=`${z} 1775${Ge}`,this.container=document.createElement("div"),this.container.className="container",this.container.innerHTML=` 1776 <div class="search-view"> 1777 <div class="search-input-wrapper"> 1778 <svg xmlns="http://www.w3.org/2000/svg" class="search-icon" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor">
1778<path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg> 1779 <input 1780 type="text" 1781 name="search-input" 1782 class="search-input" 1783 placeholder="${c(e.placeholder||t.placeholder)}" 1784 aria-label="${c(t.searchInputAriaLabel)}" 1785 autocomplete="off" 1786 /> 1787 <button class="button search-submit-button" aria-label="${c(t.searchButtonLabel)}"> 1788 <span class="search-submit-label">${c(t.searchButtonLabel)}</span> 1789 <span class="search-loading-indicator" aria-hidden="true"> 1790 <span class="loading"></span> 1791 </span> 1792 </button> 1793 </div> 1794 <div class="search-content"> 1795 <div class="search-results-wrapper"> 1796 <!-- Results will be inserted here --> 1797 </div> 1798 </div> 1799 </div> 1800 `,this.shadow.innerHTML="",this.shadow.appendChild(i),this.shadow.appendChild(this.container),this.inputElement=this.container.querySelector(".search-input"),this.resultsContainer=this.container.querySelector(".search-results-wrapper"),this.searchButton=this.container.querySelector(".search-submit-button"),this.attachEventListeners(),this.client||this.showMissingApiUrlError()}attachEventListeners(){this.inputElement&&(this.handleInputChange=e=>{const t=e.target.value.trim();t.length>0&&this.debouncedSearch?this.debouncedSearch(t):(this.debouncedSearch?.cancel(),this.currentSearchController?.abort(),this.showEmptyState())},this.inputElement.addEventListener("input",this.handleInputChange),this.handleInputKeydownEnter=e=>{if(e.key==="Enter"){const t=e.target.value.trim();t.length>0&&this.performSearch(t)}},this.inputElement.addEventListener("keydown",this.handleInputKeydownEnter),this.handleInputKeydownEscape=e=>{e.key==="Escape"&&this.inputElement&&(this.inputElement.value="")},window.addEventListener("keydown",this.handleInputKeydownEscape),this.searchButton&&(this.handleSearchButtonClick=()=>{const e=this.inputElement?.value.trim()||"";e.length>0&&this.performSearch(e)},this.searchButton.addEventListener("click",this.handleSearchButtonClick)))}async performSearch(e){if(!this.client){this.showMissingApiUrlError();return}this.currentSearchController&&(this.currentSearchController.abort(),this.currentSearchController=null);const t=new AbortController;this.currentSearchController=t,this.showLoadingState();try{const s=this.getProps(),i=await this.client.search(e,{signal:t.signal,maxResults:s.maxResults||he,request:this.getRequestOptions()});if(t.signal.aborted||this.currentSearchController!==t)return;const r=i.slice(0,s.maxRenderResults||ce);this.lastSearchQuery=e,this.lastSearchTotal=i.length,this.stats?.trackSearch(e,i.length),this.displayResults(r,e,i.length)}catch(s){if(s.name==="AbortError"||t.signal.aborted||this.currentSearchController!==t)return;this.showErrorState(s.message)}finally{this.currentSearchController===t&&(this.currentSearchController=null)}}displayResults(e,t,s=e.length){if(this.clearLoadingInterval(),this.setLoadingIndicator(!1),!this.resultsContainer)return;if(e.length===0){this.showNoResultsState(t);return}const i=this.getProps(),r=this.resolvedTranslations,n=i.hideBranding?"":`<div class="powered-by-inline">${I}</div>`,l=s>e.length,h=l?y(r.resultsCountOverflow,{n:e.length,total:s}):y(s===1?r.resultsCount:r.resultsCountPlural,{n:s}),d=i.seeMore&&l?`<div class="search-footer"> 1801 <a href="${c(i.seeMore+encodeURIComponent(t))}" class="search-see-more"> 1802 <span>${c(r.seeMoreResults)}</span> 1803 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> 1804 </a> 1805 </div>`:"",u=` 1806 <div class="search-header"> 1807 <div class="search-count"> 1808 ${c(h)} 1809 </div> 1810 ${n} 1811 </div> 1812 <div class="search-results"> 1813 ${i.groupBy?W(Z(e,i.groupBy,r.groupOther),(p,v)=>this.renderResult(p,v)):e.map((p,v)=>this.renderResult(p,v)).join("")} 1814 </div> 1815 ${d} 1816 `;this.resultsContainer.innerHTML=u,this.attachResultHandlers()}renderResult(e,t){const s=this.getProps(),i=Y(e.metadata?.icon),r=s.hideThumbnails?"":this.renderResultImage(e.image,e.title),n=$(e.url),l=n?c(n):"#",h=n?c(K(n)):"",d=s.showDate&&e.timestamp!==void 0?`<div class="search-result-date">${c(Q(e.timestamp))}</div>`:"",u=s.showUrl&&n||d?`<div class="search-result-metadata"> 1817 ${s.showUrl&&n?`<span class="search-result-url">${h}</span>
1817`:'<span class="search-result-url search-result-url-empty"></span>'} 1818 ${d} 1819 </div>`:"";return` 1820 <a href="${l}" class="search-result-item" data-index="${t}" data-result-id="${c(e.id||"")}"> 1821 ${i} 1822 ${r} 1823 <div class="search-result-content"> 1824 <div class="search-result-title">${c(e.title||"")}</div> 1825 <div class="search-result-snippet">${c(e.description||"")}</div> 1826 ${u} 1827 </div> 1828 </a> 1829 `}renderResultImage(e,t){const s='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>';return e?` 1830 <div class="search-result-image-container"> 1831 <div class="search-result-image-loading"></div> 1832 <div class="search-result-image-placeholder" style="display: none;">${s}</div> 1833 <img 1834 class="search-result-image" 1835 src="${c(e)}" 1836 alt="${c(t)}" 1837 loading="lazy" 1838 /> 1839 </div> 1840 `:` 1841 <div class="search-result-image-container"> 1842 <div class="search-result-image-placeholder">${s}</div> 1843 </div> 1844 `}attachResultHandlers(){this.detachResultTrackingHandlers();const e=this.resultsContainer;if(!e)return;this.handleResultClick=s=>{const i=s.target?.closest(".search-result-item");if(!i)return;i.getAttribute("href")==="#"&&s.preventDefault();const r=i.getAttribute("data-index"),n=i.getAttribute("data-result-id")??"",l=r!==null?Number.parseInt(r,10):Number.NaN;!Number.isNaN(l)&&n&&this.stats?.trackClick(this.lastSearchQuery,this.lastSearchTotal,n,l)},e.addEventListener("click",this.handleResultClick);const t=e.querySelector(".search-see-more");t&&(this.handleSeeMoreClick=()=>{this.stats?.trackViewMore(this.lastSearchQuery,this.lastSearchTotal)},t.addEventListener("click",this.handleSeeMoreClick)),this.container?.querySelectorAll(".search-result-image")?.forEach(s=>{s.addEventListener("load",()=>{s.classList.add("loaded"),s.closest(".search-result-image-container")?.querySelector(".search-result-image-loading")?.remove()}),s.addEventListener("error",()=>{const i=s.closest(".search-result-image-container");i?.querySelector(".search-result-image-loading")?.remove();const r=i?.querySelector(".search-result-image-placeholder");r&&(r.style.display="flex"),s.style.display="none"})})}detachResultTrackingHandlers(){const e=this.resultsContainer;e&&this.handleResultClick&&e.removeEventListener("click",this.handleResultClick),this.handleResultClick=null,this.handleSeeMoreClick=null}showLoadingState(){if(!this.resultsContainer||(this.clearLoadingInterval(),this.setLoadingIndicator(!0),this.resultsContainer.querySelector(".search-result-item")))return;const e=this.resolvedTranslations.loadingMessages;this.loadingMessageIndex=Math.floor(Math.random()*e.length),this.resultsContainer.innerHTML=` 1845 <div class="search-loading"> 1846 <div class="loading-text loading-text-animate">${c(e[this.loadingMessageIndex])}</div> 1847 </div> 1848 `,this.startLoadingInterval()}setLoadingIndicator(e){this.searchButton?.classList.toggle("is-loading",e),this.searchButton?.setAttribute("aria-busy",String(e)),this.resultsContainer?.setAttribute("aria-busy",String(e))}startLoadingInterval(){this.loadingMessageInterval=setInterval(()=>{const e=this.resolvedTranslations.loadingMessages;this.loadingMessageIndex=(this.loadingMessageIndex+1)%e.length;const t=this.resultsContainer?.querySelector(".loading-text");t&&(t.classList.remove("loading-text-animate"),t.textContent=e[this.loadingMessageIndex],t.classList.add("loading-text-animate"))},H)}clearLoadingInterval(){this.loadingMessageInterval&&(clearInterval(this.loadingMessageInterval),this.loadingMessageInterval=null)}showEmptyState(){if(this.clearLoadingInterval(),this.setLoadingIndicator(!1),!this.resultsContainer)return;const e=this.resolvedTranslations;this.resultsContainer.innerHTML=` 1849 <div class="search-empty">
1850 <svg class="search-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1851 <circle cx="11" cy="11" r="8"></circle> 1852 <path d="m21 21-4.35-4.35"></path> 1853 </svg> 1854 <div class="search-empty-title">${c(e.emptyStateTitle)}</div> 1855 <div class="search-empty-description"> 1856 ${c(e.emptyStateDescription)} 1857 </div> 1858 </div> 1859 `}showNoResultsState(e){if(this.clearLoadingInterval(),this.setLoadingIndicator(!1),!this.resultsContainer)return;const t=this.resolvedTranslations;this.resultsContainer.innerHTML=` 1860 <div class="search-empty"> 1861 <svg class="search-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 1862 <circle cx="11" cy="11" r="8"></circle> 1863 <line x1="21" y1="21" x2="16.65" y2="16.65"></line> 1864 </svg> 1865 <div class="search-empty-title">${c(t.noResultsTitle)}</div> 1866 <div class="search-empty-description"> 1867 ${c(y(t.noResultsDescription,{query:e}))} 1868 </div> 1869 </div> 1870 `}showErrorState(e){if(this.clearLoadingInterval(),this.setLoadingIndicator(!1),!this.resultsContainer)return;const t=this.resolvedTranslations;this.resultsContainer.innerHTML=` 1871 <div class="error"> 1872 <strong>${c(t.errorPrefix)}</strong> ${c(e)} 1873 </div> 1874 `}showMissingApiUrlError(){this.resultsContainer&&this.showErrorState(this.resolvedTranslations.missingApiUrlError)}updateTheme(e){const t=e==="light"||e==="dark"||e==="auto"?e:"auto";t==="auto"?this.removeAttribute("theme"):this.setAttribute("theme",t)}cleanup(){this.clearLoadingInterval(),this.currentSearchController&&(this.currentSearchController.abort(),this.currentSearchController=null),this.client&&this.client.cancelAllRequests(),this.destroyStatsClient(),this.inputElement&&(this.handleInputChange&&this.inputElement.removeEventListener("input",this.handleInputChange),this.handleInputKeydownEnter&&this.inputElement.removeEventListener("keydown",this.handleInputKeydownEnter),this.handleInputKeydownEscape&&window.removeEventListener("keydown",this.handleInputKeydownEscape)),this.searchButton&&this.handleSearchButtonClick&&this.searchButton.removeEventListener("click",this.handleSearchButtonClick),this.detachResultTrackingHandlers(),this.handleInputChange=null,this.handleInputKeydownEnter=null,this.handleInputKeydownEscape=null,this.handleSearchButtonClick=null}async search(e){await this.performSearch(e)}}customElements.get(le)||customElements.define(le,Ze);const We=` 1875/* Modal backdrop */ 1876.modal-backdrop { 1877 position: fixed; 1878 inset: 0; 1879 background: rgba(0, 0, 0, 0.5); 1880 backdrop-filter: blur(4px); 1881 z-index: var(--search-snippet-z-modal); 1882 opacity: 0; 1883 visibility: hidden; 1884 transition: opacity var(--search-snippet-transition), visibility var(--search-snippet-transition); 1885} 1886 1887.modal-backdrop.open { 1888 opacity: 1; 1889 visibility: visible; 1890} 1891 1892/* Modal container */ 1893.modal-container { 1894 position: fixed; 1895 top: 15%; 1896 left: 50%; 1897 transform: translateX(-50%) scale(0.95); 1898 width: 90%; 1899 max-width: 600px; 1900 max-height: 70vh; 1901 background: var(--search-snippet-background); 1902 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1903 border-radius: var(--search-snippet-border-radius); 1904 box-shadow: var(--search-snippet-shadow-lg); 1905 z-index: calc(var(--search-snippet-z-modal) + 1); 1906 display: flex; 1907 flex-direction: column; 1908 opacity: 0; 1909 visibility: hidden; 1910 transition: opacity var(--search-snippet-transition), 1911 visibility var(--search-snippet-transition), 1912 transform var(--search-snippet-transition); 1913} 1914 1915.modal-container.open { 1916 opacity: 1; 1917 visibility: visible; 1918 transform: translateX(-50%) scale(1); 1919} 1920 1921/* Modal header with search input */ 1922.modal-header { 1923 display: flex; 1924 align-items: center; 1925 gap: var(--search-snippet-spacing-sm); 1926 padding: var(--search-snippet-spacing-md); 1927 border-bottom: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1928} 1929 1930.modal-search-icon { 1931 width: var(--search-snippet-icon-size); 1932 height: var(--search-snippet-icon-size); 1933 color: var(--search-snippet-text-secondary); 1934 flex-shrink: 0; 1935} 1936 1937.modal-search-input { 1938 flex: 1; 1939 border: none; 1940 outline: none; 1941 background: transparent; 1942 color: var(--search-snippet-text-color); 1943 font-size: var(--search-snippet-font-size-lg); 1944 font-family: var(--search-snippet-font-family);
1945 font-weight: var(--search-snippet-font-weight-normal); 1946 padding: var(--search-snippet-spacing-xs) 0; 1947} 1948 1949.modal-search-input::placeholder { 1950 color: var(--search-snippet-text-secondary); 1951} 1952 1953.modal-loading-indicator { 1954 display: flex; 1955 align-items: center; 1956 justify-content: center; 1957 width: var(--search-snippet-icon-size); 1958 height: var(--search-snippet-icon-size); 1959 flex-shrink: 0; 1960 visibility: hidden; 1961} 1962 1963.modal-loading-indicator .loading { 1964 width: 16px; 1965 height: 16px; 1966} 1967 1968.modal-container.is-loading .modal-loading-indicator { 1969 visibility: visible; 1970} 1971 1972.modal-shortcut-hint { 1973 display: flex; 1974 align-items: center; 1975 gap: var(--search-snippet-spacing-xs); 1976 color: var(--search-snippet-text-secondary); 1977 font-size: var(--search-snippet-font-size-sm); 1978 flex-shrink: 0; 1979} 1980 1981.modal-kbd { 1982 display: inline-flex; 1983 align-items: center; 1984 justify-content: center; 1985 min-width: 24px; 1986 height: 22px; 1987 padding: 0 var(--search-snippet-spacing-xs); 1988 background: var(--search-snippet-surface); 1989 border: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 1990 border-radius: 4px; 1991 font-size: var(--search-snippet-font-size-sm); 1992 font-family: var(--search-snippet-font-family); 1993 color: var(--search-snippet-text-secondary); 1994} 1995 1996/* Modal content (results area) */ 1997.modal-content { 1998 flex: 1; 1999 overflow-y: auto; 2000 overflow-x: hidden; 2001 padding: var(--search-snippet-spacing-sm); 2002} 2003 2004.modal-content::-webkit-scrollbar {
2005 width: 8px; 2006} 2007 2008.modal-content::-webkit-scrollbar-track { 2009 background: var(--search-snippet-surface); 2010} 2011 2012.modal-content::-webkit-scrollbar-thumb { 2013 background: var(--search-snippet-border-color); 2014 border-radius: var(--search-snippet-border-radius); 2015} 2016 2017.modal-content::-webkit-scrollbar-thumb:hover { 2018 background: var(--search-snippet-text-secondary); 2019} 2020 2021/* Results list */ 2022.modal-results { 2023 display: flex; 2024 flex-direction: column; 2025 gap: var(--search-snippet-spacing-xs); 2026} 2027 2028.result-group { 2029 display: flex; 2030 flex-direction: column; 2031 gap: var(--search-snippet-spacing-xs); 2032} 2033 2034.result-group + .result-group { 2035 margin-top: var(--search-snippet-spacing-sm); 2036} 2037 2038.result-group-header { 2039 position: sticky; 2040 top: 0; 2041 z-index: 1; 2042 padding: var(--search-snippet-spacing-xs) var(--search-snippet-spacing-md); 2043 background: var(--search-snippet-surface); 2044 color: var(--search-snippet-text-secondary); 2045 font-size: var(--search-snippet-font-size-sm); 2046 font-weight: 600; 2047 text-transform: uppercase; 2048 letter-spacing: 0.05em; 2049} 2050 2051/* 2052 * Mask the scroll container's top padding while the header is pinned so 2053 * result items don't peek through as a sliver between the search input and 2054 * the (sticky) category header. The pseudo-element rides above the header, 2055 * painted with the modal background, covering the padding gap and giving a 2056 * clean cutoff for items scrolling underneath. 2057 */ 2058.result-group-header::before { 2059 content: ""; 2060 position: absolute; 2061 left: 0; 2062 right: 0; 2063 bottom: 100%; 2064 height: var(--search-snippet-spacing-sm); 2065 background: var(--search-snippet-background); 2066} 2067 2068.modal-result-row { 2069 position: relative; 2070 display: flex; 2071} 2072 2073 2074a.modal-result-item { 2075 flex: 1; 2076 min-width: 0; 2077 padding: var(--search-snippet-spacing-md); 2078 padding-right: calc( 2079 36px + var(--search-snippet-spacing-md) + var(--search-snippet-spacing-md) 2080 ); 2081 background: transparent; 2082 border: var(--search-snippet-border-width) solid transparent; 2083 border-radius: calc(var(--search-snippet-border-radius) - 4px); 2084 cursor: pointer; 2085 transition: var(--search-snippet-transition-fast); 2086 display: flex; 2087 flex-direction: row; 2088 align-items: flex-start; 2089 gap: var(--search-snippet-spacing-md); 2090 text-decoration: none; 2091 color: inherit; 2092} 2093
2094/* Image thumbnail container */ 2095.modal-result-image-container { 2096 flex-shrink: 0; 2097 width: 48px; 2098 height: 48px; 2099 border-radius: 6px; 2100 overflow: hidden; 2101 position: relative; 2102} 2103 2104.modal-result-image { 2105 width: 100%; 2106 height: 100%; 2107 object-fit: contain; 2108 opacity: 0; 2109 transition: opacity var(--search-snippet-transition); 2110} 2111 2112.modal-result-image.loaded { 2113 opacity: 1; 2114} 2115 2116/* Loading shimmer */ 2117.modal-result-image-loading { 2118 position: absolute; 2119 inset: 0; 2120 background: linear-gradient( 2121 90deg, 2122 var(--search-snippet-surface) 25%, 2123 var(--search-snippet-border-color) 50%, 2124 var(--search-snippet-surface) 75% 2125 ); 2126 background-size: 200% 100%; 2127 animation: modal-image-shimmer 1.5s infinite; 2128} 2129 2130@keyframes modal-image-shimmer { 2131 0% { background-position: 200% 0; } 2132 100% { background-position: -200% 0; } 2133} 2134 2135/* Placeholder icon */ 2136.modal-result-image-placeholder { 2137 position: absolute; 2138 inset: 0; 2139 display: flex; 2140 align-items: center; 2141 justify-content: center; 2142 color: var(--search-snippet-text-secondary); 2143 opacity: 0.5; 2144} 2145 2146.modal-result-image-placeholder svg { 2147 width: 20px; 2148 height: 20px; 2149} 2150 2151/* Content wrapper */ 2152.modal-result-content { 2153 flex: 1; 2154 min-width: 0; 2155 display: flex; 2156 flex-direction: column; 2157 gap: var(--search-snippet-spacing-xs); 2158} 2159 2160a.modal-result-item:hover, 2161a.modal-result-item.active { 2162 background: var(--search-snippet-hover-background); 2163 border-color: var(--search-snippet-border-color); 2164} 2165 2166a.modal-result-item.active { 2167 border-color: var(--search-snippet-primary-color); 2168 background: var(--search-snippet-focus-ring); 2169} 2170 2171a.modal-result-item:focus-visible { 2172 outline: 2px solid var(--search-snippet-primary-color); 2173 outline-offset: -2px; 2174} 2175 2176.modal-favorite-button { 2177 position: absolute; 2178 top: 50%; 2179 right: var(--search-snippet-spacing-md); 2180 z-index: 1; 2181 display: flex; 2182 align-items: center; 2183 justify-content: center; 2184 width: 36px; 2185 height: 36px; 2186 padding: 8px; 2187 transform: translateY(-50%); 2188 border: 0; 2189 border-radius: 50%; 2190 background: transparent; 2191 color: var(--search-snippet-text-secondary); 2192 cursor: pointer; 2193 transition: var(--search-snippet-transition-fast); 2194} 2195 2196.modal-favorite-button:hover, 2197.modal-favorite-button:focus-visible { 2198 background: var(--search-snippet-hover-background); 2199 color: var(--search-snippet-primary-color); 2200} 2201 2202.modal-favorite-button:focus-visible { 2203 outline: 2px solid var(--search-snippet-primary-color); 2204 outline-offset: -2px; 2205} 2206 2207.modal-favorite-button svg { 2208 width: 20px; 2209 height: 20px; 2210 fill: none; 2211 stroke: currentColor; 2212 stroke-linejoin: round; 2213 stroke-width: 1.75; 2214} 2215 2216.modal-favorite-button.favorite { 2217 color: var(--search-snippet-primary-color); 2218} 2219 2220.modal-favorite-button.favorite svg { 2221 fill: currentColor; 2222} 2223 2224.modal-result-title { 2225 font-size: var(--search-snippet-font-size-base); 2226 font-weight: var(--search-snippet-font-weight-medium); 2227 color: var(--search-snippet-text-color); 2228 display: -webkit-box; 2229 -webkit-line-clamp: 1; 2230 -webkit-box-orient: vertical; 2231 overflow: hidden; 2232} 2233 2234.modal-result-description { 2235 font-size: var(--search-snippet-font-size-sm); 2236 color: var(--search-snippet-text-description); 2237 line-height: 1.5; 2238 display: -webkit-box; 2239 -webkit-line-clamp: 2; 2240 -webkit-box-orient: vertical; 2241 overflow: hidden; 2242} 2243 2244.modal-result-metadata { 2245 display: flex; 2246 align-items: center; 2247 gap: var(--search-snippet-spacing-sm); 2248 min-width: 0; 2249} 2250 2251.modal-result-url { 2252 font-size: var(--search-snippet-font-size-sm); 2253 color: var(--search-snippet-primary-color); 2254 text-decoration: none; 2255 display: block; 2256 flex: 1; 2257 min-width: 0; 2258 overflow: hidden; 2259 text-overflow: ellipsis; 2260 white-space: nowrap; 2261} 2262 2263.modal-result-url-empty { 2264 visibility: hidden; 2265} 2266 2267.modal-result-date { 2268 font-size: 12px; 2269 font-weight: var(--search-snippet-font-weight-medium); 2270 color: var(--search-snippet-text-secondary); 2271 text-align: right; 2272 flex-shrink: 0; 2273} 2274 2275.modal-result-url:hover { 2276 text-decoration: underline; 2277} 2278 2279/* Initial modal sections */ 2280.modal-initial-section { 2281 display: flex; 2282 flex-direction: column; 2283 gap: var(--search-snippet-spacing-xs); 2284} 2285 2286.modal-initial-section + .modal-initial-section { 2287 margin-top: var(--search-snippet-spacing-md); 2288} 2289 2290.modal-initial-section-title { 2291 display: flex; 2292 align-items: center; 2293 gap: var(--search-snippet-spacing-xs); 2294 margin: 0; 2295 padding: var(--search-snippet-spacing-xs) var(--search-snippet-spacing-md); 2296 color: var(--search-snippet-text-secondary); 2297 font-size: var(--search-snippet-font-size-sm); 2298 font-weight: 600; 2299 text-transform: uppercase; 2300 letter-spacing: 0.05em; 2301} 2302 2303.modal-initial-section-title svg { 2304 width: 16px; 2305 height: 16px; 2306 fill: none; 2307 stroke: currentColor; 2308 stroke-linecap: round; 2309 stroke-linejoin: round; 2310 stroke-width: 1.75; 2311} 2312 2313/* Result group header */ 2314.modal-group-header { 2315 padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md); 2316 font-size: var(--search-snippet-font-size-sm);
2317 font-weight: var(--search-snippet-font-weight-medium); 2318 color: var(--search-snippet-text-secondary); 2319 text-transform: uppercase; 2320 letter-spacing: 0.05em; 2321} 2322 2323/* Loading state */ 2324.modal-loading { 2325 display: flex; 2326 flex-direction: column; 2327 align-items: center; 2328 justify-content: center; 2329 padding: var(--search-snippet-spacing-xxl); 2330 gap: var(--search-snippet-spacing-md); 2331 color: var(--search-snippet-text-secondary); 2332} 2333 2334/* Empty state */ 2335.modal-empty { 2336 display: flex; 2337 flex-direction: column; 2338 align-items: center; 2339 justify-content: center; 2340 padding: var(--search-snippet-spacing-xxl); 2341 gap: var(--search-snippet-spacing-md); 2342 color: var(--search-snippet-text-secondary); 2343 text-align: center; 2344} 2345 2346.modal-empty-icon { 2347 width: 48px; 2348 height: 48px; 2349 opacity: 0.5; 2350} 2351 2352.modal-empty-title { 2353 font-size: var(--search-snippet-font-size-base); 2354 font-weight: var(--search-snippet-font-weight-medium); 2355 color: var(--search-snippet-text-color); 2356} 2357 2358.modal-empty-description { 2359 font-size: var(--search-snippet-font-size-sm); 2360} 2361 2362/* Footer */ 2363.modal-footer { 2364 display: flex; 2365 align-items: center; 2366 justify-content: space-between; 2367 padding: var(--search-snippet-spacing-sm) var(--search-snippet-spacing-md); 2368 border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color); 2369 background: var(--search-snippet-surface); 2370 font-size: var(--search-snippet-font-size-sm); 2371 color: var(--search-snippet-text-secondary); 2372 border-radius: 0 0 var(--search-snippet-border-radius) var(--search-snippet-border-radius); 2373} 2374 2375.modal-footer-hints { 2376 display: flex; 2377 align-items: center; 2378 gap: var(--search-snippet-spacing-md); 2379} 2380 2381.modal-footer-hint { 2382 display: flex; 2383 align-items: center; 2384 gap: var(--search-snippet-spacing-xs); 2385} 2386 2387.modal-footer-hint .modal-kbd { 2388 min-width: 20px; 2389 height: 20px; 2390 font-size: 11px; 2391} 2392 2393/* Results count */ 2394.modal-results-count { 2395 font-size: var(--search-snippet-font-size-sm); 2396 color: var(--search-snippet-text-secondary); 2397} 2398 2399/* Powered by in modal footer */ 2400.modal-footer .powered-by-inline { 2401 font-size: var(--search-snippet-font-size-sm); 2402 color: var(--search-snippet-text-secondary); 2403} 2404 2405.modal-footer .powered-by-inline a { 2406 color: var(--search-snippet-text-secondary); 2407 text-decoration: none; 2408 transition: color var(--search-snippet-transition-fast); 2409} 2410 2411.modal-footer .powered-by-inline a:hover { 2412 color: var(--search-snippet-primary-color); 2413} 2414 2415/* See more link */ 2416.modal-see-more { 2417 display: flex; 2418 align-items: center; 2419 justify-content: center; 2420 gap: var(--search-snippet-spacing-xs); 2421 padding: var(--search-snippet-spacing-md); 2422 font-size: var(--search-snippet-font-size-sm); 2423 color: var(--search-snippet-primary-color); 2424 text-decoration: none; 2425 font-weight: var(--search-snippet-font-weight-medium); 2426 transition: background var(--search-snippet-transition-fast); 2427 padding-bottom: var(--search-snippet-spacing-xs); 2428} 2429 2430.modal-see-more:hover { 2431 background: var(--search-snippet-hover); 2432 text-decoration: underline; 2433} 2434 2435/* Responsive adjustments */ 2436@media (max-width: 640px) { 2437 .modal-container { 2438 top: 10%; 2439 width: 95%; 2440 max-height: 80vh; 2441 } 2442 2443 .modal-footer-hints { 2444 display: none; 2445 } 2446} 2447 2448/* Animation for modal open */ 2449@keyframes modal-slide-in { 2450 from { 2451 opacity: 0; 2452 transform: translateX(-50%) scale(0.95) translateY(-10px); 2453 } 2454 to { 2455 opacity: 1; 2456 transform: translateX(-50%) scale(1) translateY(0); 2457 } 2458} 2459 2460.modal-container.open { 2461 animation: modal-slide-in var(--search-snippet-transition) ease-out; 2462} 2463`,de="search-snippet:recent-results",P="search-snippet:favorite-results",Xe=5;function et(a){if(!a||typeof a!="object")return!1;const e=a;return e.type==="result"&&typeof e.id=="string"&&typeof e.title=="string"&&typeof e.description=="string"&&(e.url===void 0||typeof e.url=="string")&&(e.image===void 0||typeof e.image=="string")&&(e.timestamp===void 0||typeof e.timestamp=="number")&&(e.metadata===void 0||typeof e.metadata=="object"&&e.metadata!==null)}function k(a){return a.url||a.id}function R(a,e){const t=k(e);return a.some(s=>k(s)===t)}function M(a){try{const e=localStorage.getItem(a);if(!e)return[];const t=JSON.parse(e);return Array.isArray(t)?t.filter(et):[]}catch{return[]}}function tt(a,e=de,t=Xe){const s=k(a),i=M(e).filter(n=>k(n)!==s),r=[a,...i].slice(0,Math.max(0,t));try{localStorage.setItem(e,JSON.stringify(r))}catch{}return r}function st(a,e=P){const t=M(e),s=R(t,a)?t.filter(i=>k(i)!==k(a)):[a,...t];try{localStorage.setItem(e,JSON.stringify(s))}catch{}return s}const pe="search-modal-snippet",ue=10,ge=50;class me extends HTMLElement{constructor(){super(),o(this,"shadow"),o(this,"client",null),o(this,"stats",null),o(this,"backdrop",null),o(this,"modal",null),o(this,"inputElement",null),o(this,"resultsContainer",null),o(this,"footerCount",null),o(this,"isOpen",!1),o(this,"results",[]),o(this,"favoriteResults",[]),o(this,"activeIndex",-1),o(this,"debouncedSearch",null),o(this,"currentSearchController",null),o(this,"loadingMessageInterval",null),o(this,"loadingMessageIndex",0),o(this,"translationsOverride",null),o(this,"resolvedTranslations",g(null)),o(this,"lastSearchQuery",""),o(this,"lastSearchTotal",0),o(this,"handleGlobalKeydown",null),o(this,"handleInputChange",null),o(this,"handleInputKeydown",null),o(this,"handleBackdropClick",null),o(this,"handleResultsContainerClick",null),o(this,"savedBodyStyles",null),o(this,"savedHtmlOverflow",null),this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["api-url","placeholder","max-results","max-render-results","theme","shortcut","use-meta-key","debounce-ms","hide-branding","show-url","show-date","hide-thumbnails","see-more","disable-analytics","request-options","translations"]}connectedCallback(){this.syncTranslationsFromAttribute(),this.initializeClient(),this.render(),this.attachGlobalKeyboardShortcut(),this.dispatchEvent(f("ready",void 0))}disconnectedCallback(){this.cleanup()}attributeChangedCallback(e,t,s){t!==s&&(e==="api-url"||e==="disable-analytics"?this.initializeClient():e==="theme"?this.updateTheme(s):e==="translations"&&(this.syncTranslationsFromAttribute(),this.isConnected&&this.rerender()))}get translations(){return this.translationsOverride}set translations(e){this.translationsOverride=e??null,this.resolvedTranslations=g(this.translationsOverride),this.isConnected&&this.rerender()}rerender(){const e=this.isOpen,t=this.inputElement?.value??"";this.isOpen=!1,this.render(),e&&(this.isOpen=!0,this.backdrop?.classList.add("open"),this.modal?.classList.add("open"),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.inputElement?.focus()})})),t&&this.inputElement&&(this.inputElement.value=t,t.trim().length>0&&this.performSearch(t.trim()))}syncTranslationsFromAttribute(){if(this.translationsOverride){this.resolvedTranslations=g(this.translationsOverride);return}const e=T(this.getAttribute("translations"),"SearchModalSnippet");this.resolvedTranslations=g(e)}getProps(){const e=this.resolvedTranslations;return{apiUrl:m(this.getAttribute("api-url"),""),placeholder:m(this.getAttribute("placeholder"),e.placeholder),maxResults:x(this.getAttribute("max-results"),ge),maxRenderResults:x(this.getAttribute("max-render-results"),ue),debounceMs:x(this.getAttribute("debounce-ms"),300),theme:m(this.getAttribute("theme"),"auto"),shortcut:m(this.getAttribute("shortcut"),"k"),useMetaKey:this.getAttribute("use-meta-key")!=="false",hideBranding:b(this.getAttribute("hide-branding"),!1),showUrl:b(this.getAttribute("show-url"),!1),showDate:b(this.getAttribute("show-date"),!1),hideThumbnails:b(this.getAttribute("hide-thumbnails"),!1),seeMore:m(this.getAttribute("see-more"),""),groupBy:m(this.getAttribute("group-by"),""),disableAnalytics:b(this.getAttribute("disable-analytics"),!1),translations:this.translationsOverride??void 0}}getRequestOptions(){const e=this.getAttribute("request-options");
2463if(e)try{const t=JSON.parse(e);if(t===null||typeof t!="object"||Array.isArray(t))throw new Error("request-options must be a JSON object");return t}catch{return}}initializeClient(){const e=this.getProps();if(!e.apiUrl){this.client=null,this.destroyStatsClient(),this.showMissingApiUrlError();return}try{this.client=A(e.apiUrl),this.destroyStatsClient(),e.disableAnalytics||(this.stats=new te(e.apiUrl))}catch{}}destroyStatsClient(){this.stats&&(this.stats.destroy(),this.stats=null)}render(){const e=this.getProps(),t=this.resolvedTranslations,s=l=>this.performSearch(l);this.debouncedSearch=F(s,e.debounceMs||300);const i=document.createElement("style");i.textContent=`${z} 2464${We}`;const r=e.hideBranding?"":`<div class="powered-by-inline">${I}</div>`,n=document.createElement("div");n.innerHTML=` 2465 <div class="modal-backdrop" role="presentation"></div> 2466 <div class="modal-container" role="dialog" aria-modal="true" aria-labelledby="modal-title"> 2467 <div class="modal-header"> 2468 <svg class="modal-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"> 2469 <path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/> 2470 </svg> 2471 <input 2472 type="text" 2473 class="modal-search-input" 2474 placeholder="${c(e.placeholder||t.placeholder)}" 2475 aria-label="${c(t.searchButtonLabel)}" 2476 aria-autocomplete="list" 2477 aria-controls="modal-results-list" 2478 aria-expanded="false" 2479 autocomplete="off" 2480 spellcheck="false" 2481 /> 2482 <span class="modal-loading-indicator" role="status" aria-label="${c(t.loadingAriaLabel)}"> 2483 <span class="loading" aria-hidden="true"></span> 2484 </span> 2485 </div> 2486 <div class="modal-content"> 2487 <div class="modal-results" id="modal-results-list" role="listbox" aria-label="${c(t.searchResultsAriaLabel)}"></div> 2488 </div> 2489 <div class="modal-footer"> 2490 <div class="modal-footer-hints"> 2491 <div class="modal-footer-hint"> 2492 <kbd class="modal-kbd">\u2191</kbd> 2493 <kbd class="modal-kbd">\u2193</kbd> 2494 <span>${c(t.navigateHint)}</span> 2495 </div> 2496 <div class="modal-footer-hint"> 2497 <kbd class="modal-kbd">\u21B5</kbd> 2498 <span>${c(t.selectHint)}</span> 2499 </div> 2500 <div class="modal-footer-hint"> 2501 <kbd class="modal-kbd">Esc</kbd> 2502 <span>${c(t.closeHint)}</span> 2503 </div> 2504 </div> 2505 ${r} 2506 </div> 2507 </div> 2508 `,this.shadow.innerHTML="",this.shadow.appendChild(i),this.shadow.appendChild(n),this.backdrop=this.shadow.querySelector(".modal-backdrop"),this.modal=this.shadow.querySelector(".modal-container"),this.inputElement=this.shadow.querySelector(".modal-search-input"),this.resultsContainer=this.shadow.querySelector(".modal-results"),this.footerCount=this.shadow.querySelector(".modal-results-count"),this.attachEventListeners(),this.client?this.showEmptyState():this.showMissingApiUrlError()}attachGlobalKeyboardShortcut(){const e=this.getProps(),t=e.shortcut?.toLowerCase()||"k";this.handleGlobalKeydown=s=>{(e.useMetaKey&&s.metaKey||s.ctrlKey)&&s.key.toLowerCase()===t&&!this.isOpen&&(s.preventDefault(),this.open())},document.addEventListener("keydown",this.handleGlobalKeydown)}attachEventListeners(){!this.inputElement||!this.backdrop||(this.handleInputChange=e=>{const t=e.target.value.trim();t.length>0&&this.debouncedSearch?this.debouncedSearch(t):(this.debouncedSearch?.cancel(),this.currentSearchController?.abort(),this.results=[],this.activeIndex=-1,this.showEmptyState())},this.inputElement.addEventListener("input",this.handleInputChange),this.handleInputKeydown=e=>{switch(e.key){case"ArrowDown":e.preventDefault(),this.navigateResults(1);break;case"ArrowUp":e.preventDefault(),this.navigateResults(-1);break;case"Enter":e.preventDefault(),this.selectActiveResult();break;case"Escape":e.preventDefault(),this.close();break}},this.inputElement.addEventListener("keydown",this.handleInputKeydown),this.handleBackdropClick=e=>{e.target===this.backdrop&&this.close()},this.backdrop.addEventListener("click",this.handleBackdropClick))}navigateResults(e){if(this.results.length===0)return;const t=this.activeIndex+e;t<0?this.activeIndex=this.results.length-1:t>=this.results.length?this.activeIndex=0:this.activeIndex=t,this.updateActiveResult()}updateActiveResult(){const e=this.resultsContainer?.querySelectorAll(".modal-result-item");e&&(e.forEach((t,s)=>{s===this.activeIndex?(t.classList.add("active"),t.setAttribute("aria-selected","true"),t.scrollIntoView({block:"nearest"})):(t.classList.remove("active"),t.setAttribute("aria-selected","false"))}),this.inputElement&&this.activeIndex>=0?this.inputElement.setAttribute("aria-activedescendant",`result-${this.activeIndex}`):this.inputElement&&this.inputElement.removeAttribute("aria-activedescendant"))}
2508selectActiveResult(){if(this.currentSearchController)return;if(this.activeIndex<0||this.activeIndex>=this.results.length){const s=this.inputElement?.value.trim();s&&s.length>0&&this.performSearch(s);return}const e=this.results[this.activeIndex];this.dispatchEvent(f("result-select",{result:e,index:this.activeIndex}));const t=this.resultsContainer?.querySelector(`.modal-result-item[data-index="${this.activeIndex}"]`);t&&$(e.url)&&t.click(),this.close()}async performSearch(e){if(!this.client){this.showMissingApiUrlError();return}this.currentSearchController&&(this.currentSearchController.abort(),this.currentSearchController=null);const t=new AbortController;this.currentSearchController=t,this.showLoadingState();try{const s=this.getProps(),i=await this.client.search(e,{signal:t.signal,maxResults:s.maxResults||ge,request:this.getRequestOptions()});if(t.signal.aborted||this.currentSearchController!==t)return;const r=i.slice(0,s.maxRenderResults||ue);this.lastSearchQuery=e,this.lastSearchTotal=i.length,this.stats?.trackSearch(e,i.length),this.displayResults(r,e,i.length)}catch(s){if(s.name==="AbortError"||t.signal.aborted||this.currentSearchController!==t)return;this.showErrorState(s.message)}finally{this.currentSearchController===t&&(this.currentSearchController=null)}}displayResults(e,t,s=e.length){const i=this.getProps(),r=this.resolvedTranslations,n=i.groupBy?Z(e,i.groupBy,r.groupOther):null;if(this.results=n?n.flatMap(p=>p.results):e,this.favoriteResults=M(P),this.activeIndex=this.results.length>0?0:-1,this.clearLoadingInterval(),this.setLoadingIndicator(!1),!this.resultsContainer)return;if(this.results.length===0){this.showNoResultsState(t);return}const l=n?W(n,(p,v)=>this.renderResult(p,v)):this.results.map((p,v)=>this.renderResult(p,v)).join(""),h=s>e.length,d=h?y(r.resultsCountOverflow,{n:e.length,total:s}):y(s===1?r.modalResultsCount:r.modalResultsCountPlural,{n:s}),u=i.seeMore&&h?`<a href="${c(i.seeMore+encodeURIComponent(t))}" class="modal-see-more"> 2509 <span>${c(r.seeMoreResults)}</span> 2510 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> 2511 </a>`:"";this.resultsContainer.innerHTML=l+u,this.footerCount&&(this.footerCount.textContent=d),this.inputElement&&this.inputElement.setAttribute("aria-expanded","true"),this.attachResultHandlers(),this.updateActiveResult()}renderResult(e,t){const s=this.getProps(),i=Y(e.metadata?.icon),r=s.hideThumbnails?"":this.renderResultImage(e.image,e.title),n=$(e.url),l=n?c(n):"#",h=n?c(K(n)):"",d=s.showDate&&e.timestamp!==void 0?`<div class="modal-result-date">${c(Q(e.timestamp))}</div>`:"",u=s.showUrl&&n||d?`<div class="modal-result-metadata"> 2512 ${s.showUrl&&n?`<span class="modal-result-url">${h}</span>`:'<span class="modal-result-url modal-result-url-empty"></span>'} 2513 ${d} 2514 </div>`:"",p=R(this.favoriteResults,e),v=p?this.resolvedTranslations.removeFavorite:this.resolvedTranslations.addFavorite;return` 2515 <div class="modal-result-row"> 2516 <a 2517 href="${l}" 2518 class="modal-result-item${t===this.activeIndex?" active":""}" 2519 role="option" 2520 id="result-${t}" 2521 aria-selected="${t===this.activeIndex}" 2522 tabindex="-1" 2523 data-index="${t}" 2524 data-result-id="${c(e.id||"")}" 2525 data-url="${c(n)}" 2526 > 2527 ${i} 2528 ${r} 2529 <div class="modal-result-content"> 2530 <div class="modal-result-title">${c(e.title||"")}</div> 2531 ${e.description?`<div class="modal-result-description">${c(e.description)}</div>`:""} 2532 ${u} 2533 </div> 2534 </a> 2535 <button 2536 type="button" 2537 class="modal-favorite-button${p?" favorite":""}" 2538 data-favorite-index="${t}" 2539 aria-label="${c(v)}" 2540 title="${c(v)}" 2541 aria-pressed="${p}" 2542 > 2543 <svg viewBox="0 0 24 24" aria-hidden="true"> 2544 <path d="m12 2.7 2.8 5.7 6.2.9-4.5 4.4 1.1 6.2-5.6-3-5.6 3 1.1-6.2L3 9.3l6.2-.9L12 2.7Z"></path> 2545 </svg> 2546 </button> 2547 </div> 2548 `}renderResultImage(e,t){const s='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>';return e?` 2549 <div class="modal-result-image-container"> 2550 <div class="modal-result-image-loading"></div> 2551 <div class="modal-result-image-placeholder" style="display: none;">${s}</div> 2552 <img 2553 class="modal-result-image" 2554 src="${c(e)}" 2555 alt="${c(t)}" 2556 loading="lazy" 2557 /> 2558 </div> 2559 `:` 2560 <div class="modal-result-image-container"> 2561 <div class="modal-result-image-placeholder">${s}</div> 2562 </div> 2563 `}attachResultHandlers(){this.detachResultsContainerClick();const e=this.resultsContainer;e&&(this.handleResultsContainerClick=t=>{const s=t.target;if(!s)return;const i=s.closest(".modal-favorite-button");if(i){const n=Number.parseInt(i.dataset.favoriteIndex??"",10),l=this.results[n];if(!Number.isNaN(n)&&l)if(this.favoriteResults=st(l),this.inputElement?.value.trim()){const h=R(this.favoriteResults,l),d=h?this.resolvedTranslations.removeFavorite:this.resolvedTranslations.addFavorite;i.classList.toggle("favorite",h),i.setAttribute("aria-pressed",String(h)),i.setAttribute("aria-label",d),i.title=d}else this.showEmptyState();return}const r=s.closest(".modal-result-item");if(r){r.getAttribute("href")==="#"&&t.preventDefault();const n=r.getAttribute("data-index"),l=r.getAttribute("data-result-id")??"",h=n!==null?Number.parseInt(n,10):Number.NaN;if(!Number.isNaN(h)){const d=this.results[h];d&&tt(d),l&&this.stats?.trackClick(this.lastSearchQuery,this.lastSearchTotal,l,h)}return}s.closest(".modal-see-more")&&this.stats?.trackViewMore(this.lastSearchQuery,this.lastSearchTotal)},e.addEventListener("click",this.handleResultsContainerClick),e.querySelectorAll(".modal-result-item").forEach((t,s)=>{t.addEventListener("mouseenter",()=>{this.activeIndex=s,this.updateActiveResult()})}),e.querySelectorAll(".modal-result-image").forEach(t=>{t.addEventListener("load",()=>{t.classList.add("loaded"),t.closest(".modal-result-image-container")?.querySelector(".modal-result-image-loading")?.remove()}),t.addEventListener("error",()=>{const s=t.closest(".modal-result-image-container");s?.querySelector(".modal-result-image-loading")?.remove();const i=s?.querySelector(".modal-result-image-placeholder");i&&(i.style.display="flex"),t.style.display="none"})}))}detachResultsContainerClick(){this.resultsContainer&&this.handleResultsContainerClick&&this.resultsContainer.removeEventListener("click",this.handleResultsContainerClick),this.handleResultsContainerClick=null}renderEmptyState(){const e=this.resolvedTranslations;return` 2564 <div class="modal-empty">
2565 <svg class="modal-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 2566 <circle cx="11" cy="11" r="8"></circle> 2567 <path d="m21 21-4.35-4.35"></path> 2568 </svg> 2569 <div class="modal-empty-description">${c(e.modalEmptyStateDescription)}</div> 2570 </div> 2571 `}renderInitialSection(e,t,s,i,r){return e.length===0?"":` 2572 <section class="modal-initial-section" aria-labelledby="${s}"> 2573 <h2 class="modal-initial-section-title" id="${s}"> 2574 ${r==="favorite"?`<svg viewBox="0 0 24 24" aria-hidden="true"> 2575 <path d="m12 2.7 2.8 5.7 6.2.9-4.5 4.4 1.1 6.2-5.6-3-5.6 3 1.1-6.2L3 9.3l6.2-.9L12 2.7Z"></path> 2576 </svg>`:`<svg viewBox="0 0 24 24" aria-hidden="true"> 2577 <path d="M3 12a9 9 0 1 0 3-6.7L3 8"></path> 2578 <path d="M3 3v5h5"></path> 2579 <path d="M12 7v5l4 2"></path> 2580 </svg>`} 2581 <span>${c(t)}</span> 2582 </h2> 2583 ${e.map((n,l)=>this.renderResult(n,i+l)).join("")} 2584 </section> 2585 `}showEmptyState(){if(this.clearLoadingInterval(),this.setLoadingIndicator(!1),!this.resultsContainer)return;this.favoriteResults=M(P);const e=M(de).filter(t=>!R(this.favoriteResults,t));this.results=[...this.favoriteResults,...e],this.activeIndex=this.results.length>0?0:-1,this.resultsContainer.innerHTML=this.results.length>0?`${this.renderInitialSection(this.favoriteResults,this.resolvedTranslations.favoriteResults,"modal-favorite-results-title",0,"favorite")}${this.renderInitialSection(e,this.resolvedTranslations.recentResults,"modal-recent-results-title",this.favoriteResults.length,"recent")}`:this.renderEmptyState(),this.attachResultHandlers(),this.updateActiveResult(),this.footerCount&&(this.footerCount.textContent=""),this.inputElement&&this.inputElement.setAttribute("aria-expanded",String(this.results.length>0))}showLoadingState(){if(!this.resultsContainer)return;this.clearLoadingInterval(),this.setLoadingIndicator(!0);const e=this.resolvedTranslations.loadingMessages;this.loadingMessageIndex=Math.floor(Math.random()*e.length),this.resultsContainer.querySelector(".modal-result-item")||(this.resultsContainer.innerHTML=` 2586 <div class="modal-loading"> 2587 <div class="loading-text loading-text-animate">${c(e[this.loadingMessageIndex])}</div> 2588 </div> 2589 `),this.footerCount&&(this.footerCount.textContent=e[this.loadingMessageIndex]),this.startLoadingInterval()}setLoadingIndicator(e){this.modal?.classList.toggle("is-loading",e),this.inputElement?.setAttribute("aria-busy",String(e)),this.resultsContainer?.setAttribute("aria-busy",String(e))}startLoadingInterval(){this.loadingMessageInterval=setInterval(()=>{const e=this.resolvedTranslations.loadingMessages;this.loadingMessageIndex=(this.loadingMessageIndex+1)%e.length;const t=this.resultsContainer?.querySelector(".loading-text");t&&(t.classList.remove("loading-text-animate"),t.textContent=e[this.loadingMessageIndex],t.classList.add("loading-text-animate")),this.footerCount&&(this.footerCount.textContent=e[this.loadingMessageIndex])},H)}clearLoadingInterval(){this.loadingMessageInterval&&(clearInterval(this.loadingMessageInterval),this.loadingMessageInterval=null)}showNoResultsState(e){if(this.clearLoadingInterval(),this.setLoadingIndicator(!1),!this.resultsContainer)return;const t=this.resolvedTranslations;this.resultsContainer.innerHTML=` 2590 <div class="modal-empty"> 2591 <svg class="modal-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 2592 <circle cx="11" cy="11" r="8"></circle> 2593 <line x1="21" y1="21" x2="16.65" y2="16.65"></line> 2594 </svg> 2595 <div class="modal-empty-title">${c(t.modalNoResultsTitle)}</div> 2596 <div class="modal-empty-description">${c(y(t.modalNoResultsDescription,{query:e}))}</div> 2597 </div> 2598 `,this.footerCount&&(this.footerCount.textContent=t.modalResultsCountZero),this.inputElement&&this.inputElement.setAttribute("aria-expanded","false")}showErrorState(e){if(this.clearLoadingInterval(),this.setLoadingIndicator(!1),!this.resultsContainer)return;const t=this.resolvedTranslations;this.resultsContainer.innerHTML=` 2599 <div class="error"> 2600 <strong>${c(t.errorPrefix)}</strong> ${c(e)} 2601 </div> 2602 `,this.footerCount&&(this.footerCount.textContent=t.modalResultsCountError)}showMissingApiUrlError(){this.resultsContainer&&this.showErrorState(this.resolvedTranslations.missingApiUrlError)}updateTheme(e){const t=e==="light"||e==="dark"||e==="auto"?e:"auto";t==="auto"?this.removeAttribute("theme"):this.setAttribute("theme",t)}lockBodyScroll(){const e=window.scrollY;this.savedBodyStyles={overflow:document.body.style.overflow,position:document.body.style.position,top:document.body.style.top,width:document.body.style.width,scrollbarGutter:document.body.style.scrollbarGutter},this.savedHtmlOverflow=document.documentElement.style.overflow,document.body.style.scrollbarGutter="stable",document.documentElement.style.overflow="hidden",document.body.style.overflow="hidden",document.body.style.position="fixed",document.body.style.top=`-${e}px`,document.body.style.width="100%"}unlockBodyScroll(){if(!this.savedBodyStyles)return;const e=Math.abs(Number.parseInt(document.body.style.top||"0",10));document.documentElement.style.overflow=this.savedHtmlOverflow||"",document.body.style.overflow=this.savedBodyStyles.overflow,document.body.style.position=this.savedBodyStyles.position,document.body.style.top=this.savedBodyStyles.top,document.body.style.width=this.savedBodyStyles.width,document.body.style.scrollbarGutter=this.savedBodyStyles.scrollbarGutter||"",window.scrollTo(0,e),this.savedBodyStyles=null,this.savedHtmlOverflow=null}cleanup(){this.clearLoadingInterval(),this.currentSearchController&&(this.currentSearchController.abort(),this.currentSearchController=null),this.handleGlobalKeydown&&(document.removeEventListener("keydown",this.handleGlobalKeydown),this.handleGlobalKeydown=null),this.inputElement&&(this.handleInputChange&&this.inputElement.removeEventListener("input",this.handleInputChange),this.handleInputKeydown&&this.inputElement.removeEventListener("keydown",this.handleInputKeydown)),this.backdrop&&this.handleBackdropClick&&this.backdrop.removeEventListener("click",this.handleBackdropClick),this.detachResultsContainerClick(),this.handleInputChange=null,this.handleInputKeydown=null,this.handleBackdropClick=null,this.destroyStatsClient(),this.client&&this.client.cancelAllRequests()}open(){this.isOpen||(this.isOpen=!0,this.backdrop?.classList.add("open"),this.modal?.classList.add("open"),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.inputElement?.focus()})}),this.lockBodyScroll(),this.dispatchEvent(f("open",void 0)))}close(){this.isOpen&&(this.debouncedSearch?.cancel(),this.currentSearchController?.abort(),this.currentSearchController=null,this.isOpen=!1,this.backdrop?.classList.remove("open"),this.modal?.classList.remove("open"),this.inputElement&&(this.inputElement.value=""),this.results=[],this.activeIndex=-1,this.showEmptyState(),this.unlockBodyScroll(),this.dispatchEvent(f("close",void 0)))}toggle(){this.isOpen?this.close():this.open()}async search(e){this.isOpen||this.open(),this.inputElement&&(this.inputElement.value=e),await this.performSearch(e)}getResults(){return[...this.results]}isModalOpen(){return this.isOpen}}customElements.get(pe)||customElements.define(pe,me);function ve(){const a=window.localStorage;if(!(!a||a._isTanaPatched))try{const e=a.getItem?.bind(a),t=a.setItem?.bind(a),s=a.removeItem?.bind(a);if(!e||!t||!s)return;a.getItem=function(i){if(i==="chat-page-sessions"){const r=L("en").toLowerCase();return e(`${i}_${r}`)}return e(i)},a.setItem=function(i,r){if(i==="chat-page-sessions"){const n=L("en").toLowerCase();return t(`${i}_${n}`,r)}return t(i,r)},a.removeItem=function(i){if(i==="chat-page-sessions"){const r=L("en").toLowerCase();return s(`${i}_${r}`)}return s(i)},a._isTanaPatched=!0}catch{}}function be(){}function fe(a){const e=()=>{if(!a.shadowRoot||a.shadowRoot.querySelector("#tana-cf-brand-style"))return;const s=document.createElement("style");s.id="tana-cf-brand-style",s.textContent=` 2603 :host { 2604 --search-snippet-primary-color: var(--brand-color, #10b981) !important; 2605 --search-snippet-primary-hover: var(--brand-color, #10b981) !important; 2606 --search-snippet-accent: var(--brand-color, #10b981) !important; 2607 --search-snippet-accent-color: var(--brand-color, #10b981) !important; 2608 --search-snippet-border-radius: 12px !important; 2609 --search-snippet-hover-border-color: var(--brand-color, #10b981) !important; 2610 --search-snippet-border-hover: var(--brand-color, #10b981) !important; 2611 --search-snippet-item-hover-border-color: var(--brand-color, #10b981) !important; 2612 --search-snippet-focus-border-color: var(--brand-color, #10b981) !important; 2613 --search-snippet-focus-ring-color: var(--brand-color, #10b981) !important; 2614 --search-snippet-ring-color: var(--brand-color, #10b981) !important; 2615 } 2616 a:hover, 2617 button:hover, 2618 [role="option"]:hover, 2619 [role="option"][aria-selected="true"], 2620 .result-item:hover, 2621 .search-result:hover, 2622 li:hover, 2623 [class*="result"]:hover, 2624 [class*="card"]:hover, 2625 [class*="item"]:hover { 2626 border-color: var(--brand-color, #10b981) !important; 2627 } 2628 a:focus-visible, 2629 button:focus-visible, 2630 [role="option"]:focus-visible, 2631 input:focus, 2632 textarea:focus { 2633 border-color: var(--brand-color, #10b981) !important; 2634 outline-color: var(--brand-color, #10b981) !important; 2635 } 2636 /* --- 1-Click Message Copy Button --- */ 2637 .tana-cf-copy-btn { 2638 display: inline-flex; 2639 align-items: center; 2640 gap: 3px; 2641 padding: 1px 6px; 2642 margin-left: 4px; 2643 font-size: 11px; 2644 line-height: 1.2; 2645 font-weight: 500; 2646 color: var(--search-snippet-muted-text, #71717a); 2647 background: transparent; 2648 border: 1px solid rgba(120, 120, 120, 0.2); 2649 border-radius: 9999px; 2650 cursor: pointer; 2651 transition: color 150ms ease-out, border-color 150ms ease-out, background-color 150ms ease-out; 2652 vertical-align: middle; 2653 } 2654 .tana-cf-copy-btn:hover { 2655 color: var(--brand-color, #10b981) !important; 2656 border-color: var(--brand-color, #10b981) !important; 2657 background: rgba(16, 185, 129, 0.08) !important; 2658 } 2659 .tana-cf-copy-btn.is-copied { 2660 color: #10b981 !important; 2661 border-color: #10b981 !important; 2662 } 2663 .tana-cf-copy-btn svg { 2664 width: 11px; 2665 height: 11px; 2666 flex-shrink: 0; 2667 pointer-events: none; 2668 } 2669 `,a.shadowRoot.appendChild(s)},t=()=>{if(!a.shadowRoot)return;const s=a.shadowRoot.querySelectorAll(".chat-message-assistant");if(!s.length)return;const i=L("en").toLowerCase().startsWith("vi"),r=i?"Sao ch\xE9p":"Copy",n=i?"\u0110\xE3 sao ch\xE9p":"Copied",l=U("copy"),h=U("check");
2669s.forEach(d=>{if(d.querySelector(".chat-streaming"))return;const u=d.querySelector(".chat-message-metadata");if(!u||u.querySelector(".tana-cf-copy-btn"))return;const p=document.createElement("button");p.type="button",p.className="tana-cf-copy-btn",p.setAttribute("aria-label",r),p.title=r,p.innerHTML=` 2670 <svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><use href="${l}"></use></svg> 2671 <span>${r}</span> 2672 `,p.addEventListener("click",async v=>{v.stopPropagation();const B=d.querySelector(".chat-message-text");if(!B)return;let C=Le(B).replace(/\r\n/g,` 2673`).replace(/^\s*$/gm,"").replace(/\n{3,}/g,` 2674 2675`).trim();if(C||(C=B.innerText.trim()),!!C)try{if(navigator.clipboard&&typeof navigator.clipboard.writeText=="function")await navigator.clipboard.writeText(C);else{const w=document.createElement("textarea");w.value=C,w.style.position="fixed",w.style.opacity="0",document.body.appendChild(w),w.select(),document.execCommand("copy"),w.remove()}p.classList.add("is-copied"),p.innerHTML=` 2676 <svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><use href="${h}"></use></svg> 2677 <span>${n}</span> 2678 `,Me(n),setTimeout(()=>{p.classList.remove("is-copied"),p.innerHTML=` 2679 <svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><use href="${l}"></use></svg> 2680 <span>${r}</span> 2681 `},2e3)}catch{}}),u.appendChild(p)})};e(),t();try{new MutationObserver(()=>{e(),t()}).observe(a.shadowRoot||a,{childList:!0,subtree:!0})}catch{}}typeof window<"u"&&(window.Tana=Object.assign(window.Tana||{},{_cfSearchModalSnippet:me,_cfChatPageSnippet:oe,unpatchLocalStorage:be}));function q(){const a=j(),e=Ce(),t=!a&&!e,s=e?0:a?280:400,i=a?V.mobileDecel:V.brand;return{mobile:a,reduceMotion:e,useBlur:t,durationMs:s,easing:i}}function ye(a){const e=document.getElementById("js-cf-translations");if(e?.textContent){const r=e.textContent.trim();if(r)try{const n=JSON.parse(r);return{raw:r,dict:n}}catch{return{raw:r,dict:{}}}}const t=a.dataset;if(!t.tChatTitle&&!t.tSearchPlaceholder)return null;const s=[t.tLoading1,t.tLoading2,t.tLoading3,t.tLoading4].filter(Boolean),i={chatTitle:t.tChatTitle,chatPlaceholder:t.tChatPlaceholder,chatEmptyTitle:t.tChatEmptyTitle,chatEmptyDescription:t.tChatEmptyDesc,sendButtonLabel:t.tSend,newChatButton:t.tNewChat,clearChatButton:t.tClearChat,historyTitle:t.tHistory,noChatsYet:t.tNoChats,placeholder:t.tSearchPlaceholder,emptyStateTitle:t.tEmptyTitle,emptyStateDescription:t.tEmptyDesc,modalEmptyStateDescription:t.tEmptyDesc,noResultsTitle:t.tNoResultsTitle,modalNoResultsTitle:t.tNoResultsTitle,favoriteResults:t.tFavorites,recentResults:t.tRecent,addFavorite:t.tAddFav,removeFavorite:t.tRemoveFav,navigateHint:t.tNavHint,selectHint:t.tSelectHint,closeHint:t.tCloseHint,...s.length>0?{loadingMessages:s}:{}};
2681return Object.keys(i).forEach(r=>{(i[r]==null||i[r]==="")&&delete i[r]}),Object.keys(i).length>0?{raw:JSON.stringify(i),dict:i}:null}function N(a,e){if(!e||!a)return;const t=()=>{try{const s=a.shadowRoot;if(!s)return;const i=s.querySelector('textarea, input[type="text"]');if(!i)return;const r=Object.getOwnPropertyDescriptor(i instanceof HTMLTextAreaElement?window.HTMLTextAreaElement.prototype:window.HTMLInputElement.prototype,"value")?.set;r?r.call(i,e):i.value=e,i.dispatchEvent(new Event("input",{bubbles:!0})),i.focus(),typeof i.setSelectionRange=="function"&&i.setSelectionRange(i.value.length,i.value.length)}catch{}};t(),window.setTimeout(t,150),window.setTimeout(t,400)}class we extends HTMLElement{backdrop=null;drawer=null;clickHandler;keydownHandler;themeHandler;chatOpen=!1;animCleanupTimer=null;mountTimer=null;pendingMount=null;pendingPrefill=null;connectedCallback(){this.clickHandler=this.handleClick.bind(this),this.keydownHandler=this.handleKeydown.bind(this),this.themeHandler=this.updateThemes.bind(this),document.addEventListener("click",this.clickHandler),document.addEventListener("keydown",this.keydownHandler),window.addEventListener("theme-changed",this.themeHandler)}disconnectedCallback(){document.removeEventListener("click",this.clickHandler),document.removeEventListener("keydown",this.keydownHandler),window.removeEventListener("theme-changed",this.themeHandler),this.clearAnimCleanup(),this.clearMountTimer()}clearAnimCleanup(){this.animCleanupTimer!=null&&(window.clearTimeout(this.animCleanupTimer),this.animCleanupTimer=null)}clearMountTimer(){this.mountTimer!=null&&(window.clearTimeout(this.mountTimer),this.mountTimer=null)}getActiveTheme(){return ke()?D.DARK:D.LIGHT}updateThemes(){const e=this.getActiveTheme();this.querySelectorAll("search-modal-snippet, chat-page-snippet").forEach(t=>{t.setAttribute("theme",e)})}handleClick(e){const t=e.target,s=t.closest(".js-cloudflare-search-trigger"),i=t.closest(".js-cloudflare-chat-trigger");s?(e.preventDefault(),this.openSearch(s)):i&&(e.preventDefault(),this.openChat(i))}handleKeydown(e){e.key==="Escape"&&this.chatOpen&&this.closeChat()}openSearch(e){const t=e.getAttribute("data-search-endpoint-url");if(!t)return;let s=this.querySelector("search-modal-snippet");if(!s){const i=new URL(t).origin,r=e.getAttribute("data-placeholder")||"Search posts, tags, authors...";s=document.createElement("search-modal-snippet"),s.setAttribute("api-url",i),s.setAttribute("placeholder",r),s.setAttribute("theme",this.getActiveTheme()),s.setAttribute("hide-branding","true"),s.setAttribute("max-render-results","8"),s.setAttribute("max-results","20");const n=ye(this);n&&(s.setAttribute("translations",n.raw),s.translations=n.dict),fe(s),this.appendChild(s)}this.updateThemes(),setTimeout(()=>{s&&typeof s.open=="function"&&s.open()},50)}ensureChatShell(e){if(this.drawer&&this.backdrop)return;const t=xe(),{mobile:s,useBlur:i,durationMs:r,easing:n}=q(),l=`${r/1e3}s`;this.backdrop=document.createElement("div"),this.backdrop.id="cloudflare-chat-backdrop",this.backdrop.className=`fixed inset-0 z-cf-backdrop opacity-0 pointer-events-none ${i?"bg-black/40 backdrop-blur-xs":"bg-black/50"}`,this.backdrop.style.cssText=`transition: opacity ${l} ${n};`,this.backdrop.setAttribute("aria-hidden","true"),this.appendChild(this.backdrop),this.drawer=document.createElement("div"),this.drawer.id="cloudflare-chat-drawer",this.drawer.setAttribute("role","dialog"),this.drawer.setAttribute("aria-modal","true"),this.drawer.setAttribute("aria-label",e),this.drawer.className=s?"fixed inset-0 z-cf-drawer flex h-full w-full flex-col bg-white dark:bg-zinc-950":"fixed top-0 right-0 z-cf-drawer flex h-full w-[500px] max-w-full flex-col border-l border-zinc-200 bg-white shadow-2xl dark:border-zinc-800 dark:bg-zinc-950",this.drawer.style.cssText=["transform: translate3d(100%, 0, 0)",`transition: transform ${l} ${n}`,"visibility: hidden","pointer-events: none","contain: layout style paint"].join(";");const h=document.createElement("div");h.className="flex shrink-0 items-center justify-between border-b border-zinc-200 bg-zinc-50 p-4 dark:border-zinc-800 dark:bg-zinc-900/50",h.innerHTML=` 2682 <div class="flex items-center gap-2 font-body text-base font-semibold text-zinc-900 dark:text-zinc-50"> 2683 <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 256 256" class="size-5 text-neutral-500" aria-hidden="true"><path d="M208,144a15.78,15.78,0,0,1-10.42,14.94L146,178l-19,51.62a15.92,15.92,0,0,1-29.88,0L78,178l-51.62-19a15.92,15.92,0,0,1,0-29.88L78,110l19-51.62a15.92,15.92,0,0,1,29.88,0L146,110l51.62,19A15.78,15.78,0,0,1,208,144ZM152,48h16V64a8,8,0,0,0,16,0V48h16a8,8,0,0,0,0-16H184V16a8,8,0,0,0-16,0V32H152a8,8,0,0,0,0,16Zm88,32h-8V72a8,8,0,0,0-16,0v8h-8a8,8,0,0,0,0,16h8v8a8,8,0,0,0,16,0V96h8a8,8,0,0,0,0-16Z"></path></svg> 2684 ${e} 2685 </div> 2686 <button id="close-cloudflare-chat" type="button" class="rounded-md p-1 text-zinc-500 transition-colors hover:bg-zinc-100 dark:hover:bg-zinc-800" aria-label="Close"> 2687 <svg class="size-5 fill-none stroke-current" aria-hidden="true"> 2688 <use href="${t}cache/sprite.svg#close-icon"></use> 2689 </svg> 2690 </button> 2691 `,this.drawer.appendChild(h);const d=document.createElement("div");d.className="min-h-0 flex-1 overflow-hidden",d.dataset.chatMount="pending",this.drawer.appendChild(d),this.appendChild(this.drawer),h.querySelector("#close-cloudflare-chat")?.addEventListener("click",()=>this.closeChat()),this.backdrop.addEventListener("click",()=>this.closeChat())}
2691settleClosedLayers(){!this.drawer||!this.backdrop||(this.drawer.style.willChange="auto",this.backdrop.style.willChange="auto",this.drawer.style.visibility="hidden",this.drawer.style.pointerEvents="none",this.backdrop.style.visibility="hidden",this.backdrop.setAttribute("aria-hidden","true"))}settleOpenLayers(){!this.drawer||!this.backdrop||(this.drawer.style.willChange="auto",this.backdrop.style.willChange="auto")}afterTransition(e){this.clearAnimCleanup();const{durationMs:t}=q(),s=this.drawer;if(!s||t===0){e();return}let i=!1;const r=()=>{i||(i=!0,s.removeEventListener("transitionend",n),this.clearAnimCleanup(),e())},n=l=>{l.target===s&&l.propertyName==="transform"&&r()};s.addEventListener("transitionend",n),this.animCleanupTimer=window.setTimeout(r,t+80)}openChat(e){const t=e.getAttribute("data-search-endpoint-url");if(!t||this.chatOpen)return;ve();const s=new URL(t).origin,i=e.getAttribute("data-placeholder")||"Ask AI anything...",r=e.getAttribute("data-translation-ask-ai")||"Ask AI",n=e.getAttribute("data-prefill-query"),{mobile:l,durationMs:h}=q();if(this.pendingPrefill=n,this.ensureChatShell(r),this.updateThemes(),!this.drawer||!this.backdrop)return;this.chatOpen=!0,this.pendingMount={origin:s,placeholder:i},this.drawer.style.visibility="visible",this.backdrop.style.visibility="visible",this.drawer.style.pointerEvents="none",this.backdrop.style.pointerEvents="none",this.drawer.style.transform="translate3d(100%, 0, 0)",this.backdrop.style.opacity="0",this.backdrop.setAttribute("aria-hidden","false"),h>0&&(this.drawer.style.willChange="transform",this.backdrop.style.willChange="opacity"),Se();const d=()=>{!this.drawer||!this.backdrop||!this.chatOpen||(this.drawer.style.transform="translate3d(0, 0, 0)",this.backdrop.style.opacity="1",this.backdrop.style.pointerEvents="auto",this.drawer.style.pointerEvents="auto")};if(h===0){d(),this.settleOpenLayers(),this.mountChatSnippet(s,i);return}requestAnimationFrame(()=>{requestAnimationFrame(d)}),this.afterTransition(()=>{this.chatOpen&&(this.settleOpenLayers(),this.pendingMount&&(this.mountChatSnippet(this.pendingMount.origin,this.pendingMount.placeholder),this.pendingMount=null))}),l||(this.clearMountTimer(),this.mountTimer=window.setTimeout(()=>{this.chatOpen&&this.pendingMount&&(this.mountChatSnippet(this.pendingMount.origin,this.pendingMount.placeholder),this.pendingMount=null)},120))}mountChatSnippet(e,t){if(!this.drawer||!this.chatOpen)return;const s=this.drawer.querySelector("[data-chat-mount]");if(!s)return;let i=s.querySelector("chat-page-snippet");if(!i){const r=()=>{if(!this.drawer||!this.chatOpen||s.querySelector("chat-page-snippet"))return;i=document.createElement("chat-page-snippet"),i.setAttribute("api-url",e),i.setAttribute("placeholder",t),i.setAttribute("theme",this.getActiveTheme()),i.setAttribute("hide-branding","true"),i.setAttribute("chat-query-rewrite",'{"enabled":false}');const l=ye(this);l&&(i.setAttribute("translations",l.raw),i.translations=l.dict),i.style.display="block",i.style.height="100%",i.style.contain="layout style",fe(i),i.addEventListener("ready",()=>{typeof i.toggleSidebar=="function"&&!i.sidebarCollapsed&&i.toggleSidebar(),this.pendingPrefill&&(N(i,this.pendingPrefill),this.pendingPrefill=null)}),s.appendChild(i),s.dataset.chatMount="ready",this.pendingPrefill&&N(i,this.pendingPrefill)},n=j();typeof requestIdleCallback=="function"?requestIdleCallback(r,{timeout:n?400:150}):window.setTimeout(r,n?50:0);return}typeof i.toggleSidebar=="function"&&!i.sidebarCollapsed&&i.toggleSidebar(),this.pendingPrefill&&(N(i,this.pendingPrefill),this.pendingPrefill=null)}closeChat(){if(!this.drawer||!this.backdrop||!this.chatOpen)return;this.chatOpen=!1,this.pendingMount=null,this.clearMountTimer();const{durationMs:e}=q();e>0&&(this.drawer.style.willChange="transform",this.backdrop.style.willChange="opacity"),this.drawer.style.transform="translate3d(100%, 0, 0)",this.backdrop.style.opacity="0",this.backdrop.style.pointerEvents="none",this.drawer.style.pointerEvents="none",Ee(),this.afterTransition(()=>{this.settleClosedLayers()})}}customElements.get("tana-cloudflare-ai")||customElements.define("tana-cloudflare-ai",we);export{we as TanaCloudflareAI,ve as patchLocalStorage,be as unpatchLocalStorage};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.