@rndev77/suzu-ai 0.1.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/package.json +34 -0
- package/src/bind-panel.js +1500 -0
- package/src/index.d.ts +22 -0
- package/src/index.js +123 -0
- package/src/markup.js +87 -0
- package/src/style.css +2704 -0
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SuzuChat } from "@rndev77/suzu-ai-core";
|
|
2
|
+
|
|
3
|
+
export interface SuzuWidgetOptions {
|
|
4
|
+
apiBase: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
target?: string | ParentNode;
|
|
7
|
+
launcher?: boolean;
|
|
8
|
+
open?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SuzuWidgetInstance {
|
|
12
|
+
el: HTMLElement | null;
|
|
13
|
+
open(): void;
|
|
14
|
+
close(): void;
|
|
15
|
+
send(text?: string): void;
|
|
16
|
+
reset(): void;
|
|
17
|
+
destroy(): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createSuzuWidget(options: SuzuWidgetOptions): SuzuWidgetInstance;
|
|
21
|
+
export { SuzuChat };
|
|
22
|
+
export default createSuzuWidget;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SuzuChat } from "@rndev77/suzu-ai-core";
|
|
2
|
+
import { bindSuzuPanel } from "./bind-panel.js";
|
|
3
|
+
import { launcherMarkup, panelMarkup } from "./markup.js";
|
|
4
|
+
|
|
5
|
+
var STYLE_ID = "suzu-widget-css";
|
|
6
|
+
var mounted = null;
|
|
7
|
+
|
|
8
|
+
function ensureSuzuChat() {
|
|
9
|
+
if (typeof window === "undefined") return;
|
|
10
|
+
window.SuzuChat = SuzuChat;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function ensureStyles() {
|
|
14
|
+
if (typeof document === "undefined") return;
|
|
15
|
+
if (document.getElementById(STYLE_ID)) return;
|
|
16
|
+
var href = new URL("./style.css", import.meta.url).href;
|
|
17
|
+
var link = document.createElement("link");
|
|
18
|
+
link.id = STYLE_ID;
|
|
19
|
+
link.rel = "stylesheet";
|
|
20
|
+
link.href = href;
|
|
21
|
+
document.head.appendChild(link);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolveTarget(target) {
|
|
25
|
+
if (!target) return document.body;
|
|
26
|
+
if (typeof target === "string") return document.querySelector(target) || document.body;
|
|
27
|
+
return target;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function applyCredentials(panel, apiBase, apiKey) {
|
|
31
|
+
if (!panel) return;
|
|
32
|
+
if (apiBase) panel.setAttribute("data-api-url", apiBase);
|
|
33
|
+
if (apiKey) panel.setAttribute("data-api-key", apiKey);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function controllerApi() {
|
|
37
|
+
var ctrl = (typeof window !== "undefined" && window.SuzuPanelController) || {};
|
|
38
|
+
return {
|
|
39
|
+
open: function () {
|
|
40
|
+
if (ctrl.open) ctrl.open();
|
|
41
|
+
},
|
|
42
|
+
close: function () {
|
|
43
|
+
if (ctrl.close) ctrl.close();
|
|
44
|
+
},
|
|
45
|
+
send: function (text) {
|
|
46
|
+
if (ctrl.send) ctrl.send(text);
|
|
47
|
+
},
|
|
48
|
+
reset: function () {
|
|
49
|
+
if (ctrl.reset) ctrl.reset();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function createSuzuWidget(options) {
|
|
55
|
+
options = options || {};
|
|
56
|
+
if (typeof document === "undefined") {
|
|
57
|
+
throw new Error("createSuzuWidget работает только в браузере");
|
|
58
|
+
}
|
|
59
|
+
ensureSuzuChat();
|
|
60
|
+
ensureStyles();
|
|
61
|
+
|
|
62
|
+
var apiBase = String(options.apiBase || "");
|
|
63
|
+
var apiKey = String(options.apiKey || "");
|
|
64
|
+
var target = resolveTarget(options.target);
|
|
65
|
+
var withLauncher = options.launcher !== false;
|
|
66
|
+
|
|
67
|
+
var panel = document.getElementById("suzu-panel");
|
|
68
|
+
if (!panel) {
|
|
69
|
+
var wrap = document.createElement("div");
|
|
70
|
+
wrap.className = "suzu-widget-root";
|
|
71
|
+
wrap.innerHTML = panelMarkup(apiBase, apiKey);
|
|
72
|
+
target.appendChild(wrap);
|
|
73
|
+
panel = wrap.querySelector("#suzu-panel");
|
|
74
|
+
} else {
|
|
75
|
+
applyCredentials(panel, apiBase, apiKey);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var launcher = document.getElementById("suzu-launcher");
|
|
79
|
+
if (withLauncher && !launcher) {
|
|
80
|
+
var holder = document.createElement("div");
|
|
81
|
+
holder.innerHTML = launcherMarkup();
|
|
82
|
+
launcher = holder.firstElementChild;
|
|
83
|
+
document.body.appendChild(launcher);
|
|
84
|
+
}
|
|
85
|
+
if (launcher) {
|
|
86
|
+
launcher.hidden = !withLauncher;
|
|
87
|
+
if (!launcher._suzuBound) {
|
|
88
|
+
launcher.addEventListener("click", function () {
|
|
89
|
+
var api = window.SuzuPanelController;
|
|
90
|
+
if (api && api.open) api.open();
|
|
91
|
+
});
|
|
92
|
+
launcher._suzuBound = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!window.__suzuPanelBound) {
|
|
97
|
+
bindSuzuPanel();
|
|
98
|
+
window.__suzuPanelBound = true;
|
|
99
|
+
}
|
|
100
|
+
var api = controllerApi();
|
|
101
|
+
if (options.open) api.open();
|
|
102
|
+
|
|
103
|
+
mounted = {
|
|
104
|
+
el: panel,
|
|
105
|
+
open: api.open,
|
|
106
|
+
close: api.close,
|
|
107
|
+
send: api.send,
|
|
108
|
+
reset: api.reset,
|
|
109
|
+
destroy: function () {
|
|
110
|
+
api.close();
|
|
111
|
+
var root = panel && panel.closest(".suzu-widget-root");
|
|
112
|
+
if (root && root.parentNode) root.parentNode.removeChild(root);
|
|
113
|
+
else if (panel && panel.parentNode) panel.parentNode.removeChild(panel);
|
|
114
|
+
var fab = document.getElementById("suzu-launcher");
|
|
115
|
+
if (fab && fab.parentNode) fab.parentNode.removeChild(fab);
|
|
116
|
+
if (mounted === this) mounted = null;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
return mounted;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { SuzuChat };
|
|
123
|
+
export default createSuzuWidget;
|
package/src/markup.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
var LOGO =
|
|
2
|
+
'<svg viewBox="0 0 176.5 195.58" width="22" height="24" aria-hidden="true">' +
|
|
3
|
+
'<path fill="currentColor" d="M126.34,33.73c-5.05-2.46-10.38-4.43-15.92-5.89-3.94-8.28-12.38-14-22.16-14s-18.24,5.73-22.18,14c-5.54,1.46-10.85,3.43-15.9,5.86C52.44,14.72,68.62,0,88.26,0s35.81,14.72,38.09,33.73Z"/>' +
|
|
4
|
+
'<path fill="currentColor" d="M89.18,109.77h-.93c-48.26,.16-73.04,12.47-84.42,21-.02,.02-.05,.05-.07,.05l-1.53,1.18c-.83,.67-1.58,1.32-2.23,1.9,.32,5.56,5.19,10.71,13.38,15.14,12.87,26.38,39.27,44.92,70.19,46.55v-37.69c-5.26-1.9-9.02-6.95-9.02-12.89,0-7.53,6.12-13.7,13.7-13.7s13.7,6.17,13.7,13.7c0,5.93-3.78,10.99-9.04,12.89v37.67c30.67-1.74,56.88-20.12,69.75-46.29,8.69-4.59,13.75-9.62,13.84-15.44-8.99-8.23-33.31-24.06-87.32-24.06Z"/>' +
|
|
5
|
+
'<path fill="currentColor" d="M93.13,103.62c-1.55-.02-3.15-.05-4.73-.05-1.69,0-3.36,.02-5.03,.05,.93-1.76,2.78-2.9,4.98-2.87,2.06,.02,3.85,1.18,4.78,2.87Z"/>' +
|
|
6
|
+
'<path fill="currentColor" d="M125.63,95.94c-1.21,2.02-2.64,3.76-4.31,5.12-.9,.79-1.85,1.44-2.9,1.97-1.48,.76-3.15,1.27-4.98,1.53-.37,.05-.76,.09-1.14,.12h-.07c-.56-.05-1.14-.12-1.69-.16-1.58-.14-3.18-.25-4.78-.37-1.18-.09-2.39-.16-3.62-.21-1.04-.07-2.09-.12-3.15-.16,.07-.09,.16-.16,.23-.21,.97-.65,1.95-1.32,2.92-1.95h.02c1.07-.74,2.13-1.44,3.2-2.13,2.02-1.32,4.03-2.64,6.05-3.99,.58-.39,1.07-.46,1.76-.21,.79,.28,1.72,.46,2.53,.35,2.5-.35,4.36-2.71,4.15-5.15-.19-2.43-2.36-4.52-4.71-4.54-2.62,0-4.68,1.99-4.94,4.68-.05,.46-.39,1.04-.79,1.3-1.34,.97-2.78,1.85-4.17,2.76-2.27,1.46-4.54,2.94-6.84,4.45h-.02c-.49,.3-.97,.63-1.46,.95-2.9-2.87-3.5-3.36-5.52-3.94-.63-.19-.93-.42-1.04-.86-.05-.16-.07-.37-.07-.63,.05-5.96,.05-11.91,0-17.85,0-.07,0-.12,.02-.16,0-.74,.25-1.25,.9-1.72,2.57-1.95,2.6-5.75,.12-7.72-2.09-1.67-5.24-1.37-6.86,.63-1.78,2.23-1.44,5.38,.72,7.14,.44,.35,.93,.95,.93,1.44v.21c.07,6.07,.05,12.17,.07,18.24,0,.14,0,.25-.05,.37-.07,.44-.32,.65-.83,.76-1.99,.49-3.62,1.62-4.91,3.2-.6,.74-1.04,.79-1.83,.28-.19-.12-.37-.23-.56-.37h-.02c-3.5-2.29-7-4.54-10.52-6.77-.76-.49-1.16-.97-1.25-1.95-.35-2.97-3.11-4.96-5.86-4.33-2.74,.63-4.4,3.57-3.57,6.31,.83,2.69,3.89,4.01,6.68,2.92,.39-.14,1.02-.09,1.37,.14,2.11,1.34,4.22,2.71,6.31,4.06,1.09,.72,2.18,1.41,3.27,2.11,.95,.63,1.88,1.23,2.83,1.83,.19,.12,.3,.23,.39,.35-.72,.02-1.41,.07-2.13,.12-1.46,.05-2.9,.14-4.33,.23-1.11,.09-2.23,.16-3.34,.25-1.09,.07-2.2,.16-3.27,.28-.12,.02-.21,.02-.32,.02-.02,.02-.05,.02-.07,0-2.25-.16-4.29-.72-6.1-1.65-1.02-.53-1.99-1.18-2.9-1.97-1.53-1.25-2.85-2.85-4.03-4.71-3.04-4.8-3.66-10.15-3.41-15.69,.02-.32,.46-.81,.81-.93,1.99-.65,3.99-1.37,6.03-1.81,8-1.78,14.23,.67,18.94,7.39,1.37,1.97,2.6,3.99,3.92,5.98,.23,.35,.51,.74,.86,.93,1.18,.63,2.76,.25,3.57-.76,.86-1.07,.81-2.27-.02-3.5-1.21-1.72-2.46-3.41-3.52-5.22-1.53-2.55-2.34-5.29-2.53-8.11-.12-1.53-.02-3.06,.21-4.64,.51-3.36,1.74-6.26,3.45-8.79,2.02-2.99,4.75-5.47,7.93-7.63,.67-.44,1.23-.44,1.83,.07,1.92,1.65,4.03,3.11,5.73,4.96,.76,.83,1.46,1.72,2.11,2.62,2.71,3.99,4.08,8.67,3.73,13.38h-.02c-.28,3.41-1.48,6.84-3.71,10.04-.83,1.21-1.74,2.36-2.57,3.57-.81,1.18-.49,3.01,.67,3.82s3.11,.46,3.89-.72c1.07-1.62,2.11-3.27,3.15-4.91,2.55-4.08,5.86-7.16,10.64-8.44,5.42-1.48,10.5,.07,15.55,1.88,.23,.09,.46,.53,.46,.81,.19,5.35-.32,10.59-3.2,15.28Z"/>' +
|
|
7
|
+
'<path fill="currentColor" d="M171.29,112.7c0,1.48-.05,2.97-.12,4.43-.05,.93-.12,1.85-.19,2.76-.07,.88-.16,1.76-.28,2.64-8.28-7.19-24.64-13.03-45.32-16.23,.76-.63,1.48-1.28,2.16-1.97,.65-.65,1.27-1.34,1.83-2.06,2.25-2.78,3.89-5.98,4.96-9.57,1.65-5.63,1.04-11.43,1.39-17.15,.02-.32-.51-.86-.88-1-2.32-.83-4.66-1.55-6.98-2.36-6.61-2.32-13.19-3.04-19.84-.16-.09,.02-.23,0-.32,0-.07-.09-.14-.14-.14-.21-.02-.09-.05-.19-.05-.3-.02-.14-.02-.28-.05-.42-.32-4.8-1.88-9.16-4.47-13.14-.28-.46-.6-.93-.93-1.39-3.48-4.84-8.18-8.25-13.21-11.27-.35-.21-1.11-.12-1.48,.14-2.76,1.88-5.63,3.62-8.14,5.8-2.29,2.02-4.27,4.22-5.84,6.65-2.16,3.36-3.59,7.12-4.2,11.34-.12,.74-.19,1.48-.26,2.27,0,.19-.02,.39-.05,.6-.42-.09-.67-.14-.93-.25-4.82-2.06-9.83-2.18-14.81-.93-3.99,1-7.88,2.41-11.78,3.73-.32,.12-.63,.79-.6,1.21,.12,4.08,.09,8.18,.49,12.24,.53,5.38,2.43,10.15,5.82,14.23,.56,.7,1.18,1.37,1.83,2.02,.72,.7,1.46,1.34,2.2,2.02-1.85,.28-3.66,.6-5.42,.93-.86,.16-1.69,.32-2.53,.49-1.88,.37-3.73,.79-5.52,1.21-.9,.19-1.78,.39-2.64,.65-13.07,3.29-23.27,7.81-29.23,13.03-.09-.9-.19-1.83-.25-2.76-.09-.9-.16-1.83-.19-2.76v-.02c-.09-1.46-.14-2.92-.14-4.4,0-32.04,18.13-59.83,44.69-73.67,4.54-2.39,9.36-4.36,14.37-5.86,7.6-2.29,15.65-3.52,23.99-3.52s16.39,1.23,23.97,3.52c5.03,1.51,9.83,3.48,14.39,5.86,26.54,13.86,44.67,41.66,44.67,73.67Z"/>' +
|
|
8
|
+
"</svg>";
|
|
9
|
+
|
|
10
|
+
export function panelMarkup(apiBase, apiKey) {
|
|
11
|
+
return (
|
|
12
|
+
'<div class="suzu-panel" id="suzu-panel" aria-hidden="true" data-api-url="' +
|
|
13
|
+
escapeAttr(apiBase) +
|
|
14
|
+
'" data-api-key="' +
|
|
15
|
+
escapeAttr(apiKey) +
|
|
16
|
+
'">' +
|
|
17
|
+
'<button class="suzu-panel__dim" type="button" data-suzu-panel-close aria-label="Закрыть"></button>' +
|
|
18
|
+
'<button class="suzu-panel__chats-dim" type="button" data-suzu-chats-close aria-label="Закрыть чаты"></button>' +
|
|
19
|
+
'<aside class="suzu-panel__chats" id="suzu-panel-chats">' +
|
|
20
|
+
'<div class="suzu-ui__chats-head">' +
|
|
21
|
+
'<span class="suzu-ui__chats-title">Чаты</span>' +
|
|
22
|
+
'<button type="button" class="suzu-ui__new" id="suzu-panel-new" aria-label="Новый чат">' +
|
|
23
|
+
'<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>' +
|
|
24
|
+
"</button>" +
|
|
25
|
+
'<button type="button" class="suzu-panel__chats-x" data-suzu-chats-close aria-label="Закрыть чаты">×</button>' +
|
|
26
|
+
"</div>" +
|
|
27
|
+
'<div id="suzu-panel-chat-list"></div>' +
|
|
28
|
+
"</aside>" +
|
|
29
|
+
'<div class="suzu-panel__sheet" role="dialog" aria-modal="true" aria-label="Ассистент SUZU">' +
|
|
30
|
+
'<div class="suzu-panel__grab" aria-hidden="true"></div>' +
|
|
31
|
+
'<div class="suzu-panel__main">' +
|
|
32
|
+
'<header class="suzu-ui__bar suzu-panel__bar">' +
|
|
33
|
+
'<button class="suzu-panel__burger" type="button" data-suzu-chats-open aria-label="Чаты">' +
|
|
34
|
+
'<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">' +
|
|
35
|
+
'<path d="M4.5 7h15M4.5 12h15M4.5 17h15" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>' +
|
|
36
|
+
"</svg>" +
|
|
37
|
+
"</button>" +
|
|
38
|
+
'<span class="suzu-panel__title">Ассистент</span>' +
|
|
39
|
+
'<button class="suzu-ui__close" type="button" data-suzu-panel-close aria-label="Закрыть">×</button>' +
|
|
40
|
+
"</header>" +
|
|
41
|
+
'<div class="suzu-panel__thread" id="suzu-panel-thread">' +
|
|
42
|
+
'<div class="suzu-panel__empty" id="suzu-panel-empty">' +
|
|
43
|
+
"<h3>Привет!</h3>" +
|
|
44
|
+
"<p>Чем могу помочь?</p>" +
|
|
45
|
+
'<div class="suzu-panel__suggest" id="suzu-panel-suggest"></div>' +
|
|
46
|
+
"</div>" +
|
|
47
|
+
"</div>" +
|
|
48
|
+
'<div class="suzu-panel__pills" id="suzu-panel-pills" hidden></div>' +
|
|
49
|
+
'<form class="suzu-glow suzu-glow--composer" id="suzu-panel-form">' +
|
|
50
|
+
'<div class="suzu-glow__inner">' +
|
|
51
|
+
'<input type="text" placeholder="Опишите, что ищете" aria-label="Запрос" data-suzu-draft autocomplete="off" autocapitalize="none" autocorrect="off" spellcheck="false" enterkeyhint="send">' +
|
|
52
|
+
'<button type="submit" aria-label="Отправить">' +
|
|
53
|
+
LOGO +
|
|
54
|
+
"</button>" +
|
|
55
|
+
"</div>" +
|
|
56
|
+
"</form>" +
|
|
57
|
+
"</div>" +
|
|
58
|
+
'<div class="suzu-panel__resize" role="separator" aria-orientation="vertical" aria-label="Изменить ширину панели">' +
|
|
59
|
+
'<span class="suzu-panel__grip" aria-hidden="true"></span>' +
|
|
60
|
+
"</div>" +
|
|
61
|
+
'<div class="suzu-product" id="suzu-product" hidden>' +
|
|
62
|
+
'<button class="suzu-product__dim" type="button" data-suzu-product-close aria-label="Закрыть карточку"></button>' +
|
|
63
|
+
'<div class="suzu-product__card" role="dialog" aria-modal="true" aria-label="Товар">' +
|
|
64
|
+
'<button class="suzu-product__x" type="button" data-suzu-product-close aria-label="Закрыть">×</button>' +
|
|
65
|
+
'<div class="suzu-product__media"></div>' +
|
|
66
|
+
'<div class="suzu-product__body"></div>' +
|
|
67
|
+
"</div>" +
|
|
68
|
+
"</div>" +
|
|
69
|
+
"</div>" +
|
|
70
|
+
"</div>"
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function launcherMarkup() {
|
|
75
|
+
return (
|
|
76
|
+
'<button type="button" class="suzu-launcher" id="suzu-launcher" aria-label="Открыть ассистента">' +
|
|
77
|
+
LOGO +
|
|
78
|
+
"</button>"
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function escapeAttr(value) {
|
|
83
|
+
return String(value || "")
|
|
84
|
+
.replace(/&/g, "&")
|
|
85
|
+
.replace(/"/g, """)
|
|
86
|
+
.replace(/</g, "<");
|
|
87
|
+
}
|