clay-server 2.12.0 → 2.13.0-beta.1
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/lib/daemon.js +14 -0
- package/lib/dm.js +3 -3
- package/lib/mates.js +222 -0
- package/lib/project.js +83 -2
- package/lib/public/app.js +273 -10
- package/lib/public/css/base.css +1 -0
- package/lib/public/css/mates.css +1018 -0
- package/lib/public/index.html +238 -0
- package/lib/public/modules/mate-knowledge.js +222 -0
- package/lib/public/modules/mate-sidebar.js +329 -0
- package/lib/public/modules/mate-wizard.js +265 -0
- package/lib/public/modules/profile.js +207 -0
- package/lib/public/modules/sidebar.js +143 -3
- package/lib/public/style.css +1 -0
- package/lib/sdk-bridge.js +4 -0
- package/lib/server.js +110 -3
- package/lib/sessions.js +27 -0
- package/package.json +1 -1
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { escapeHtml } from './utils.js';
|
|
2
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
3
|
+
import { hideKnowledge } from './mate-knowledge.js';
|
|
4
|
+
|
|
5
|
+
var getMateWs = null;
|
|
6
|
+
var currentMateId = null;
|
|
7
|
+
var currentMate = null;
|
|
8
|
+
var cachedSessions = [];
|
|
9
|
+
|
|
10
|
+
var columnEl = null;
|
|
11
|
+
var listEl = null;
|
|
12
|
+
var avatarEl = null;
|
|
13
|
+
var nameEl = null;
|
|
14
|
+
var newSessionBtn = null;
|
|
15
|
+
|
|
16
|
+
export function initMateSidebar(mateWsGetter) {
|
|
17
|
+
getMateWs = mateWsGetter;
|
|
18
|
+
columnEl = document.getElementById("mate-sidebar-column");
|
|
19
|
+
listEl = document.getElementById("mate-session-list");
|
|
20
|
+
avatarEl = document.getElementById("mate-sidebar-avatar");
|
|
21
|
+
nameEl = document.getElementById("mate-sidebar-name");
|
|
22
|
+
newSessionBtn = document.getElementById("mate-new-session-btn");
|
|
23
|
+
|
|
24
|
+
if (newSessionBtn) {
|
|
25
|
+
newSessionBtn.addEventListener("click", function () {
|
|
26
|
+
var ws = getMateWs ? getMateWs() : null;
|
|
27
|
+
if (ws && ws.readyState === 1) {
|
|
28
|
+
ws.send(JSON.stringify({ type: "new_session" }));
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Header click: toggle seed data panel
|
|
34
|
+
var headerEl = document.getElementById("mate-sidebar-header");
|
|
35
|
+
if (headerEl) {
|
|
36
|
+
headerEl.addEventListener("click", function () {
|
|
37
|
+
var seedPanel = document.getElementById("mate-sidebar-seed");
|
|
38
|
+
if (!seedPanel) return;
|
|
39
|
+
var expanded = !seedPanel.classList.contains("hidden");
|
|
40
|
+
if (expanded) {
|
|
41
|
+
seedPanel.classList.add("hidden");
|
|
42
|
+
headerEl.classList.remove("expanded");
|
|
43
|
+
} else {
|
|
44
|
+
seedPanel.classList.remove("hidden");
|
|
45
|
+
headerEl.classList.add("expanded");
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Tools: reuse existing project sidebar buttons
|
|
51
|
+
var mateStickyBtn = document.getElementById("mate-sticky-notes-btn");
|
|
52
|
+
if (mateStickyBtn) {
|
|
53
|
+
mateStickyBtn.addEventListener("click", function () {
|
|
54
|
+
hideKnowledge();
|
|
55
|
+
var origBtn = document.getElementById("sticky-notes-sidebar-btn");
|
|
56
|
+
if (origBtn) origBtn.click();
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
var mateSkillsBtn = document.getElementById("mate-skills-btn");
|
|
60
|
+
if (mateSkillsBtn) {
|
|
61
|
+
mateSkillsBtn.addEventListener("click", function () {
|
|
62
|
+
var origBtn = document.getElementById("skills-btn");
|
|
63
|
+
if (origBtn) origBtn.click();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function showMateSidebar(mateId, mateData) {
|
|
69
|
+
currentMateId = mateId;
|
|
70
|
+
currentMate = mateData;
|
|
71
|
+
cachedSessions = [];
|
|
72
|
+
|
|
73
|
+
if (!columnEl) return;
|
|
74
|
+
columnEl.classList.remove("hidden");
|
|
75
|
+
|
|
76
|
+
// Populate header
|
|
77
|
+
var profile = mateData.profile || mateData || {};
|
|
78
|
+
var displayName = profile.displayName || mateData.displayName || mateData.name || "Mate";
|
|
79
|
+
var avatarStyle = profile.avatarStyle || "bottts";
|
|
80
|
+
var avatarSeed = profile.avatarSeed || mateId;
|
|
81
|
+
|
|
82
|
+
var mateColor = profile.avatarColor || mateData.avatarColor || "#7c3aed";
|
|
83
|
+
|
|
84
|
+
if (avatarEl) {
|
|
85
|
+
avatarEl.src = "https://api.dicebear.com/9.x/" + encodeURIComponent(avatarStyle) + "/svg?seed=" + encodeURIComponent(avatarSeed) + "&size=32";
|
|
86
|
+
}
|
|
87
|
+
if (nameEl) nameEl.textContent = displayName;
|
|
88
|
+
|
|
89
|
+
// Apply mate color to sidebar
|
|
90
|
+
var headerEl = columnEl.querySelector(".mate-sidebar-header");
|
|
91
|
+
if (headerEl) headerEl.style.background = mateColor;
|
|
92
|
+
columnEl.style.background = mateColor + "0a";
|
|
93
|
+
|
|
94
|
+
// Render seed data panel
|
|
95
|
+
var seedPanel = document.getElementById("mate-sidebar-seed");
|
|
96
|
+
var headerClickEl = document.getElementById("mate-sidebar-header");
|
|
97
|
+
if (seedPanel) {
|
|
98
|
+
seedPanel.innerHTML = "";
|
|
99
|
+
seedPanel.classList.add("hidden");
|
|
100
|
+
if (headerClickEl) headerClickEl.classList.remove("expanded");
|
|
101
|
+
var sd = mateData.seedData || {};
|
|
102
|
+
if (sd.relationship) {
|
|
103
|
+
seedPanel.appendChild(makeSeedRow("Role", sd.relationship.replace(/_/g, " ")));
|
|
104
|
+
}
|
|
105
|
+
if (sd.activity && sd.activity.length > 0) {
|
|
106
|
+
seedPanel.appendChild(makeSeedTags("Activities", sd.activity));
|
|
107
|
+
}
|
|
108
|
+
if (sd.communicationStyle && sd.communicationStyle.length > 0) {
|
|
109
|
+
seedPanel.appendChild(makeSeedTags("Style", sd.communicationStyle.map(function (s) { return s.replace(/_/g, " "); })));
|
|
110
|
+
}
|
|
111
|
+
if (sd.autonomy) {
|
|
112
|
+
var autonomyLabels = {
|
|
113
|
+
always_ask: "Ask me everything",
|
|
114
|
+
minor_stuff_ok: "Small stuff is fine",
|
|
115
|
+
mostly_autonomous: "Mostly free",
|
|
116
|
+
fully_autonomous: "Full freedom",
|
|
117
|
+
};
|
|
118
|
+
seedPanel.appendChild(makeSeedRow("Autonomy", autonomyLabels[sd.autonomy] || sd.autonomy.replace(/_/g, " ")));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Clear session list
|
|
123
|
+
if (listEl) listEl.innerHTML = "";
|
|
124
|
+
refreshIcons();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function makeSeedRow(label, value) {
|
|
128
|
+
var row = document.createElement("div");
|
|
129
|
+
row.className = "mate-sidebar-seed-row";
|
|
130
|
+
row.innerHTML = '<span class="mate-sidebar-seed-label">' + escapeHtml(label) + '</span><span class="mate-sidebar-seed-value">' + escapeHtml(value) + '</span>';
|
|
131
|
+
return row;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function makeSeedTags(label, items) {
|
|
135
|
+
var row = document.createElement("div");
|
|
136
|
+
row.className = "mate-sidebar-seed-row";
|
|
137
|
+
var labelEl = document.createElement("span");
|
|
138
|
+
labelEl.className = "mate-sidebar-seed-label";
|
|
139
|
+
labelEl.textContent = label;
|
|
140
|
+
row.appendChild(labelEl);
|
|
141
|
+
var tagsEl = document.createElement("div");
|
|
142
|
+
tagsEl.className = "mate-sidebar-seed-tags";
|
|
143
|
+
for (var i = 0; i < items.length; i++) {
|
|
144
|
+
var tag = document.createElement("span");
|
|
145
|
+
tag.className = "mate-sidebar-seed-tag";
|
|
146
|
+
tag.textContent = items[i];
|
|
147
|
+
tagsEl.appendChild(tag);
|
|
148
|
+
}
|
|
149
|
+
row.appendChild(tagsEl);
|
|
150
|
+
return row;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function updateMateSidebarProfile(mateData) {
|
|
154
|
+
if (!columnEl || !mateData) return;
|
|
155
|
+
var profile = mateData.profile || mateData || {};
|
|
156
|
+
var displayName = profile.displayName || mateData.displayName || mateData.name || "Mate";
|
|
157
|
+
var avatarStyle = profile.avatarStyle || "bottts";
|
|
158
|
+
var avatarSeed = profile.avatarSeed || (mateData.id || "mate");
|
|
159
|
+
var mateColor = profile.avatarColor || mateData.avatarColor || "#7c3aed";
|
|
160
|
+
|
|
161
|
+
if (avatarEl) {
|
|
162
|
+
avatarEl.src = "https://api.dicebear.com/9.x/" + encodeURIComponent(avatarStyle) + "/svg?seed=" + encodeURIComponent(avatarSeed) + "&size=32";
|
|
163
|
+
}
|
|
164
|
+
// Check if name changed for engrave effect
|
|
165
|
+
var oldName = nameEl ? nameEl.textContent : "";
|
|
166
|
+
if (nameEl && displayName !== oldName && oldName !== displayName) {
|
|
167
|
+
engraveText(nameEl, displayName, mateColor);
|
|
168
|
+
} else if (nameEl) {
|
|
169
|
+
nameEl.textContent = displayName;
|
|
170
|
+
}
|
|
171
|
+
var headerEl = columnEl.querySelector(".mate-sidebar-header");
|
|
172
|
+
if (headerEl) headerEl.style.background = mateColor;
|
|
173
|
+
columnEl.style.background = mateColor + "0a";
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Ten Commandments engrave effect: letters appear one by one with spark particles
|
|
177
|
+
var engraveTimers = [];
|
|
178
|
+
var engraveTarget = null;
|
|
179
|
+
|
|
180
|
+
function engraveText(el, text, color) {
|
|
181
|
+
// Cancel any pending engrave
|
|
182
|
+
for (var t = 0; t < engraveTimers.length; t++) {
|
|
183
|
+
clearTimeout(engraveTimers[t]);
|
|
184
|
+
}
|
|
185
|
+
engraveTimers = [];
|
|
186
|
+
|
|
187
|
+
// Skip if already engraving to the same name
|
|
188
|
+
if (engraveTarget === text) return;
|
|
189
|
+
engraveTarget = text;
|
|
190
|
+
|
|
191
|
+
el.textContent = "";
|
|
192
|
+
el.style.position = "relative";
|
|
193
|
+
var chars = text.split("");
|
|
194
|
+
var step = 80;
|
|
195
|
+
|
|
196
|
+
// Flash the header background
|
|
197
|
+
var headerEl = columnEl ? columnEl.querySelector(".mate-sidebar-header") : null;
|
|
198
|
+
if (headerEl) {
|
|
199
|
+
headerEl.style.animation = "none";
|
|
200
|
+
void headerEl.offsetWidth; // reflow
|
|
201
|
+
headerEl.style.animation = "engrave-header-flash 0.8s ease-out";
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for (var i = 0; i < chars.length; i++) {
|
|
205
|
+
(function (ch, idx) {
|
|
206
|
+
var tid = setTimeout(function () {
|
|
207
|
+
var span = document.createElement("span");
|
|
208
|
+
span.textContent = ch;
|
|
209
|
+
span.style.opacity = "0";
|
|
210
|
+
span.style.display = "inline-block";
|
|
211
|
+
span.style.animation = "engrave-char 0.5s ease-out forwards";
|
|
212
|
+
el.appendChild(span);
|
|
213
|
+
|
|
214
|
+
// Spawn spark particles at character position
|
|
215
|
+
var tid2 = setTimeout(function () {
|
|
216
|
+
var rect = span.getBoundingClientRect();
|
|
217
|
+
spawnSparks(rect.left + rect.width / 2, rect.top + rect.height / 2, color);
|
|
218
|
+
}, 30);
|
|
219
|
+
engraveTimers.push(tid2);
|
|
220
|
+
}, idx * step);
|
|
221
|
+
engraveTimers.push(tid);
|
|
222
|
+
})(chars[i], i);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function spawnSparks(cx, cy) {
|
|
227
|
+
var sparkColors = ["#fff700", "#ff8c00", "#ff4500", "#fffbe6", "#ffdd57"];
|
|
228
|
+
var count = 8;
|
|
229
|
+
for (var i = 0; i < count; i++) {
|
|
230
|
+
var spark = document.createElement("div");
|
|
231
|
+
spark.className = "mate-engrave-spark";
|
|
232
|
+
var angle = (Math.PI * 2 * i) / count + (Math.random() - 0.5) * 1.0;
|
|
233
|
+
var dist = 10 + Math.random() * 18;
|
|
234
|
+
var dx = Math.cos(angle) * dist;
|
|
235
|
+
var dy = Math.sin(angle) * dist;
|
|
236
|
+
var sc = sparkColors[Math.floor(Math.random() * sparkColors.length)];
|
|
237
|
+
spark.style.left = cx + "px";
|
|
238
|
+
spark.style.top = cy + "px";
|
|
239
|
+
spark.style.setProperty("--dx", dx + "px");
|
|
240
|
+
spark.style.setProperty("--dy", dy + "px");
|
|
241
|
+
spark.style.setProperty("--spark-color", sc);
|
|
242
|
+
spark.style.background = sc;
|
|
243
|
+
document.body.appendChild(spark);
|
|
244
|
+
spark.addEventListener("animationend", function () { spark.remove(); });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function hideMateSidebar() {
|
|
249
|
+
currentMateId = null;
|
|
250
|
+
currentMate = null;
|
|
251
|
+
cachedSessions = [];
|
|
252
|
+
if (columnEl) columnEl.classList.add("hidden");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function renderMateSessionList(sessions) {
|
|
256
|
+
cachedSessions = sessions || [];
|
|
257
|
+
if (!listEl) return;
|
|
258
|
+
listEl.innerHTML = "";
|
|
259
|
+
|
|
260
|
+
if (cachedSessions.length === 0) {
|
|
261
|
+
var empty = document.createElement("div");
|
|
262
|
+
empty.className = "mate-session-empty";
|
|
263
|
+
empty.textContent = "No sessions yet";
|
|
264
|
+
listEl.appendChild(empty);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
for (var i = 0; i < cachedSessions.length; i++) {
|
|
269
|
+
var s = cachedSessions[i];
|
|
270
|
+
listEl.appendChild(renderMateSessionItem(s));
|
|
271
|
+
}
|
|
272
|
+
refreshIcons();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function renderMateSessionItem(s) {
|
|
276
|
+
var el = document.createElement("div");
|
|
277
|
+
el.className = "mate-session-item" + (s.active ? " active" : "");
|
|
278
|
+
el.dataset.sessionId = s.id;
|
|
279
|
+
|
|
280
|
+
var textSpan = document.createElement("span");
|
|
281
|
+
textSpan.className = "mate-session-item-text";
|
|
282
|
+
var html = "";
|
|
283
|
+
if (s.isProcessing) {
|
|
284
|
+
html += '<span class="mate-session-processing"></span>';
|
|
285
|
+
}
|
|
286
|
+
html += escapeHtml(s.title || "New Session");
|
|
287
|
+
textSpan.innerHTML = html;
|
|
288
|
+
el.appendChild(textSpan);
|
|
289
|
+
|
|
290
|
+
// Relative time
|
|
291
|
+
if (s.lastActivity) {
|
|
292
|
+
var timeSpan = document.createElement("span");
|
|
293
|
+
timeSpan.className = "mate-session-time";
|
|
294
|
+
timeSpan.textContent = relativeTime(s.lastActivity);
|
|
295
|
+
el.appendChild(timeSpan);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
el.addEventListener("click", (function (id) {
|
|
299
|
+
return function () {
|
|
300
|
+
var ws = getMateWs ? getMateWs() : null;
|
|
301
|
+
if (ws && ws.readyState === 1) {
|
|
302
|
+
ws.send(JSON.stringify({ type: "switch_session", id: id }));
|
|
303
|
+
}
|
|
304
|
+
// Update active state visually
|
|
305
|
+
var items = listEl.querySelectorAll(".mate-session-item");
|
|
306
|
+
for (var j = 0; j < items.length; j++) {
|
|
307
|
+
items[j].classList.remove("active");
|
|
308
|
+
}
|
|
309
|
+
el.classList.add("active");
|
|
310
|
+
};
|
|
311
|
+
})(s.id));
|
|
312
|
+
|
|
313
|
+
return el;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function relativeTime(ts) {
|
|
317
|
+
var now = Date.now();
|
|
318
|
+
var diff = now - ts;
|
|
319
|
+
var sec = Math.floor(diff / 1000);
|
|
320
|
+
if (sec < 60) return "now";
|
|
321
|
+
var min = Math.floor(sec / 60);
|
|
322
|
+
if (min < 60) return min + "m";
|
|
323
|
+
var hr = Math.floor(min / 60);
|
|
324
|
+
if (hr < 24) return hr + "h";
|
|
325
|
+
var day = Math.floor(hr / 24);
|
|
326
|
+
if (day < 30) return day + "d";
|
|
327
|
+
var month = Math.floor(day / 30);
|
|
328
|
+
return month + "mo";
|
|
329
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// Mate Wizard Module
|
|
2
|
+
// Handles the 4-step wizard for creating a new Mate
|
|
3
|
+
|
|
4
|
+
var mateWizardStep = 1;
|
|
5
|
+
var mateWizardData = {
|
|
6
|
+
relationship: null,
|
|
7
|
+
activity: [],
|
|
8
|
+
communicationStyle: [],
|
|
9
|
+
autonomy: "minor_stuff_ok",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
var _sendWs = null;
|
|
13
|
+
var _onMateCreated = null;
|
|
14
|
+
|
|
15
|
+
export function initMateWizard(sendWs, onMateCreated) {
|
|
16
|
+
_sendWs = sendWs;
|
|
17
|
+
_onMateCreated = onMateCreated;
|
|
18
|
+
|
|
19
|
+
// Button listeners
|
|
20
|
+
var closeBtn = document.getElementById("mate-wizard-close");
|
|
21
|
+
var backdrop = document.querySelector(".mate-wizard-backdrop");
|
|
22
|
+
var backBtn = document.getElementById("mate-wizard-back");
|
|
23
|
+
var nextBtn = document.getElementById("mate-wizard-next");
|
|
24
|
+
|
|
25
|
+
if (closeBtn) closeBtn.addEventListener("click", closeMateWizard);
|
|
26
|
+
if (backdrop) backdrop.addEventListener("click", closeMateWizard);
|
|
27
|
+
if (backBtn) backBtn.addEventListener("click", mateWizardBack);
|
|
28
|
+
if (nextBtn) nextBtn.addEventListener("click", mateWizardNext);
|
|
29
|
+
|
|
30
|
+
// Step 1: Relationship card clicks
|
|
31
|
+
var cards = document.querySelectorAll("#mate-wizard .mate-card");
|
|
32
|
+
for (var i = 0; i < cards.length; i++) {
|
|
33
|
+
(function (card) {
|
|
34
|
+
card.addEventListener("click", function () {
|
|
35
|
+
// Deselect all
|
|
36
|
+
var allCards = document.querySelectorAll("#mate-wizard .mate-card");
|
|
37
|
+
for (var j = 0; j < allCards.length; j++) {
|
|
38
|
+
allCards[j].classList.remove("selected");
|
|
39
|
+
}
|
|
40
|
+
card.classList.add("selected");
|
|
41
|
+
mateWizardData.relationship = card.dataset.value;
|
|
42
|
+
|
|
43
|
+
// Show/hide custom input
|
|
44
|
+
var customInput = document.getElementById("mate-relationship-custom");
|
|
45
|
+
if (customInput) {
|
|
46
|
+
if (card.dataset.value === "custom") {
|
|
47
|
+
customInput.classList.remove("hidden");
|
|
48
|
+
customInput.focus();
|
|
49
|
+
} else {
|
|
50
|
+
customInput.classList.add("hidden");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
})(cards[i]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Step 2: Activity tag clicks
|
|
58
|
+
var tags = document.querySelectorAll("#mate-wizard .mate-tag");
|
|
59
|
+
for (var i = 0; i < tags.length; i++) {
|
|
60
|
+
(function (tag) {
|
|
61
|
+
tag.addEventListener("click", function () {
|
|
62
|
+
tag.classList.toggle("selected");
|
|
63
|
+
});
|
|
64
|
+
})(tags[i]);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Step 2: Custom activity input (just a free-text field, collected on submit)
|
|
68
|
+
var activityCustom = document.getElementById("mate-activity-custom");
|
|
69
|
+
if (activityCustom) {
|
|
70
|
+
activityCustom.addEventListener("keydown", function (e) {
|
|
71
|
+
e.stopPropagation();
|
|
72
|
+
if (e.key === "Enter") e.preventDefault();
|
|
73
|
+
});
|
|
74
|
+
activityCustom.addEventListener("keyup", function (e) { e.stopPropagation(); });
|
|
75
|
+
activityCustom.addEventListener("keypress", function (e) { e.stopPropagation(); });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Step 3: Communication style card clicks (multi-select)
|
|
79
|
+
var styleCards = document.querySelectorAll("#mate-wizard .mate-style-card");
|
|
80
|
+
for (var i = 0; i < styleCards.length; i++) {
|
|
81
|
+
(function (card) {
|
|
82
|
+
card.addEventListener("click", function () {
|
|
83
|
+
card.classList.toggle("selected");
|
|
84
|
+
});
|
|
85
|
+
})(styleCards[i]);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Step 4: Autonomy button clicks
|
|
89
|
+
var autonomyBtns = document.querySelectorAll("#mate-wizard .mate-autonomy-btn");
|
|
90
|
+
for (var i = 0; i < autonomyBtns.length; i++) {
|
|
91
|
+
(function (btn) {
|
|
92
|
+
btn.addEventListener("click", function () {
|
|
93
|
+
var allBtns = document.querySelectorAll("#mate-wizard .mate-autonomy-btn");
|
|
94
|
+
for (var j = 0; j < allBtns.length; j++) {
|
|
95
|
+
allBtns[j].classList.remove("active");
|
|
96
|
+
}
|
|
97
|
+
btn.classList.add("active");
|
|
98
|
+
mateWizardData.autonomy = btn.dataset.value;
|
|
99
|
+
});
|
|
100
|
+
})(autonomyBtns[i]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function openMateWizard() {
|
|
105
|
+
mateWizardStep = 1;
|
|
106
|
+
mateWizardData = {
|
|
107
|
+
relationship: null,
|
|
108
|
+
activity: [],
|
|
109
|
+
communicationStyle: [],
|
|
110
|
+
autonomy: "minor_stuff_ok",
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Reset UI
|
|
114
|
+
var el = document.getElementById("mate-wizard");
|
|
115
|
+
if (!el) return;
|
|
116
|
+
|
|
117
|
+
// Reset cards
|
|
118
|
+
var cards = el.querySelectorAll(".mate-card");
|
|
119
|
+
for (var i = 0; i < cards.length; i++) {
|
|
120
|
+
cards[i].classList.remove("selected");
|
|
121
|
+
}
|
|
122
|
+
var customInput = document.getElementById("mate-relationship-custom");
|
|
123
|
+
if (customInput) { customInput.classList.add("hidden"); customInput.value = ""; }
|
|
124
|
+
|
|
125
|
+
// Reset tags
|
|
126
|
+
var tags = el.querySelectorAll(".mate-tag");
|
|
127
|
+
for (var i = 0; i < tags.length; i++) {
|
|
128
|
+
tags[i].classList.remove("selected");
|
|
129
|
+
}
|
|
130
|
+
var activityCustom = document.getElementById("mate-activity-custom");
|
|
131
|
+
if (activityCustom) activityCustom.value = "";
|
|
132
|
+
|
|
133
|
+
// Reset style cards
|
|
134
|
+
var styleCards = el.querySelectorAll(".mate-style-card");
|
|
135
|
+
for (var i = 0; i < styleCards.length; i++) {
|
|
136
|
+
styleCards[i].classList.remove("selected");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Reset autonomy
|
|
140
|
+
var autonomyBtns = el.querySelectorAll(".mate-autonomy-btn");
|
|
141
|
+
for (var i = 0; i < autonomyBtns.length; i++) {
|
|
142
|
+
autonomyBtns[i].classList.remove("active");
|
|
143
|
+
if (autonomyBtns[i].dataset.value === "minor_stuff_ok") {
|
|
144
|
+
autonomyBtns[i].classList.add("active");
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
el.classList.remove("hidden");
|
|
149
|
+
updateMateWizardStep();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function closeMateWizard() {
|
|
153
|
+
var el = document.getElementById("mate-wizard");
|
|
154
|
+
if (el) el.classList.add("hidden");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function updateMateWizardStep() {
|
|
158
|
+
var steps = document.querySelectorAll("#mate-wizard .mate-step");
|
|
159
|
+
for (var i = 0; i < steps.length; i++) {
|
|
160
|
+
var stepNum = parseInt(steps[i].getAttribute("data-step"), 10);
|
|
161
|
+
if (stepNum === mateWizardStep) {
|
|
162
|
+
steps[i].classList.add("active");
|
|
163
|
+
} else {
|
|
164
|
+
steps[i].classList.remove("active");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
var dots = document.querySelectorAll("#mate-wizard .mate-dot");
|
|
169
|
+
for (var j = 0; j < dots.length; j++) {
|
|
170
|
+
var dotStep = parseInt(dots[j].getAttribute("data-step"), 10);
|
|
171
|
+
dots[j].classList.remove("active", "done");
|
|
172
|
+
if (dotStep === mateWizardStep) dots[j].classList.add("active");
|
|
173
|
+
else if (dotStep < mateWizardStep) dots[j].classList.add("done");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
var backBtn = document.getElementById("mate-wizard-back");
|
|
177
|
+
var nextBtn = document.getElementById("mate-wizard-next");
|
|
178
|
+
if (backBtn) backBtn.style.visibility = mateWizardStep === 1 ? "hidden" : "visible";
|
|
179
|
+
if (nextBtn) nextBtn.textContent = mateWizardStep === 4 ? "Create Mate" : "Next";
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function collectMateWizardData() {
|
|
183
|
+
// Relationship
|
|
184
|
+
var selectedCard = document.querySelector("#mate-wizard .mate-card.selected");
|
|
185
|
+
if (selectedCard) {
|
|
186
|
+
mateWizardData.relationship = selectedCard.dataset.value;
|
|
187
|
+
if (selectedCard.dataset.value === "custom") {
|
|
188
|
+
var customInput = document.getElementById("mate-relationship-custom");
|
|
189
|
+
if (customInput && customInput.value.trim()) {
|
|
190
|
+
mateWizardData.relationship = customInput.value.trim();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Activities
|
|
196
|
+
var selectedTags = document.querySelectorAll("#mate-wizard .mate-tag.selected");
|
|
197
|
+
mateWizardData.activity = [];
|
|
198
|
+
for (var i = 0; i < selectedTags.length; i++) {
|
|
199
|
+
mateWizardData.activity.push(selectedTags[i].dataset.value || selectedTags[i].textContent.toLowerCase());
|
|
200
|
+
}
|
|
201
|
+
var activityCustom = document.getElementById("mate-activity-custom");
|
|
202
|
+
if (activityCustom && activityCustom.value.trim()) {
|
|
203
|
+
mateWizardData.activity.push(activityCustom.value.trim());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Communication style (multi-select cards)
|
|
207
|
+
var selectedStyles = document.querySelectorAll("#mate-wizard .mate-style-card.selected");
|
|
208
|
+
mateWizardData.communicationStyle = [];
|
|
209
|
+
for (var i = 0; i < selectedStyles.length; i++) {
|
|
210
|
+
mateWizardData.communicationStyle.push(selectedStyles[i].dataset.value);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Autonomy (already set via button clicks)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function mateWizardNext() {
|
|
217
|
+
collectMateWizardData();
|
|
218
|
+
|
|
219
|
+
// Validate current step
|
|
220
|
+
if (mateWizardStep === 1) {
|
|
221
|
+
if (!mateWizardData.relationship) {
|
|
222
|
+
// Flash the cards to indicate selection needed
|
|
223
|
+
var grid = document.querySelector("#mate-wizard .mate-card-grid");
|
|
224
|
+
if (grid) {
|
|
225
|
+
grid.style.outline = "2px solid var(--error, #ff5555)";
|
|
226
|
+
grid.style.outlineOffset = "4px";
|
|
227
|
+
grid.style.borderRadius = "10px";
|
|
228
|
+
setTimeout(function () { grid.style.outline = ""; grid.style.outlineOffset = ""; }, 1500);
|
|
229
|
+
}
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (mateWizardStep < 4) {
|
|
235
|
+
mateWizardStep++;
|
|
236
|
+
updateMateWizardStep();
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Step 4: Submit
|
|
241
|
+
mateWizardSubmit();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function mateWizardBack() {
|
|
245
|
+
if (mateWizardStep > 1) {
|
|
246
|
+
collectMateWizardData();
|
|
247
|
+
mateWizardStep--;
|
|
248
|
+
updateMateWizardStep();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function mateWizardSubmit() {
|
|
253
|
+
collectMateWizardData();
|
|
254
|
+
closeMateWizard();
|
|
255
|
+
|
|
256
|
+
if (_sendWs) {
|
|
257
|
+
_sendWs({ type: "mate_create", seedData: mateWizardData });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function handleMateCreated(mate) {
|
|
262
|
+
if (_onMateCreated) {
|
|
263
|
+
_onMateCreated(mate);
|
|
264
|
+
}
|
|
265
|
+
}
|