clay-server 2.7.2 → 2.8.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/bin/cli.js +2 -1
- package/lib/config.js +7 -4
- package/lib/project.js +343 -15
- package/lib/public/app.js +1043 -135
- package/lib/public/apple-touch-icon-dark.png +0 -0
- package/lib/public/apple-touch-icon.png +0 -0
- package/lib/public/clay-logo.png +0 -0
- package/lib/public/css/base.css +10 -0
- package/lib/public/css/filebrowser.css +1 -0
- package/lib/public/css/home-hub.css +455 -0
- package/lib/public/css/icon-strip.css +6 -5
- package/lib/public/css/loop.css +141 -23
- package/lib/public/css/messages.css +2 -0
- package/lib/public/css/mobile-nav.css +38 -12
- package/lib/public/css/overlays.css +205 -169
- package/lib/public/css/playbook.css +264 -0
- package/lib/public/css/profile.css +268 -0
- package/lib/public/css/scheduler-modal.css +1429 -0
- package/lib/public/css/scheduler.css +1305 -0
- package/lib/public/css/sidebar.css +305 -11
- package/lib/public/css/sticky-notes.css +23 -19
- package/lib/public/css/stt.css +155 -0
- package/lib/public/css/title-bar.css +14 -6
- package/lib/public/favicon-banded-32.png +0 -0
- package/lib/public/favicon-banded.png +0 -0
- package/lib/public/icon-192-dark.png +0 -0
- package/lib/public/icon-192.png +0 -0
- package/lib/public/icon-512-dark.png +0 -0
- package/lib/public/icon-512.png +0 -0
- package/lib/public/icon-banded-76.png +0 -0
- package/lib/public/icon-banded-96.png +0 -0
- package/lib/public/index.html +335 -42
- package/lib/public/modules/ascii-logo.js +389 -0
- package/lib/public/modules/filebrowser.js +2 -1
- package/lib/public/modules/markdown.js +118 -0
- package/lib/public/modules/notifications.js +50 -63
- package/lib/public/modules/playbook.js +578 -0
- package/lib/public/modules/profile.js +357 -0
- package/lib/public/modules/project-settings.js +4 -9
- package/lib/public/modules/scheduler.js +2826 -0
- package/lib/public/modules/server-settings.js +1 -1
- package/lib/public/modules/sidebar.js +378 -31
- package/lib/public/modules/sticky-notes.js +2 -0
- package/lib/public/modules/stt.js +272 -0
- package/lib/public/modules/terminal.js +32 -0
- package/lib/public/modules/theme.js +3 -10
- package/lib/public/modules/tools.js +2 -1
- package/lib/public/style.css +6 -0
- package/lib/public/sw.js +82 -3
- package/lib/public/wordmark-banded-20.png +0 -0
- package/lib/public/wordmark-banded-32.png +0 -0
- package/lib/public/wordmark-banded-64.png +0 -0
- package/lib/public/wordmark-banded-80.png +0 -0
- package/lib/scheduler.js +402 -0
- package/lib/sdk-bridge.js +3 -2
- package/lib/server.js +124 -3
- package/lib/sessions.js +35 -2
- package/package.json +1 -1
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
// User profile module — Discord-style popover for name, language, avatar
|
|
2
|
+
// Stores profile server-side in ~/.clay/profile.json
|
|
3
|
+
// Avatar generated via DiceBear API (deterministic SVG from seed)
|
|
4
|
+
|
|
5
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
6
|
+
import { setSTTLang, getSTTLang } from './stt.js';
|
|
7
|
+
|
|
8
|
+
var ctx;
|
|
9
|
+
var profile = { name: '', lang: 'en-US', avatarStyle: 'thumbs', avatarSeed: '', avatarColor: '#7c3aed' };
|
|
10
|
+
var popoverEl = null;
|
|
11
|
+
var saveTimer = null;
|
|
12
|
+
var previewSeed = '';
|
|
13
|
+
|
|
14
|
+
var LANGUAGES = [
|
|
15
|
+
{ code: 'en-US', name: 'English' },
|
|
16
|
+
{ code: 'ko-KR', name: 'Korean' },
|
|
17
|
+
{ code: 'ja-JP', name: 'Japanese' },
|
|
18
|
+
{ code: 'zh-CN', name: 'Chinese' },
|
|
19
|
+
{ code: 'es-ES', name: 'Spanish' },
|
|
20
|
+
{ code: 'fr-FR', name: 'French' },
|
|
21
|
+
{ code: 'de-DE', name: 'German' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
var AVATAR_STYLES = [
|
|
25
|
+
{ id: 'thumbs', name: 'Thumbs' },
|
|
26
|
+
{ id: 'bottts', name: 'Bots' },
|
|
27
|
+
{ id: 'pixel-art', name: 'Pixel' },
|
|
28
|
+
{ id: 'adventurer', name: 'Adventurer' },
|
|
29
|
+
{ id: 'micah', name: 'Micah' },
|
|
30
|
+
{ id: 'lorelei', name: 'Lorelei' },
|
|
31
|
+
{ id: 'fun-emoji', name: 'Emoji' },
|
|
32
|
+
{ id: 'icons', name: 'Icons' },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
var COLORS = [
|
|
36
|
+
'#7c3aed', '#4f46e5', '#2563eb', '#0891b2',
|
|
37
|
+
'#059669', '#65a30d', '#d97706', '#dc2626',
|
|
38
|
+
'#db2777', '#6366f1', '#0d9488', '#ea580c',
|
|
39
|
+
'#475569', '#1e293b', '#be123c', '#a21caf',
|
|
40
|
+
'#0369a1', '#15803d',
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// --- DiceBear URL builder ---
|
|
44
|
+
function avatarUrl(style, seed, size) {
|
|
45
|
+
var s = encodeURIComponent(seed || 'anonymous');
|
|
46
|
+
return 'https://api.dicebear.com/9.x/' + style + '/svg?seed=' + s + '&size=' + (size || 64);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getAvatarSeed() {
|
|
50
|
+
return profile.avatarSeed || 'anonymous';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// --- API ---
|
|
54
|
+
function fetchProfile() {
|
|
55
|
+
return fetch('/api/profile').then(function(r) { return r.json(); });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function saveProfile() {
|
|
59
|
+
return fetch('/api/profile', {
|
|
60
|
+
method: 'PUT',
|
|
61
|
+
headers: { 'Content-Type': 'application/json' },
|
|
62
|
+
body: JSON.stringify(profile),
|
|
63
|
+
}).then(function(r) { return r.json(); });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function debouncedSave() {
|
|
67
|
+
if (saveTimer) clearTimeout(saveTimer);
|
|
68
|
+
saveTimer = setTimeout(function() {
|
|
69
|
+
saveProfile();
|
|
70
|
+
saveTimer = null;
|
|
71
|
+
}, 400);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// --- DOM updates ---
|
|
75
|
+
function applyToIsland() {
|
|
76
|
+
var avatarWrap = document.querySelector('.user-island-avatar');
|
|
77
|
+
var nameEl = document.querySelector('.user-island-name');
|
|
78
|
+
if (!avatarWrap || !nameEl) return;
|
|
79
|
+
|
|
80
|
+
var displayName = profile.name || 'Awesome Clay User';
|
|
81
|
+
|
|
82
|
+
// Replace letter fallback with DiceBear img
|
|
83
|
+
var existingImg = avatarWrap.querySelector('img');
|
|
84
|
+
var existingLetter = avatarWrap.querySelector('.user-island-avatar-letter');
|
|
85
|
+
var url = avatarUrl(profile.avatarStyle || 'thumbs', getAvatarSeed(), 32);
|
|
86
|
+
|
|
87
|
+
if (existingImg) {
|
|
88
|
+
existingImg.src = url;
|
|
89
|
+
} else {
|
|
90
|
+
if (existingLetter) existingLetter.style.display = 'none';
|
|
91
|
+
var img = document.createElement('img');
|
|
92
|
+
img.src = url;
|
|
93
|
+
img.alt = displayName;
|
|
94
|
+
avatarWrap.appendChild(img);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
nameEl.textContent = displayName;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// --- Popover ---
|
|
101
|
+
function showPopover() {
|
|
102
|
+
if (popoverEl) {
|
|
103
|
+
hidePopover();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
popoverEl = document.createElement('div');
|
|
108
|
+
popoverEl.className = 'profile-popover';
|
|
109
|
+
|
|
110
|
+
var displayName = profile.name || '';
|
|
111
|
+
var currentLang = profile.lang || 'en-US';
|
|
112
|
+
var currentColor = profile.avatarColor || '#7c3aed';
|
|
113
|
+
var currentStyle = profile.avatarStyle || 'thumbs';
|
|
114
|
+
var seed = getAvatarSeed();
|
|
115
|
+
previewSeed = seed;
|
|
116
|
+
|
|
117
|
+
var html = '';
|
|
118
|
+
|
|
119
|
+
// Banner + close
|
|
120
|
+
html += '<div class="profile-banner" style="background:' + currentColor + '">';
|
|
121
|
+
html += '<button class="profile-close-btn">×</button>';
|
|
122
|
+
html += '</div>';
|
|
123
|
+
|
|
124
|
+
// Avatar row (overlapping banner)
|
|
125
|
+
html += '<div class="profile-avatar-row">';
|
|
126
|
+
html += '<div class="profile-popover-avatar">';
|
|
127
|
+
html += '<img class="profile-popover-avatar-img" src="' + avatarUrl(currentStyle, seed, 80) + '" alt="avatar">';
|
|
128
|
+
html += '</div>';
|
|
129
|
+
html += '<div class="profile-name-display">' + escapeAttr(displayName || 'Awesome Clay User') + '</div>';
|
|
130
|
+
html += '</div>';
|
|
131
|
+
|
|
132
|
+
// Body
|
|
133
|
+
html += '<div class="profile-popover-body">';
|
|
134
|
+
|
|
135
|
+
// Name
|
|
136
|
+
html += '<div class="profile-field">';
|
|
137
|
+
html += '<label class="profile-field-label">Display Name</label>';
|
|
138
|
+
html += '<input type="text" class="profile-field-input" id="profile-name-input" value="' + escapeAttr(displayName) + '" placeholder="Enter your name..." maxlength="50" spellcheck="false" autocomplete="off">';
|
|
139
|
+
html += '</div>';
|
|
140
|
+
|
|
141
|
+
// Language dropdown
|
|
142
|
+
html += '<div class="profile-field">';
|
|
143
|
+
html += '<label class="profile-field-label">Language <span class="profile-field-hint">for voice input</span></label>';
|
|
144
|
+
html += '<select class="profile-field-select" id="profile-lang-select">';
|
|
145
|
+
for (var i = 0; i < LANGUAGES.length; i++) {
|
|
146
|
+
var l = LANGUAGES[i];
|
|
147
|
+
var sel = (currentLang === l.code) ? ' selected' : '';
|
|
148
|
+
html += '<option value="' + l.code + '"' + sel + '>' + l.name + '</option>';
|
|
149
|
+
}
|
|
150
|
+
html += '</select>';
|
|
151
|
+
html += '</div>';
|
|
152
|
+
|
|
153
|
+
// Avatar picker
|
|
154
|
+
html += '<div class="profile-field">';
|
|
155
|
+
html += '<label class="profile-field-label">Avatar <button class="profile-shuffle-btn" title="Shuffle">' + iconHtml('shuffle') + '</button></label>';
|
|
156
|
+
html += '<div class="profile-avatar-grid">';
|
|
157
|
+
for (var j = 0; j < AVATAR_STYLES.length; j++) {
|
|
158
|
+
var st = AVATAR_STYLES[j];
|
|
159
|
+
var activeS = (currentStyle === st.id) ? ' profile-avatar-option-active' : '';
|
|
160
|
+
html += '<button class="profile-avatar-option' + activeS + '" data-style="' + st.id + '" title="' + st.name + '">';
|
|
161
|
+
html += '<img src="' + avatarUrl(st.id, seed, 40) + '" alt="' + st.name + '">';
|
|
162
|
+
html += '</button>';
|
|
163
|
+
}
|
|
164
|
+
html += '</div>';
|
|
165
|
+
html += '</div>';
|
|
166
|
+
|
|
167
|
+
// Color
|
|
168
|
+
html += '<div class="profile-field">';
|
|
169
|
+
html += '<label class="profile-field-label">Color</label>';
|
|
170
|
+
html += '<div class="profile-color-grid">';
|
|
171
|
+
for (var k = 0; k < COLORS.length; k++) {
|
|
172
|
+
var c = COLORS[k];
|
|
173
|
+
var activeC = (currentColor === c) ? ' profile-color-active' : '';
|
|
174
|
+
html += '<button class="profile-color-swatch' + activeC + '" data-color="' + c + '" style="background:' + c + '"></button>';
|
|
175
|
+
}
|
|
176
|
+
html += '</div>';
|
|
177
|
+
html += '</div>';
|
|
178
|
+
|
|
179
|
+
html += '</div>'; // close body
|
|
180
|
+
|
|
181
|
+
popoverEl.innerHTML = html;
|
|
182
|
+
|
|
183
|
+
// --- Events ---
|
|
184
|
+
popoverEl.querySelector('.profile-close-btn').addEventListener('click', function(e) {
|
|
185
|
+
e.stopPropagation();
|
|
186
|
+
hidePopover();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
var nameInput = popoverEl.querySelector('#profile-name-input');
|
|
190
|
+
nameInput.addEventListener('input', function() {
|
|
191
|
+
profile.name = nameInput.value.trim();
|
|
192
|
+
applyToIsland();
|
|
193
|
+
updatePopoverHeader();
|
|
194
|
+
debouncedSave();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
nameInput.addEventListener('keydown', function(e) {
|
|
198
|
+
if (e.key === 'Enter') {
|
|
199
|
+
e.preventDefault();
|
|
200
|
+
hidePopover();
|
|
201
|
+
}
|
|
202
|
+
e.stopPropagation();
|
|
203
|
+
});
|
|
204
|
+
nameInput.addEventListener('keyup', function(e) { e.stopPropagation(); });
|
|
205
|
+
nameInput.addEventListener('keypress', function(e) { e.stopPropagation(); });
|
|
206
|
+
|
|
207
|
+
// Language dropdown
|
|
208
|
+
popoverEl.querySelector('#profile-lang-select').addEventListener('change', function(e) {
|
|
209
|
+
profile.lang = e.target.value;
|
|
210
|
+
setSTTLang(profile.lang);
|
|
211
|
+
debouncedSave();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Avatar style — clicking confirms both the style and the current previewSeed
|
|
215
|
+
popoverEl.querySelectorAll('.profile-avatar-option[data-style]').forEach(function(btn) {
|
|
216
|
+
btn.addEventListener('click', function() {
|
|
217
|
+
profile.avatarStyle = btn.dataset.style;
|
|
218
|
+
profile.avatarSeed = previewSeed;
|
|
219
|
+
applyToIsland();
|
|
220
|
+
updatePopoverHeader();
|
|
221
|
+
popoverEl.querySelectorAll('.profile-avatar-option').forEach(function(b) {
|
|
222
|
+
b.classList.remove('profile-avatar-option-active');
|
|
223
|
+
});
|
|
224
|
+
btn.classList.add('profile-avatar-option-active');
|
|
225
|
+
debouncedSave();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Shuffle button — only changes preview candidates, not the actual profile
|
|
230
|
+
popoverEl.querySelector('.profile-shuffle-btn').addEventListener('click', function(e) {
|
|
231
|
+
e.stopPropagation();
|
|
232
|
+
previewSeed = Math.random().toString(36).substring(2, 10);
|
|
233
|
+
refreshAvatarPreviews();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Color swatches
|
|
237
|
+
popoverEl.querySelectorAll('.profile-color-swatch').forEach(function(btn) {
|
|
238
|
+
btn.addEventListener('click', function() {
|
|
239
|
+
profile.avatarColor = btn.dataset.color;
|
|
240
|
+
applyToIsland();
|
|
241
|
+
var bannerEl = popoverEl.querySelector('.profile-banner');
|
|
242
|
+
if (bannerEl) bannerEl.style.background = profile.avatarColor;
|
|
243
|
+
popoverEl.querySelectorAll('.profile-color-swatch').forEach(function(b) {
|
|
244
|
+
b.classList.remove('profile-color-active');
|
|
245
|
+
});
|
|
246
|
+
btn.classList.add('profile-color-active');
|
|
247
|
+
debouncedSave();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// Prevent clicks inside popover from closing it
|
|
252
|
+
popoverEl.addEventListener('click', function(e) {
|
|
253
|
+
e.stopPropagation();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
var island = document.getElementById('user-island');
|
|
257
|
+
island.appendChild(popoverEl);
|
|
258
|
+
refreshIcons();
|
|
259
|
+
|
|
260
|
+
if (!profile.name) {
|
|
261
|
+
nameInput.focus();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
setTimeout(function() {
|
|
265
|
+
document.addEventListener('click', closeOnOutside);
|
|
266
|
+
document.addEventListener('keydown', closeOnEscape);
|
|
267
|
+
}, 0);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function updatePopoverHeader() {
|
|
271
|
+
if (!popoverEl) return;
|
|
272
|
+
var img = popoverEl.querySelector('.profile-popover-avatar-img');
|
|
273
|
+
var nd = popoverEl.querySelector('.profile-name-display');
|
|
274
|
+
if (img) img.src = avatarUrl(profile.avatarStyle || 'thumbs', getAvatarSeed(), 80);
|
|
275
|
+
if (nd) nd.textContent = profile.name || 'Awesome Clay User';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
function refreshAvatarPreviews() {
|
|
280
|
+
if (!popoverEl) return;
|
|
281
|
+
popoverEl.querySelectorAll('.profile-avatar-option[data-style] img').forEach(function(img) {
|
|
282
|
+
var style = img.closest('.profile-avatar-option').dataset.style;
|
|
283
|
+
img.src = avatarUrl(style, previewSeed, 40);
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function closeOnOutside(e) {
|
|
288
|
+
var island = document.getElementById('user-island');
|
|
289
|
+
if (popoverEl && !popoverEl.contains(e.target) && !island.contains(e.target)) {
|
|
290
|
+
hidePopover();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function closeOnEscape(e) {
|
|
295
|
+
if (e.key === 'Escape' && popoverEl) {
|
|
296
|
+
hidePopover();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function hidePopover() {
|
|
301
|
+
if (popoverEl) {
|
|
302
|
+
popoverEl.remove();
|
|
303
|
+
popoverEl = null;
|
|
304
|
+
}
|
|
305
|
+
document.removeEventListener('click', closeOnOutside);
|
|
306
|
+
document.removeEventListener('keydown', closeOnEscape);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function escapeAttr(str) {
|
|
310
|
+
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// --- Init ---
|
|
314
|
+
export function initProfile(_ctx) {
|
|
315
|
+
ctx = _ctx;
|
|
316
|
+
|
|
317
|
+
var island = document.getElementById('user-island');
|
|
318
|
+
if (!island) return;
|
|
319
|
+
|
|
320
|
+
var profileArea = island.querySelector('.user-island-profile');
|
|
321
|
+
if (profileArea) {
|
|
322
|
+
profileArea.addEventListener('click', function(e) {
|
|
323
|
+
e.stopPropagation();
|
|
324
|
+
showPopover();
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
fetchProfile().then(function(data) {
|
|
329
|
+
if (data.name !== undefined) profile.name = data.name;
|
|
330
|
+
if (data.lang) profile.lang = data.lang;
|
|
331
|
+
if (data.avatarColor) profile.avatarColor = data.avatarColor;
|
|
332
|
+
if (data.avatarStyle) profile.avatarStyle = data.avatarStyle;
|
|
333
|
+
if (data.avatarSeed) profile.avatarSeed = data.avatarSeed;
|
|
334
|
+
|
|
335
|
+
// Auto-generate seed if none exists
|
|
336
|
+
if (!profile.avatarSeed) {
|
|
337
|
+
profile.avatarSeed = Math.random().toString(36).substring(2, 10);
|
|
338
|
+
saveProfile();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
applyToIsland();
|
|
342
|
+
|
|
343
|
+
if (profile.lang) {
|
|
344
|
+
setSTTLang(profile.lang);
|
|
345
|
+
}
|
|
346
|
+
}).catch(function(err) {
|
|
347
|
+
console.warn('[Profile] Failed to load:', err);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function getProfile() {
|
|
352
|
+
return profile;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export function getProfileLang() {
|
|
356
|
+
return profile.lang;
|
|
357
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// project-settings.js — Project settings panel (profile, defaults, instructions, env)
|
|
2
2
|
import { refreshIcons } from './icons.js';
|
|
3
3
|
import { showToast } from './utils.js';
|
|
4
|
+
import { parseEmojis } from './markdown.js';
|
|
4
5
|
|
|
5
6
|
var ctx = null;
|
|
6
7
|
var panelEl = null;
|
|
@@ -252,9 +253,7 @@ function updateIconPreview(icon) {
|
|
|
252
253
|
var removeBtn = document.getElementById("ps-icon-remove-btn");
|
|
253
254
|
if (preview) {
|
|
254
255
|
preview.textContent = icon || "";
|
|
255
|
-
if (
|
|
256
|
-
twemoji.parse(preview, { folder: "svg", ext: ".svg" });
|
|
257
|
-
}
|
|
256
|
+
if (icon) parseEmojis(preview);
|
|
258
257
|
}
|
|
259
258
|
if (removeBtn) {
|
|
260
259
|
removeBtn.classList.toggle("hidden", !icon);
|
|
@@ -339,9 +338,7 @@ function showPsEmojiPicker() {
|
|
|
339
338
|
grid.appendChild(btn);
|
|
340
339
|
})(emojis[i]);
|
|
341
340
|
}
|
|
342
|
-
|
|
343
|
-
twemoji.parse(grid, { folder: "svg", ext: ".svg" });
|
|
344
|
-
}
|
|
341
|
+
parseEmojis(grid);
|
|
345
342
|
scrollArea.scrollTop = 0;
|
|
346
343
|
}
|
|
347
344
|
|
|
@@ -353,9 +350,7 @@ function showPsEmojiPicker() {
|
|
|
353
350
|
}
|
|
354
351
|
|
|
355
352
|
buildGrid(EMOJI_CATEGORIES[0].emojis);
|
|
356
|
-
|
|
357
|
-
twemoji.parse(tabBar, { folder: "svg", ext: ".svg" });
|
|
358
|
-
}
|
|
353
|
+
parseEmojis(tabBar);
|
|
359
354
|
|
|
360
355
|
anchor.innerHTML = "";
|
|
361
356
|
anchor.appendChild(picker);
|