@michaelmishin/speclens 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/dist/speclens.iife.js +208 -46
- package/dist/speclens.iife.js.map +1 -1
- package/dist/speclens.js +392 -45
- package/dist/speclens.js.map +1 -1
- package/package.json +1 -1
package/dist/speclens.js
CHANGED
|
@@ -17995,6 +17995,144 @@ const objectToNumericMapAsync = async (object) => {
|
|
|
17995
17995
|
};
|
|
17996
17996
|
const wait = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
17997
17997
|
const SPACE_OR_PUNCTUATION = /[\n\r\p{Z}\p{P}]+/u;
|
|
17998
|
+
const STOP_WORDS = /* @__PURE__ */ new Set([
|
|
17999
|
+
"a",
|
|
18000
|
+
"an",
|
|
18001
|
+
"the",
|
|
18002
|
+
"is",
|
|
18003
|
+
"are",
|
|
18004
|
+
"was",
|
|
18005
|
+
"were",
|
|
18006
|
+
"be",
|
|
18007
|
+
"been",
|
|
18008
|
+
"being",
|
|
18009
|
+
"have",
|
|
18010
|
+
"has",
|
|
18011
|
+
"had",
|
|
18012
|
+
"do",
|
|
18013
|
+
"does",
|
|
18014
|
+
"did",
|
|
18015
|
+
"will",
|
|
18016
|
+
"would",
|
|
18017
|
+
"shall",
|
|
18018
|
+
"should",
|
|
18019
|
+
"may",
|
|
18020
|
+
"might",
|
|
18021
|
+
"must",
|
|
18022
|
+
"can",
|
|
18023
|
+
"could",
|
|
18024
|
+
"of",
|
|
18025
|
+
"in",
|
|
18026
|
+
"to",
|
|
18027
|
+
"for",
|
|
18028
|
+
"with",
|
|
18029
|
+
"on",
|
|
18030
|
+
"at",
|
|
18031
|
+
"from",
|
|
18032
|
+
"by",
|
|
18033
|
+
"about",
|
|
18034
|
+
"as",
|
|
18035
|
+
"into",
|
|
18036
|
+
"through",
|
|
18037
|
+
"during",
|
|
18038
|
+
"before",
|
|
18039
|
+
"after",
|
|
18040
|
+
"above",
|
|
18041
|
+
"below",
|
|
18042
|
+
"between",
|
|
18043
|
+
"and",
|
|
18044
|
+
"but",
|
|
18045
|
+
"or",
|
|
18046
|
+
"nor",
|
|
18047
|
+
"not",
|
|
18048
|
+
"so",
|
|
18049
|
+
"yet",
|
|
18050
|
+
"both",
|
|
18051
|
+
"either",
|
|
18052
|
+
"neither",
|
|
18053
|
+
"each",
|
|
18054
|
+
"every",
|
|
18055
|
+
"all",
|
|
18056
|
+
"any",
|
|
18057
|
+
"few",
|
|
18058
|
+
"more",
|
|
18059
|
+
"most",
|
|
18060
|
+
"other",
|
|
18061
|
+
"some",
|
|
18062
|
+
"such",
|
|
18063
|
+
"no",
|
|
18064
|
+
"only",
|
|
18065
|
+
"own",
|
|
18066
|
+
"same",
|
|
18067
|
+
"than",
|
|
18068
|
+
"too",
|
|
18069
|
+
"very",
|
|
18070
|
+
"just",
|
|
18071
|
+
"that",
|
|
18072
|
+
"this",
|
|
18073
|
+
"these",
|
|
18074
|
+
"those",
|
|
18075
|
+
"it",
|
|
18076
|
+
"its",
|
|
18077
|
+
"if",
|
|
18078
|
+
"then",
|
|
18079
|
+
"else",
|
|
18080
|
+
"when",
|
|
18081
|
+
"up",
|
|
18082
|
+
"out",
|
|
18083
|
+
"off",
|
|
18084
|
+
"over",
|
|
18085
|
+
"under",
|
|
18086
|
+
"again",
|
|
18087
|
+
"further",
|
|
18088
|
+
"once",
|
|
18089
|
+
"here",
|
|
18090
|
+
"there",
|
|
18091
|
+
"where",
|
|
18092
|
+
"why",
|
|
18093
|
+
"how",
|
|
18094
|
+
"which",
|
|
18095
|
+
"who",
|
|
18096
|
+
"whom",
|
|
18097
|
+
"what",
|
|
18098
|
+
"while",
|
|
18099
|
+
"also",
|
|
18100
|
+
"use",
|
|
18101
|
+
"used",
|
|
18102
|
+
"using",
|
|
18103
|
+
"return",
|
|
18104
|
+
"returns",
|
|
18105
|
+
"returned",
|
|
18106
|
+
"get",
|
|
18107
|
+
"set",
|
|
18108
|
+
"true",
|
|
18109
|
+
"false",
|
|
18110
|
+
"null",
|
|
18111
|
+
"undefined",
|
|
18112
|
+
"string",
|
|
18113
|
+
"number",
|
|
18114
|
+
"boolean",
|
|
18115
|
+
"object",
|
|
18116
|
+
"array",
|
|
18117
|
+
"type",
|
|
18118
|
+
"value",
|
|
18119
|
+
"values",
|
|
18120
|
+
"field",
|
|
18121
|
+
"fields",
|
|
18122
|
+
"example",
|
|
18123
|
+
"default"
|
|
18124
|
+
]);
|
|
18125
|
+
function extractKeywords(texts, max) {
|
|
18126
|
+
const freq = /* @__PURE__ */ new Map();
|
|
18127
|
+
for (const text2 of texts) {
|
|
18128
|
+
const words = text2.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/);
|
|
18129
|
+
for (const w2 of words) {
|
|
18130
|
+
if (w2.length < 3 || STOP_WORDS.has(w2)) continue;
|
|
18131
|
+
freq.set(w2, (freq.get(w2) || 0) + 1);
|
|
18132
|
+
}
|
|
18133
|
+
}
|
|
18134
|
+
return [...freq.entries()].filter(([, count]) => count >= 2).sort((a2, b2) => b2[1] - a2[1]).slice(0, max).map(([word]) => word);
|
|
18135
|
+
}
|
|
17998
18136
|
function buildSearchIndex(operations, guides) {
|
|
17999
18137
|
const opSearch = new MiniSearch({
|
|
18000
18138
|
fields: ["operationId", "summary", "description", "path", "method", "tags"],
|
|
@@ -18044,10 +18182,13 @@ function buildSearchIndex(operations, guides) {
|
|
|
18044
18182
|
}));
|
|
18045
18183
|
guideSearch.addAll(guideDocs);
|
|
18046
18184
|
}
|
|
18185
|
+
const apiTexts = operations.flatMap((op) => [op.summary, op.description, ...op.tags]);
|
|
18186
|
+
const guideTexts = (guides || []).flatMap((g2) => [g2.title, g2.category || "", g2.content || ""]);
|
|
18187
|
+
const keywords = extractKeywords([...apiTexts, ...guideTexts], 12);
|
|
18047
18188
|
return {
|
|
18048
|
-
search(query) {
|
|
18189
|
+
search(query, scope2 = "all") {
|
|
18049
18190
|
if (!query.trim()) return [];
|
|
18050
|
-
const opResults = opSearch.search(query).map((result) => ({
|
|
18191
|
+
const opResults = scope2 !== "guides" ? opSearch.search(query).map((result) => ({
|
|
18051
18192
|
type: "operation",
|
|
18052
18193
|
operationId: result.operationId,
|
|
18053
18194
|
path: result.path,
|
|
@@ -18055,8 +18196,8 @@ function buildSearchIndex(operations, guides) {
|
|
|
18055
18196
|
summary: result.summary,
|
|
18056
18197
|
tags: result.tags.split(" ").filter(Boolean),
|
|
18057
18198
|
score: result.score
|
|
18058
|
-
}));
|
|
18059
|
-
const guideResults = guideSearch ? guideSearch.search(query).map((result) => ({
|
|
18199
|
+
})) : [];
|
|
18200
|
+
const guideResults = scope2 !== "api" && guideSearch ? guideSearch.search(query).map((result) => ({
|
|
18060
18201
|
type: "guide",
|
|
18061
18202
|
slug: result.slug,
|
|
18062
18203
|
title: result.title,
|
|
@@ -18070,6 +18211,12 @@ function buildSearchIndex(operations, guides) {
|
|
|
18070
18211
|
const opSuggestions = opSearch.autoSuggest(query).map((s2) => s2.suggestion);
|
|
18071
18212
|
const guideSuggestions = guideSearch ? guideSearch.autoSuggest(query).map((s2) => s2.suggestion) : [];
|
|
18072
18213
|
return [.../* @__PURE__ */ new Set([...opSuggestions, ...guideSuggestions])];
|
|
18214
|
+
},
|
|
18215
|
+
getKeywords() {
|
|
18216
|
+
return keywords;
|
|
18217
|
+
},
|
|
18218
|
+
hasGuides() {
|
|
18219
|
+
return guideSearch !== null;
|
|
18073
18220
|
}
|
|
18074
18221
|
};
|
|
18075
18222
|
}
|
|
@@ -20363,7 +20510,7 @@ class ThemeManager {
|
|
|
20363
20510
|
}
|
|
20364
20511
|
}
|
|
20365
20512
|
}
|
|
20366
|
-
const
|
|
20513
|
+
const SAFE_ENCODED_LENGTH = 8e3;
|
|
20367
20514
|
function generateAiPrompt(op) {
|
|
20368
20515
|
const lines = [];
|
|
20369
20516
|
lines.push(`I'm working with the following REST API endpoint and need help understanding how to use it correctly.
|
|
@@ -20381,8 +20528,9 @@ ${op.description}`);
|
|
|
20381
20528
|
const flags = [];
|
|
20382
20529
|
if (p2.required) flags.push("required");
|
|
20383
20530
|
if (p2.deprecated) flags.push("deprecated");
|
|
20384
|
-
const
|
|
20385
|
-
const
|
|
20531
|
+
const schema2 = p2.schema;
|
|
20532
|
+
const type2 = (schema2 == null ? void 0 : schema2.type) ?? "any";
|
|
20533
|
+
const enumVals = schema2 == null ? void 0 : schema2.enum;
|
|
20386
20534
|
let line = `- **${p2.name}** (${p2.in}, ${type2}${flags.length ? ", " + flags.join(", ") : ""})`;
|
|
20387
20535
|
if (p2.description) line += `: ${p2.description}`;
|
|
20388
20536
|
if (enumVals == null ? void 0 : enumVals.length) line += ` — Allowed values: ${enumVals.join(", ")}`;
|
|
@@ -20399,20 +20547,9 @@ ${op.description}`);
|
|
|
20399
20547
|
Content-Type: \`${content.mediaType}\``);
|
|
20400
20548
|
if (content.schema) {
|
|
20401
20549
|
const schemaStr = JSON.stringify(content.schema, null, 2);
|
|
20402
|
-
|
|
20403
|
-
|
|
20404
|
-
|
|
20405
|
-
lines.push("```");
|
|
20406
|
-
} else {
|
|
20407
|
-
lines.push("Schema: (large schema, key properties shown)");
|
|
20408
|
-
const props = content.schema.properties;
|
|
20409
|
-
if (props) {
|
|
20410
|
-
for (const [key, val] of Object.entries(props)) {
|
|
20411
|
-
const t2 = (val == null ? void 0 : val.type) ?? "object";
|
|
20412
|
-
lines.push(`- ${key}: ${t2}`);
|
|
20413
|
-
}
|
|
20414
|
-
}
|
|
20415
|
-
}
|
|
20550
|
+
lines.push("```json");
|
|
20551
|
+
lines.push(schemaStr);
|
|
20552
|
+
lines.push("```");
|
|
20416
20553
|
}
|
|
20417
20554
|
if (content.example !== void 0) {
|
|
20418
20555
|
lines.push(`
|
|
@@ -20432,14 +20569,10 @@ ${JSON.stringify(content.example, null, 2)}
|
|
|
20432
20569
|
for (const content of r2.content) {
|
|
20433
20570
|
if (content.schema) {
|
|
20434
20571
|
const schemaStr = JSON.stringify(content.schema, null, 2);
|
|
20435
|
-
|
|
20436
|
-
lines.push(`\`${content.mediaType}\`
|
|
20572
|
+
lines.push(`\`${content.mediaType}\`
|
|
20437
20573
|
\`\`\`json
|
|
20438
20574
|
${schemaStr}
|
|
20439
20575
|
\`\`\``);
|
|
20440
|
-
} else {
|
|
20441
|
-
lines.push(`\`${content.mediaType}\` — (large schema)`);
|
|
20442
|
-
}
|
|
20443
20576
|
}
|
|
20444
20577
|
}
|
|
20445
20578
|
}
|
|
@@ -20456,20 +20589,20 @@ ${schemaStr}
|
|
|
20456
20589
|
}
|
|
20457
20590
|
lines.push(`
|
|
20458
20591
|
Please help me understand this endpoint, write an example request, and explain the expected response.`);
|
|
20459
|
-
|
|
20460
|
-
if (prompt.length > MAX_PROMPT_LENGTH) {
|
|
20461
|
-
prompt = prompt.slice(0, MAX_PROMPT_LENGTH - 3) + "...";
|
|
20462
|
-
}
|
|
20463
|
-
return prompt;
|
|
20592
|
+
return lines.join("\n");
|
|
20464
20593
|
}
|
|
20465
|
-
function
|
|
20594
|
+
function _baseUrl(target) {
|
|
20595
|
+
return target === "chatgpt" ? "https://chatgpt.com/" : "https://claude.ai/new";
|
|
20596
|
+
}
|
|
20597
|
+
async function openAiWithPrompt(prompt, target) {
|
|
20466
20598
|
const encoded = encodeURIComponent(prompt);
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
|
|
20470
|
-
case "claude":
|
|
20471
|
-
return `https://claude.ai/new?q=${encoded}`;
|
|
20599
|
+
if (encoded.length <= SAFE_ENCODED_LENGTH) {
|
|
20600
|
+
window.open(`${_baseUrl(target)}?q=${encoded}`, "_blank", "noopener,noreferrer");
|
|
20601
|
+
return "url";
|
|
20472
20602
|
}
|
|
20603
|
+
await navigator.clipboard.writeText(prompt);
|
|
20604
|
+
window.open(_baseUrl(target), "_blank", "noopener,noreferrer");
|
|
20605
|
+
return "clipboard";
|
|
20473
20606
|
}
|
|
20474
20607
|
var __defProp$d = Object.defineProperty;
|
|
20475
20608
|
var __getOwnPropDesc$d = Object.getOwnPropertyDescriptor;
|
|
@@ -21258,6 +21391,7 @@ let SlSearch = class extends i$1 {
|
|
|
21258
21391
|
this._query = "";
|
|
21259
21392
|
this._results = [];
|
|
21260
21393
|
this._highlightIndex = 0;
|
|
21394
|
+
this._scope = "all";
|
|
21261
21395
|
}
|
|
21262
21396
|
firstUpdated() {
|
|
21263
21397
|
var _a2;
|
|
@@ -21266,12 +21400,29 @@ let SlSearch = class extends i$1 {
|
|
|
21266
21400
|
_handleInput(e2) {
|
|
21267
21401
|
this._query = e2.target.value;
|
|
21268
21402
|
this._highlightIndex = 0;
|
|
21403
|
+
this._runSearch();
|
|
21404
|
+
}
|
|
21405
|
+
_runSearch() {
|
|
21269
21406
|
if (this.searchEngine && this._query.trim()) {
|
|
21270
|
-
this._results = this.searchEngine.search(this._query).slice(0, 20);
|
|
21407
|
+
this._results = this.searchEngine.search(this._query, this._scope).slice(0, 20);
|
|
21271
21408
|
} else {
|
|
21272
21409
|
this._results = [];
|
|
21273
21410
|
}
|
|
21274
21411
|
}
|
|
21412
|
+
_setScope(scope2) {
|
|
21413
|
+
var _a2;
|
|
21414
|
+
this._scope = scope2;
|
|
21415
|
+
this._runSearch();
|
|
21416
|
+
(_a2 = this._input) == null ? void 0 : _a2.focus();
|
|
21417
|
+
}
|
|
21418
|
+
_searchKeyword(keyword2) {
|
|
21419
|
+
var _a2;
|
|
21420
|
+
this._query = keyword2;
|
|
21421
|
+
this._highlightIndex = 0;
|
|
21422
|
+
this._runSearch();
|
|
21423
|
+
if (this._input) this._input.value = keyword2;
|
|
21424
|
+
(_a2 = this._input) == null ? void 0 : _a2.focus();
|
|
21425
|
+
}
|
|
21275
21426
|
_handleKeyDown(e2) {
|
|
21276
21427
|
switch (e2.key) {
|
|
21277
21428
|
case "Escape":
|
|
@@ -21331,6 +21482,9 @@ let SlSearch = class extends i$1 {
|
|
|
21331
21482
|
}
|
|
21332
21483
|
}
|
|
21333
21484
|
render() {
|
|
21485
|
+
var _a2, _b2;
|
|
21486
|
+
const showScopeBar = (_a2 = this.searchEngine) == null ? void 0 : _a2.hasGuides();
|
|
21487
|
+
const keywords = ((_b2 = this.searchEngine) == null ? void 0 : _b2.getKeywords()) || [];
|
|
21334
21488
|
return b`
|
|
21335
21489
|
<div class="overlay" @click=${() => this.dispatchEvent(new CustomEvent("close"))}></div>
|
|
21336
21490
|
<div class="modal" @keydown=${this._handleKeyDown}>
|
|
@@ -21348,9 +21502,28 @@ let SlSearch = class extends i$1 {
|
|
|
21348
21502
|
<span class="esc-hint">Esc</span>
|
|
21349
21503
|
</div>
|
|
21350
21504
|
|
|
21505
|
+
${showScopeBar ? b`
|
|
21506
|
+
<div class="scope-bar">
|
|
21507
|
+
<button class="scope-chip ${this._scope === "all" ? "active" : ""}" @click=${() => this._setScope("all")}>All</button>
|
|
21508
|
+
<button class="scope-chip ${this._scope === "api" ? "active" : ""}" @click=${() => this._setScope("api")}>API Reference</button>
|
|
21509
|
+
<button class="scope-chip ${this._scope === "guides" ? "active" : ""}" @click=${() => this._setScope("guides")}>Guides</button>
|
|
21510
|
+
</div>
|
|
21511
|
+
` : null}
|
|
21512
|
+
|
|
21351
21513
|
<div class="results">
|
|
21352
21514
|
${this._query.trim() === "" ? b`
|
|
21353
|
-
|
|
21515
|
+
${keywords.length > 0 ? b`
|
|
21516
|
+
<div class="keywords-section">
|
|
21517
|
+
<div class="keywords-label">Suggested searches</div>
|
|
21518
|
+
<div class="keywords-list">
|
|
21519
|
+
${keywords.map((kw) => b`
|
|
21520
|
+
<button class="keyword-chip" @click=${() => this._searchKeyword(kw)}>${kw}</button>
|
|
21521
|
+
`)}
|
|
21522
|
+
</div>
|
|
21523
|
+
</div>
|
|
21524
|
+
` : b`
|
|
21525
|
+
<div class="empty-state">Start typing to search…</div>
|
|
21526
|
+
`}
|
|
21354
21527
|
` : this._results.length === 0 ? b`
|
|
21355
21528
|
<div class="no-results">No results for "${this._query}"</div>
|
|
21356
21529
|
` : this._results.map((result, i3) => this._renderResult(result, i3))}
|
|
@@ -21531,6 +21704,70 @@ SlSearch.styles = [
|
|
|
21531
21704
|
color: var(--sl-color-text-muted);
|
|
21532
21705
|
border: 1px solid var(--sl-color-border);
|
|
21533
21706
|
}
|
|
21707
|
+
|
|
21708
|
+
/* ── Scope filter ────────────────────── */
|
|
21709
|
+
.scope-bar {
|
|
21710
|
+
display: flex;
|
|
21711
|
+
gap: 4px;
|
|
21712
|
+
padding: 4px var(--sl-spacing-lg) var(--sl-spacing-sm);
|
|
21713
|
+
}
|
|
21714
|
+
|
|
21715
|
+
.scope-chip {
|
|
21716
|
+
padding: 3px 10px;
|
|
21717
|
+
border-radius: 999px;
|
|
21718
|
+
font-size: var(--sl-font-size-xs);
|
|
21719
|
+
font-weight: 600;
|
|
21720
|
+
cursor: pointer;
|
|
21721
|
+
transition: all var(--sl-transition-fast);
|
|
21722
|
+
border: 1px solid var(--sl-color-border);
|
|
21723
|
+
background: transparent;
|
|
21724
|
+
color: var(--sl-color-text-muted);
|
|
21725
|
+
}
|
|
21726
|
+
|
|
21727
|
+
.scope-chip:hover {
|
|
21728
|
+
background: var(--sl-color-surface-raised);
|
|
21729
|
+
color: var(--sl-color-text);
|
|
21730
|
+
}
|
|
21731
|
+
|
|
21732
|
+
.scope-chip.active {
|
|
21733
|
+
background: var(--sl-color-primary);
|
|
21734
|
+
color: #fff;
|
|
21735
|
+
border-color: var(--sl-color-primary);
|
|
21736
|
+
}
|
|
21737
|
+
|
|
21738
|
+
/* ── Keyword chips ───────────────────── */
|
|
21739
|
+
.keywords-section {
|
|
21740
|
+
padding: var(--sl-spacing-sm) var(--sl-spacing-lg) var(--sl-spacing-md);
|
|
21741
|
+
}
|
|
21742
|
+
|
|
21743
|
+
.keywords-label {
|
|
21744
|
+
font-size: var(--sl-font-size-xs);
|
|
21745
|
+
color: var(--sl-color-text-muted);
|
|
21746
|
+
margin-bottom: 6px;
|
|
21747
|
+
}
|
|
21748
|
+
|
|
21749
|
+
.keywords-list {
|
|
21750
|
+
display: flex;
|
|
21751
|
+
flex-wrap: wrap;
|
|
21752
|
+
gap: 6px;
|
|
21753
|
+
}
|
|
21754
|
+
|
|
21755
|
+
.keyword-chip {
|
|
21756
|
+
padding: 3px 10px;
|
|
21757
|
+
border-radius: 999px;
|
|
21758
|
+
font-size: var(--sl-font-size-xs);
|
|
21759
|
+
cursor: pointer;
|
|
21760
|
+
transition: all var(--sl-transition-fast);
|
|
21761
|
+
border: 1px solid var(--sl-color-border);
|
|
21762
|
+
background: var(--sl-color-surface-raised);
|
|
21763
|
+
color: var(--sl-color-text-muted);
|
|
21764
|
+
}
|
|
21765
|
+
|
|
21766
|
+
.keyword-chip:hover {
|
|
21767
|
+
background: var(--sl-color-primary);
|
|
21768
|
+
color: #fff;
|
|
21769
|
+
border-color: var(--sl-color-primary);
|
|
21770
|
+
}
|
|
21534
21771
|
`
|
|
21535
21772
|
];
|
|
21536
21773
|
__decorateClass$b([
|
|
@@ -21545,6 +21782,9 @@ __decorateClass$b([
|
|
|
21545
21782
|
__decorateClass$b([
|
|
21546
21783
|
r$1()
|
|
21547
21784
|
], SlSearch.prototype, "_highlightIndex", 2);
|
|
21785
|
+
__decorateClass$b([
|
|
21786
|
+
r$1()
|
|
21787
|
+
], SlSearch.prototype, "_scope", 2);
|
|
21548
21788
|
__decorateClass$b([
|
|
21549
21789
|
e$2("input")
|
|
21550
21790
|
], SlSearch.prototype, "_input", 2);
|
|
@@ -29278,6 +29518,7 @@ let SlOperation = class extends i$1 {
|
|
|
29278
29518
|
this._routeCopied = false;
|
|
29279
29519
|
this._aiMenuOpen = false;
|
|
29280
29520
|
this._aiMenuRect = null;
|
|
29521
|
+
this._aiToast = false;
|
|
29281
29522
|
}
|
|
29282
29523
|
willUpdate(changed) {
|
|
29283
29524
|
var _a2;
|
|
@@ -29330,12 +29571,27 @@ let SlOperation = class extends i$1 {
|
|
|
29330
29571
|
requestAnimationFrame(() => document.addEventListener("click", close, true));
|
|
29331
29572
|
}
|
|
29332
29573
|
}
|
|
29333
|
-
_openAi(target, e2) {
|
|
29574
|
+
async _openAi(target, e2) {
|
|
29334
29575
|
e2.stopPropagation();
|
|
29335
29576
|
this._aiMenuOpen = false;
|
|
29336
29577
|
const prompt = generateAiPrompt(this.operation);
|
|
29337
|
-
const
|
|
29338
|
-
|
|
29578
|
+
const result = await openAiWithPrompt(prompt, target);
|
|
29579
|
+
if (result === "clipboard") {
|
|
29580
|
+
this._aiToast = true;
|
|
29581
|
+
setTimeout(() => {
|
|
29582
|
+
this._aiToast = false;
|
|
29583
|
+
}, 4e3);
|
|
29584
|
+
}
|
|
29585
|
+
}
|
|
29586
|
+
async _copyPrompt(e2) {
|
|
29587
|
+
e2.stopPropagation();
|
|
29588
|
+
this._aiMenuOpen = false;
|
|
29589
|
+
const prompt = generateAiPrompt(this.operation);
|
|
29590
|
+
await navigator.clipboard.writeText(prompt);
|
|
29591
|
+
this._aiToast = true;
|
|
29592
|
+
setTimeout(() => {
|
|
29593
|
+
this._aiToast = false;
|
|
29594
|
+
}, 4e3);
|
|
29339
29595
|
}
|
|
29340
29596
|
render() {
|
|
29341
29597
|
const op = this.operation;
|
|
@@ -29461,6 +29717,23 @@ let SlOperation = class extends i$1 {
|
|
|
29461
29717
|
</svg>
|
|
29462
29718
|
Claude
|
|
29463
29719
|
</button>
|
|
29720
|
+
<div style="border-top:1px solid var(--sl-color-border);margin:4px 0"></div>
|
|
29721
|
+
<button class="ai-menu-item" @click=${(e2) => this._copyPrompt(e2)}>
|
|
29722
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
29723
|
+
<rect x="5" y="5" width="8" height="8" rx="1"/>
|
|
29724
|
+
<path d="M3 11V3h8"/>
|
|
29725
|
+
</svg>
|
|
29726
|
+
Copy Prompt
|
|
29727
|
+
</button>
|
|
29728
|
+
</div>
|
|
29729
|
+
` : null}
|
|
29730
|
+
${this._aiToast ? b`
|
|
29731
|
+
<div class="ai-toast">
|
|
29732
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
29733
|
+
<rect x="5" y="5" width="8" height="8" rx="1"/>
|
|
29734
|
+
<path d="M3 11V3h8"/>
|
|
29735
|
+
</svg>
|
|
29736
|
+
Prompt copied — paste it into the chat
|
|
29464
29737
|
</div>
|
|
29465
29738
|
` : null}
|
|
29466
29739
|
`;
|
|
@@ -29796,6 +30069,32 @@ SlOperation.styles = [
|
|
|
29796
30069
|
flex-shrink: 0;
|
|
29797
30070
|
}
|
|
29798
30071
|
|
|
30072
|
+
/* ── AI clipboard toast ──────────────── */
|
|
30073
|
+
.ai-toast {
|
|
30074
|
+
position: fixed;
|
|
30075
|
+
bottom: 24px;
|
|
30076
|
+
left: 50%;
|
|
30077
|
+
transform: translateX(-50%);
|
|
30078
|
+
z-index: 10000;
|
|
30079
|
+
display: flex;
|
|
30080
|
+
align-items: center;
|
|
30081
|
+
gap: 10px;
|
|
30082
|
+
padding: 12px 18px;
|
|
30083
|
+
background: var(--sl-color-text);
|
|
30084
|
+
color: var(--sl-color-bg);
|
|
30085
|
+
border-radius: var(--sl-radius-lg);
|
|
30086
|
+
font-size: var(--sl-font-size-sm);
|
|
30087
|
+
font-weight: 500;
|
|
30088
|
+
box-shadow: var(--sl-shadow-lg);
|
|
30089
|
+
white-space: nowrap;
|
|
30090
|
+
animation: sl-toast-in 200ms ease;
|
|
30091
|
+
}
|
|
30092
|
+
|
|
30093
|
+
@keyframes sl-toast-in {
|
|
30094
|
+
from { opacity: 0; transform: translateX(-50%) translateY(8px); }
|
|
30095
|
+
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
30096
|
+
}
|
|
30097
|
+
|
|
29799
30098
|
@media (max-width: 900px) {
|
|
29800
30099
|
.op-body {
|
|
29801
30100
|
grid-template-columns: 1fr;
|
|
@@ -29849,6 +30148,9 @@ __decorateClass$5([
|
|
|
29849
30148
|
__decorateClass$5([
|
|
29850
30149
|
r$1()
|
|
29851
30150
|
], SlOperation.prototype, "_aiMenuRect", 2);
|
|
30151
|
+
__decorateClass$5([
|
|
30152
|
+
r$1()
|
|
30153
|
+
], SlOperation.prototype, "_aiToast", 2);
|
|
29852
30154
|
SlOperation = __decorateClass$5([
|
|
29853
30155
|
t$1("sl-operation")
|
|
29854
30156
|
], SlOperation);
|
|
@@ -31635,6 +31937,7 @@ let SpecLensElement = class extends i$1 {
|
|
|
31635
31937
|
this._searchOpen = false;
|
|
31636
31938
|
this._tryItAiMenuOpen = false;
|
|
31637
31939
|
this._tryItAiMenuRect = null;
|
|
31940
|
+
this._aiToast = false;
|
|
31638
31941
|
this._search = null;
|
|
31639
31942
|
this._router = null;
|
|
31640
31943
|
this._themeManager = null;
|
|
@@ -31773,12 +32076,17 @@ let SpecLensElement = class extends i$1 {
|
|
|
31773
32076
|
requestAnimationFrame(() => document.addEventListener("click", close, true));
|
|
31774
32077
|
}
|
|
31775
32078
|
}
|
|
31776
|
-
_openTryItAi(target) {
|
|
32079
|
+
async _openTryItAi(target) {
|
|
31777
32080
|
this._tryItAiMenuOpen = false;
|
|
31778
32081
|
if (!this._tryItOperation) return;
|
|
31779
32082
|
const prompt = generateAiPrompt(this._tryItOperation);
|
|
31780
|
-
const
|
|
31781
|
-
|
|
32083
|
+
const result = await openAiWithPrompt(prompt, target);
|
|
32084
|
+
if (result === "clipboard") {
|
|
32085
|
+
this._aiToast = true;
|
|
32086
|
+
setTimeout(() => {
|
|
32087
|
+
this._aiToast = false;
|
|
32088
|
+
}, 4e3);
|
|
32089
|
+
}
|
|
31782
32090
|
}
|
|
31783
32091
|
/** Set the color theme programmatically. Useful in embed mode where the header is hidden. */
|
|
31784
32092
|
setTheme(preference) {
|
|
@@ -32042,6 +32350,16 @@ let SpecLensElement = class extends i$1 {
|
|
|
32042
32350
|
@select-guide=${this._handleSearchSelectGuide}
|
|
32043
32351
|
></sl-search>
|
|
32044
32352
|
` : null}
|
|
32353
|
+
|
|
32354
|
+
${this._aiToast ? b`
|
|
32355
|
+
<div class="ai-toast">
|
|
32356
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
32357
|
+
<rect x="5" y="5" width="8" height="8" rx="1"/>
|
|
32358
|
+
<path d="M3 11V3h8"/>
|
|
32359
|
+
</svg>
|
|
32360
|
+
Prompt copied — paste it into the chat
|
|
32361
|
+
</div>
|
|
32362
|
+
` : null}
|
|
32045
32363
|
</div>
|
|
32046
32364
|
`;
|
|
32047
32365
|
}
|
|
@@ -32639,6 +32957,32 @@ SpecLensElement.styles = [
|
|
|
32639
32957
|
--sl-header-height: 0px;
|
|
32640
32958
|
min-height: unset;
|
|
32641
32959
|
}
|
|
32960
|
+
|
|
32961
|
+
/* ── AI clipboard toast ──────────────── */
|
|
32962
|
+
.ai-toast {
|
|
32963
|
+
position: fixed;
|
|
32964
|
+
bottom: 24px;
|
|
32965
|
+
left: 50%;
|
|
32966
|
+
transform: translateX(-50%);
|
|
32967
|
+
z-index: 10000;
|
|
32968
|
+
display: flex;
|
|
32969
|
+
align-items: center;
|
|
32970
|
+
gap: 10px;
|
|
32971
|
+
padding: 12px 18px;
|
|
32972
|
+
background: var(--sl-color-text);
|
|
32973
|
+
color: var(--sl-color-bg);
|
|
32974
|
+
border-radius: var(--sl-radius-lg);
|
|
32975
|
+
font-size: var(--sl-font-size-sm);
|
|
32976
|
+
font-weight: 500;
|
|
32977
|
+
box-shadow: var(--sl-shadow-lg);
|
|
32978
|
+
white-space: nowrap;
|
|
32979
|
+
animation: sl-toast-in 200ms ease;
|
|
32980
|
+
}
|
|
32981
|
+
|
|
32982
|
+
@keyframes sl-toast-in {
|
|
32983
|
+
from { opacity: 0; transform: translateX(-50%) translateY(8px); }
|
|
32984
|
+
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
32985
|
+
}
|
|
32642
32986
|
`
|
|
32643
32987
|
];
|
|
32644
32988
|
__decorateClass([
|
|
@@ -32713,6 +33057,9 @@ __decorateClass([
|
|
|
32713
33057
|
__decorateClass([
|
|
32714
33058
|
r$1()
|
|
32715
33059
|
], SpecLensElement.prototype, "_tryItAiMenuRect", 2);
|
|
33060
|
+
__decorateClass([
|
|
33061
|
+
r$1()
|
|
33062
|
+
], SpecLensElement.prototype, "_aiToast", 2);
|
|
32716
33063
|
SpecLensElement = __decorateClass([
|
|
32717
33064
|
t$1("spec-lens")
|
|
32718
33065
|
], SpecLensElement);
|