@lokutor/sdk 1.1.22 → 1.1.23
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/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +32 -6
- package/dist/index.mjs +32 -6
- package/package.json +1 -1
- package/src/conversational-panel.ts +42 -6
package/dist/index.d.mts
CHANGED
|
@@ -613,6 +613,10 @@ interface ConversationalPanelConfig {
|
|
|
613
613
|
curtainBgSrc?: string;
|
|
614
614
|
/** Tool definitions for LLM function calling */
|
|
615
615
|
tools?: any[];
|
|
616
|
+
/** Maximum conversation duration in seconds (default 300) */
|
|
617
|
+
maxDuration?: number;
|
|
618
|
+
/** Seconds of silence before auto-close (default 30) */
|
|
619
|
+
silenceTimeout?: number;
|
|
616
620
|
}
|
|
617
621
|
declare class ConversationalPanel {
|
|
618
622
|
private cfg;
|
|
@@ -623,6 +627,8 @@ declare class ConversationalPanel {
|
|
|
623
627
|
private connectingSound;
|
|
624
628
|
private connectingFadeTimer;
|
|
625
629
|
private isRunning;
|
|
630
|
+
private _locked;
|
|
631
|
+
private _lastSpeechTime;
|
|
626
632
|
private el;
|
|
627
633
|
private curtain;
|
|
628
634
|
private curtainTitle;
|
|
@@ -633,6 +639,7 @@ declare class ConversationalPanel {
|
|
|
633
639
|
private timerEl;
|
|
634
640
|
private canvas;
|
|
635
641
|
private muteBtn;
|
|
642
|
+
private muteSvg;
|
|
636
643
|
private stopBtn;
|
|
637
644
|
private visualizerWrap;
|
|
638
645
|
onTranscription?: (text: string) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -613,6 +613,10 @@ interface ConversationalPanelConfig {
|
|
|
613
613
|
curtainBgSrc?: string;
|
|
614
614
|
/** Tool definitions for LLM function calling */
|
|
615
615
|
tools?: any[];
|
|
616
|
+
/** Maximum conversation duration in seconds (default 300) */
|
|
617
|
+
maxDuration?: number;
|
|
618
|
+
/** Seconds of silence before auto-close (default 30) */
|
|
619
|
+
silenceTimeout?: number;
|
|
616
620
|
}
|
|
617
621
|
declare class ConversationalPanel {
|
|
618
622
|
private cfg;
|
|
@@ -623,6 +627,8 @@ declare class ConversationalPanel {
|
|
|
623
627
|
private connectingSound;
|
|
624
628
|
private connectingFadeTimer;
|
|
625
629
|
private isRunning;
|
|
630
|
+
private _locked;
|
|
631
|
+
private _lastSpeechTime;
|
|
626
632
|
private el;
|
|
627
633
|
private curtain;
|
|
628
634
|
private curtainTitle;
|
|
@@ -633,6 +639,7 @@ declare class ConversationalPanel {
|
|
|
633
639
|
private timerEl;
|
|
634
640
|
private canvas;
|
|
635
641
|
private muteBtn;
|
|
642
|
+
private muteSvg;
|
|
636
643
|
private stopBtn;
|
|
637
644
|
private visualizerWrap;
|
|
638
645
|
onTranscription?: (text: string) => void;
|
package/dist/index.js
CHANGED
|
@@ -1474,6 +1474,13 @@ var PANEL_CSS = (
|
|
|
1474
1474
|
}
|
|
1475
1475
|
.cv-error.is-visible { display: flex; }
|
|
1476
1476
|
.cv-error-icon { color: var(--cv-accent); flex-shrink: 0; }
|
|
1477
|
+
@media (max-width: 640px) {
|
|
1478
|
+
.cv-panel { aspect-ratio: 4 / 3; border-radius: 20px; padding: 1rem 0; }
|
|
1479
|
+
.cv-curtain-content { padding: 0.75rem; gap: 0.5rem; }
|
|
1480
|
+
.cv-curtain-title { font-size: clamp(1rem, 5cqi, 1.6rem); }
|
|
1481
|
+
.cv-curtain-btn { padding: 0.5rem 1.25rem; font-size: clamp(0.7rem, 2cqi, 0.85rem); }
|
|
1482
|
+
.cv-visualizer-wrap { width: clamp(100px, 50cqi, 200px); height: clamp(100px, 50cqi, 200px); }
|
|
1483
|
+
}
|
|
1477
1484
|
`
|
|
1478
1485
|
);
|
|
1479
1486
|
var styleInjected = false;
|
|
@@ -1493,6 +1500,8 @@ var ConversationalPanel = class {
|
|
|
1493
1500
|
connectingSound = null;
|
|
1494
1501
|
connectingFadeTimer = null;
|
|
1495
1502
|
isRunning = false;
|
|
1503
|
+
_locked = false;
|
|
1504
|
+
_lastSpeechTime = 0;
|
|
1496
1505
|
// Cached DOM refs
|
|
1497
1506
|
el;
|
|
1498
1507
|
curtain;
|
|
@@ -1504,6 +1513,7 @@ var ConversationalPanel = class {
|
|
|
1504
1513
|
timerEl;
|
|
1505
1514
|
canvas;
|
|
1506
1515
|
muteBtn;
|
|
1516
|
+
muteSvg;
|
|
1507
1517
|
stopBtn;
|
|
1508
1518
|
visualizerWrap;
|
|
1509
1519
|
// Callbacks
|
|
@@ -1585,6 +1595,7 @@ var ConversationalPanel = class {
|
|
|
1585
1595
|
this.timerEl = this.el.querySelector(".cv-timer");
|
|
1586
1596
|
this.canvas = this.el.querySelector(".cv-canvas");
|
|
1587
1597
|
this.muteBtn = this.el.querySelector(".cv-btn--mute");
|
|
1598
|
+
this.muteSvg = this.muteBtn.querySelector("svg");
|
|
1588
1599
|
this.stopBtn = this.el.querySelector(".cv-btn--end");
|
|
1589
1600
|
this.visualizerWrap = this.el.querySelector(".cv-visualizer-wrap");
|
|
1590
1601
|
this.startBtn.addEventListener("click", () => this.start());
|
|
@@ -1599,6 +1610,10 @@ var ConversationalPanel = class {
|
|
|
1599
1610
|
/** Start the conversation (called when user clicks "Start Conversation" or externally) */
|
|
1600
1611
|
async start() {
|
|
1601
1612
|
if (this.isRunning) return;
|
|
1613
|
+
if (this._locked) {
|
|
1614
|
+
this.showError("This session has ended. Refresh the page to start a new one.");
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1602
1617
|
this.isRunning = true;
|
|
1603
1618
|
this.startBtn.disabled = true;
|
|
1604
1619
|
this.errorEl.classList.remove("is-visible");
|
|
@@ -1632,6 +1647,7 @@ var ConversationalPanel = class {
|
|
|
1632
1647
|
this.onTranscription?.(text);
|
|
1633
1648
|
},
|
|
1634
1649
|
onResponse: (text) => {
|
|
1650
|
+
this._lastSpeechTime = Date.now();
|
|
1635
1651
|
this.onResponse?.(text);
|
|
1636
1652
|
},
|
|
1637
1653
|
onToolCall: (tool) => {
|
|
@@ -1758,12 +1774,26 @@ var ConversationalPanel = class {
|
|
|
1758
1774
|
// ─── internal helpers ────────────────────────────────────
|
|
1759
1775
|
startTimer() {
|
|
1760
1776
|
let elapsed = 0;
|
|
1777
|
+
const maxDur = this.cfg.maxDuration || 300;
|
|
1778
|
+
const silentMax = this.cfg.silenceTimeout || 30;
|
|
1779
|
+
this._lastSpeechTime = Date.now();
|
|
1761
1780
|
this.timerEl.textContent = "00:00";
|
|
1762
1781
|
this.timerTicker = window.setInterval(() => {
|
|
1763
1782
|
elapsed++;
|
|
1764
1783
|
const m = Math.floor(elapsed / 60).toString().padStart(2, "0");
|
|
1765
1784
|
const s = (elapsed % 60).toString().padStart(2, "0");
|
|
1766
1785
|
this.timerEl.textContent = `${m}:${s}`;
|
|
1786
|
+
if (elapsed >= maxDur) {
|
|
1787
|
+
this._locked = true;
|
|
1788
|
+
this.stop();
|
|
1789
|
+
this.showError("Conversation time limit reached. Refresh to start a new one.");
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
if (Date.now() - this._lastSpeechTime > silentMax * 1e3) {
|
|
1793
|
+
this._locked = true;
|
|
1794
|
+
this.stop();
|
|
1795
|
+
this.showError("Session ended due to inactivity. Refresh to start a new one.");
|
|
1796
|
+
}
|
|
1767
1797
|
}, 1e3);
|
|
1768
1798
|
}
|
|
1769
1799
|
toggleMute() {
|
|
@@ -1773,12 +1803,8 @@ var ConversationalPanel = class {
|
|
|
1773
1803
|
this.muteBtn.classList.toggle("is-muted", muted);
|
|
1774
1804
|
const span = this.muteBtn.querySelector("span");
|
|
1775
1805
|
if (span) span.textContent = muted ? "Unmute" : "Mute";
|
|
1776
|
-
if (
|
|
1777
|
-
this.
|
|
1778
|
-
this.visualizer?.setDeactivated?.(true);
|
|
1779
|
-
} else {
|
|
1780
|
-
this.agent.resumeAudio?.();
|
|
1781
|
-
this.visualizer?.setDeactivated?.(false);
|
|
1806
|
+
if (this.muteSvg) {
|
|
1807
|
+
this.muteSvg.innerHTML = muted ? '<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="23" y1="1" x2="1" y2="23"/>' : '<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/>';
|
|
1782
1808
|
}
|
|
1783
1809
|
} catch (_) {
|
|
1784
1810
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1427,6 +1427,13 @@ var PANEL_CSS = (
|
|
|
1427
1427
|
}
|
|
1428
1428
|
.cv-error.is-visible { display: flex; }
|
|
1429
1429
|
.cv-error-icon { color: var(--cv-accent); flex-shrink: 0; }
|
|
1430
|
+
@media (max-width: 640px) {
|
|
1431
|
+
.cv-panel { aspect-ratio: 4 / 3; border-radius: 20px; padding: 1rem 0; }
|
|
1432
|
+
.cv-curtain-content { padding: 0.75rem; gap: 0.5rem; }
|
|
1433
|
+
.cv-curtain-title { font-size: clamp(1rem, 5cqi, 1.6rem); }
|
|
1434
|
+
.cv-curtain-btn { padding: 0.5rem 1.25rem; font-size: clamp(0.7rem, 2cqi, 0.85rem); }
|
|
1435
|
+
.cv-visualizer-wrap { width: clamp(100px, 50cqi, 200px); height: clamp(100px, 50cqi, 200px); }
|
|
1436
|
+
}
|
|
1430
1437
|
`
|
|
1431
1438
|
);
|
|
1432
1439
|
var styleInjected = false;
|
|
@@ -1446,6 +1453,8 @@ var ConversationalPanel = class {
|
|
|
1446
1453
|
connectingSound = null;
|
|
1447
1454
|
connectingFadeTimer = null;
|
|
1448
1455
|
isRunning = false;
|
|
1456
|
+
_locked = false;
|
|
1457
|
+
_lastSpeechTime = 0;
|
|
1449
1458
|
// Cached DOM refs
|
|
1450
1459
|
el;
|
|
1451
1460
|
curtain;
|
|
@@ -1457,6 +1466,7 @@ var ConversationalPanel = class {
|
|
|
1457
1466
|
timerEl;
|
|
1458
1467
|
canvas;
|
|
1459
1468
|
muteBtn;
|
|
1469
|
+
muteSvg;
|
|
1460
1470
|
stopBtn;
|
|
1461
1471
|
visualizerWrap;
|
|
1462
1472
|
// Callbacks
|
|
@@ -1538,6 +1548,7 @@ var ConversationalPanel = class {
|
|
|
1538
1548
|
this.timerEl = this.el.querySelector(".cv-timer");
|
|
1539
1549
|
this.canvas = this.el.querySelector(".cv-canvas");
|
|
1540
1550
|
this.muteBtn = this.el.querySelector(".cv-btn--mute");
|
|
1551
|
+
this.muteSvg = this.muteBtn.querySelector("svg");
|
|
1541
1552
|
this.stopBtn = this.el.querySelector(".cv-btn--end");
|
|
1542
1553
|
this.visualizerWrap = this.el.querySelector(".cv-visualizer-wrap");
|
|
1543
1554
|
this.startBtn.addEventListener("click", () => this.start());
|
|
@@ -1552,6 +1563,10 @@ var ConversationalPanel = class {
|
|
|
1552
1563
|
/** Start the conversation (called when user clicks "Start Conversation" or externally) */
|
|
1553
1564
|
async start() {
|
|
1554
1565
|
if (this.isRunning) return;
|
|
1566
|
+
if (this._locked) {
|
|
1567
|
+
this.showError("This session has ended. Refresh the page to start a new one.");
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1555
1570
|
this.isRunning = true;
|
|
1556
1571
|
this.startBtn.disabled = true;
|
|
1557
1572
|
this.errorEl.classList.remove("is-visible");
|
|
@@ -1585,6 +1600,7 @@ var ConversationalPanel = class {
|
|
|
1585
1600
|
this.onTranscription?.(text);
|
|
1586
1601
|
},
|
|
1587
1602
|
onResponse: (text) => {
|
|
1603
|
+
this._lastSpeechTime = Date.now();
|
|
1588
1604
|
this.onResponse?.(text);
|
|
1589
1605
|
},
|
|
1590
1606
|
onToolCall: (tool) => {
|
|
@@ -1711,12 +1727,26 @@ var ConversationalPanel = class {
|
|
|
1711
1727
|
// ─── internal helpers ────────────────────────────────────
|
|
1712
1728
|
startTimer() {
|
|
1713
1729
|
let elapsed = 0;
|
|
1730
|
+
const maxDur = this.cfg.maxDuration || 300;
|
|
1731
|
+
const silentMax = this.cfg.silenceTimeout || 30;
|
|
1732
|
+
this._lastSpeechTime = Date.now();
|
|
1714
1733
|
this.timerEl.textContent = "00:00";
|
|
1715
1734
|
this.timerTicker = window.setInterval(() => {
|
|
1716
1735
|
elapsed++;
|
|
1717
1736
|
const m = Math.floor(elapsed / 60).toString().padStart(2, "0");
|
|
1718
1737
|
const s = (elapsed % 60).toString().padStart(2, "0");
|
|
1719
1738
|
this.timerEl.textContent = `${m}:${s}`;
|
|
1739
|
+
if (elapsed >= maxDur) {
|
|
1740
|
+
this._locked = true;
|
|
1741
|
+
this.stop();
|
|
1742
|
+
this.showError("Conversation time limit reached. Refresh to start a new one.");
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
if (Date.now() - this._lastSpeechTime > silentMax * 1e3) {
|
|
1746
|
+
this._locked = true;
|
|
1747
|
+
this.stop();
|
|
1748
|
+
this.showError("Session ended due to inactivity. Refresh to start a new one.");
|
|
1749
|
+
}
|
|
1720
1750
|
}, 1e3);
|
|
1721
1751
|
}
|
|
1722
1752
|
toggleMute() {
|
|
@@ -1726,12 +1756,8 @@ var ConversationalPanel = class {
|
|
|
1726
1756
|
this.muteBtn.classList.toggle("is-muted", muted);
|
|
1727
1757
|
const span = this.muteBtn.querySelector("span");
|
|
1728
1758
|
if (span) span.textContent = muted ? "Unmute" : "Mute";
|
|
1729
|
-
if (
|
|
1730
|
-
this.
|
|
1731
|
-
this.visualizer?.setDeactivated?.(true);
|
|
1732
|
-
} else {
|
|
1733
|
-
this.agent.resumeAudio?.();
|
|
1734
|
-
this.visualizer?.setDeactivated?.(false);
|
|
1759
|
+
if (this.muteSvg) {
|
|
1760
|
+
this.muteSvg.innerHTML = muted ? '<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="23" y1="1" x2="1" y2="23"/>' : '<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/>';
|
|
1735
1761
|
}
|
|
1736
1762
|
} catch (_) {
|
|
1737
1763
|
}
|
package/package.json
CHANGED
|
@@ -214,6 +214,13 @@ const PANEL_CSS = /*css*/ `
|
|
|
214
214
|
}
|
|
215
215
|
.cv-error.is-visible { display: flex; }
|
|
216
216
|
.cv-error-icon { color: var(--cv-accent); flex-shrink: 0; }
|
|
217
|
+
@media (max-width: 640px) {
|
|
218
|
+
.cv-panel { aspect-ratio: 4 / 3; border-radius: 20px; padding: 1rem 0; }
|
|
219
|
+
.cv-curtain-content { padding: 0.75rem; gap: 0.5rem; }
|
|
220
|
+
.cv-curtain-title { font-size: clamp(1rem, 5cqi, 1.6rem); }
|
|
221
|
+
.cv-curtain-btn { padding: 0.5rem 1.25rem; font-size: clamp(0.7rem, 2cqi, 0.85rem); }
|
|
222
|
+
.cv-visualizer-wrap { width: clamp(100px, 50cqi, 200px); height: clamp(100px, 50cqi, 200px); }
|
|
223
|
+
}
|
|
217
224
|
`;
|
|
218
225
|
|
|
219
226
|
let styleInjected = false;
|
|
@@ -249,6 +256,10 @@ export interface ConversationalPanelConfig {
|
|
|
249
256
|
curtainBgSrc?: string;
|
|
250
257
|
/** Tool definitions for LLM function calling */
|
|
251
258
|
tools?: any[];
|
|
259
|
+
/** Maximum conversation duration in seconds (default 300) */
|
|
260
|
+
maxDuration?: number;
|
|
261
|
+
/** Seconds of silence before auto-close (default 30) */
|
|
262
|
+
silenceTimeout?: number;
|
|
252
263
|
}
|
|
253
264
|
|
|
254
265
|
export class ConversationalPanel {
|
|
@@ -260,6 +271,8 @@ export class ConversationalPanel {
|
|
|
260
271
|
private connectingSound: HTMLAudioElement | null = null;
|
|
261
272
|
private connectingFadeTimer: number | null = null;
|
|
262
273
|
private isRunning = false;
|
|
274
|
+
private _locked = false;
|
|
275
|
+
private _lastSpeechTime = 0;
|
|
263
276
|
|
|
264
277
|
// Cached DOM refs
|
|
265
278
|
private el!: HTMLElement;
|
|
@@ -272,6 +285,7 @@ export class ConversationalPanel {
|
|
|
272
285
|
private timerEl!: HTMLElement;
|
|
273
286
|
private canvas!: HTMLCanvasElement;
|
|
274
287
|
private muteBtn!: HTMLElement;
|
|
288
|
+
private muteSvg!: SVGElement;
|
|
275
289
|
private stopBtn!: HTMLElement;
|
|
276
290
|
private visualizerWrap!: HTMLElement;
|
|
277
291
|
|
|
@@ -361,6 +375,7 @@ export class ConversationalPanel {
|
|
|
361
375
|
this.timerEl = this.el.querySelector('.cv-timer')!;
|
|
362
376
|
this.canvas = this.el.querySelector('.cv-canvas')!;
|
|
363
377
|
this.muteBtn = this.el.querySelector('.cv-btn--mute')!;
|
|
378
|
+
this.muteSvg = this.muteBtn.querySelector('svg')!;
|
|
364
379
|
this.stopBtn = this.el.querySelector('.cv-btn--end')!;
|
|
365
380
|
this.visualizerWrap = this.el.querySelector('.cv-visualizer-wrap')!;
|
|
366
381
|
|
|
@@ -379,6 +394,10 @@ export class ConversationalPanel {
|
|
|
379
394
|
/** Start the conversation (called when user clicks "Start Conversation" or externally) */
|
|
380
395
|
async start() {
|
|
381
396
|
if (this.isRunning) return;
|
|
397
|
+
if (this._locked) {
|
|
398
|
+
this.showError('This session has ended. Refresh the page to start a new one.');
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
382
401
|
this.isRunning = true;
|
|
383
402
|
this.startBtn.disabled = true;
|
|
384
403
|
this.errorEl.classList.remove('is-visible');
|
|
@@ -417,6 +436,7 @@ export class ConversationalPanel {
|
|
|
417
436
|
this.onTranscription?.(text);
|
|
418
437
|
},
|
|
419
438
|
onResponse: (text: string) => {
|
|
439
|
+
this._lastSpeechTime = Date.now();
|
|
420
440
|
this.onResponse?.(text);
|
|
421
441
|
},
|
|
422
442
|
onToolCall: (tool: any) => {
|
|
@@ -548,12 +568,30 @@ export class ConversationalPanel {
|
|
|
548
568
|
|
|
549
569
|
private startTimer() {
|
|
550
570
|
let elapsed = 0;
|
|
571
|
+
const maxDur = this.cfg.maxDuration || 300;
|
|
572
|
+
const silentMax = this.cfg.silenceTimeout || 30;
|
|
573
|
+
this._lastSpeechTime = Date.now();
|
|
551
574
|
this.timerEl.textContent = '00:00';
|
|
552
575
|
this.timerTicker = window.setInterval(() => {
|
|
553
576
|
elapsed++;
|
|
554
577
|
const m = Math.floor(elapsed / 60).toString().padStart(2, '0');
|
|
555
578
|
const s = (elapsed % 60).toString().padStart(2, '0');
|
|
556
579
|
this.timerEl.textContent = `${m}:${s}`;
|
|
580
|
+
|
|
581
|
+
// Check max duration
|
|
582
|
+
if (elapsed >= maxDur) {
|
|
583
|
+
this._locked = true;
|
|
584
|
+
this.stop();
|
|
585
|
+
this.showError('Conversation time limit reached. Refresh to start a new one.');
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Check silence timeout
|
|
590
|
+
if (Date.now() - this._lastSpeechTime > silentMax * 1000) {
|
|
591
|
+
this._locked = true;
|
|
592
|
+
this.stop();
|
|
593
|
+
this.showError('Session ended due to inactivity. Refresh to start a new one.');
|
|
594
|
+
}
|
|
557
595
|
}, 1000);
|
|
558
596
|
}
|
|
559
597
|
|
|
@@ -564,12 +602,10 @@ export class ConversationalPanel {
|
|
|
564
602
|
this.muteBtn.classList.toggle('is-muted', muted);
|
|
565
603
|
const span = this.muteBtn.querySelector('span');
|
|
566
604
|
if (span) span.textContent = muted ? 'Unmute' : 'Mute';
|
|
567
|
-
if (
|
|
568
|
-
this.
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
this.agent.resumeAudio?.();
|
|
572
|
-
this.visualizer?.setDeactivated?.(false);
|
|
605
|
+
if (this.muteSvg) {
|
|
606
|
+
this.muteSvg.innerHTML = muted
|
|
607
|
+
? '<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="23" y1="1" x2="1" y2="23"/>'
|
|
608
|
+
: '<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/>';
|
|
573
609
|
}
|
|
574
610
|
} catch (_) {}
|
|
575
611
|
}
|