clay-server 2.23.1 → 2.24.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.
@@ -1,4 +1,4 @@
1
- import { mateAvatarUrl } from './avatar.js';
1
+ import { mateAvatarUrl, userAvatarUrl } from './avatar.js';
2
2
  import { renderMarkdown, highlightCodeBlocks } from './markdown.js';
3
3
  import { escapeHtml, copyToClipboard } from './utils.js';
4
4
  import { iconHtml, refreshIcons } from './icons.js';
@@ -12,6 +12,8 @@ var mentionFiltered = []; // filtered mate list
12
12
  var mentionActiveIdx = -1; // highlighted item in dropdown
13
13
  var selectedMateId = null; // selected mate for pending send
14
14
  var selectedMateName = null; // display name of selected mate
15
+ var selectedMateColor = null; // avatar color for sticky re-apply
16
+ var selectedMateAvatar = null; // avatar src for sticky re-apply
15
17
 
16
18
  // Streaming state
17
19
  var currentMentionEl = null; // current mention response DOM element
@@ -78,10 +80,16 @@ export function showMentionMenu(query) {
78
80
  menuEl.innerHTML = mentionFiltered.map(function (m, i) {
79
81
  var name = (m.profile && m.profile.displayName) || m.name || "Mate";
80
82
  var color = (m.profile && m.profile.avatarColor) || "#6c5ce7";
83
+ var bio = m.bio || (m.profile && m.profile.bio) || "";
81
84
  var avatarSrc = mateAvatarUrl(m, 24);
82
85
  return '<div class="mention-item' + (i === 0 ? ' active' : '') + '" data-idx="' + i + '">' +
83
86
  '<img class="mention-item-avatar" src="' + escapeHtml(avatarSrc) + '" width="24" height="24" />' +
84
- '<span class="mention-item-name">' + escapeHtml(name) + '</span>' +
87
+ '<div class="mention-item-info">' +
88
+ '<span class="mention-item-name">' + escapeHtml(name) +
89
+ (m.primary ? ' <span class="mention-item-badge">SYSTEM</span>' : '') +
90
+ '</span>' +
91
+ (bio ? '<span class="mention-item-bio">' + escapeHtml(bio) + '</span>' : '') +
92
+ '</div>' +
85
93
  '<span class="mention-item-dot" style="background:' + escapeHtml(color) + '"></span>' +
86
94
  '</div>';
87
95
  }).join("");
@@ -148,6 +156,8 @@ function selectMentionItem(idx) {
148
156
 
149
157
  selectedMateId = mate.id;
150
158
  selectedMateName = name;
159
+ selectedMateColor = color;
160
+ selectedMateAvatar = avatarSrc;
151
161
 
152
162
  // Remove the @query text from the textarea, keep remaining text
153
163
  if (ctx.inputEl && mentionAtIdx >= 0) {
@@ -198,6 +208,8 @@ export function removeMentionChip() {
198
208
  removeInputMentionChip();
199
209
  selectedMateId = null;
200
210
  selectedMateName = null;
211
+ selectedMateColor = null;
212
+ selectedMateAvatar = null;
201
213
  if (ctx.inputEl) ctx.inputEl.focus();
202
214
  }
203
215
 
@@ -229,10 +241,30 @@ export function parseMentionFromInput(text) {
229
241
  export function clearMentionState() {
230
242
  selectedMateId = null;
231
243
  selectedMateName = null;
244
+ selectedMateColor = null;
245
+ selectedMateAvatar = null;
232
246
  mentionAtIdx = -1;
233
247
  removeInputMentionChip();
234
248
  }
235
249
 
250
+ // Re-apply the same mate mention after sending (sticky mention).
251
+ // Keeps the chip visible so the next message also goes to the same mate.
252
+ export function stickyReapplyMention() {
253
+ if (!selectedMateId || !selectedMateName) return;
254
+ var id = selectedMateId;
255
+ var name = selectedMateName;
256
+ var color = selectedMateColor || "#6c5ce7";
257
+ var avatarSrc = selectedMateAvatar || "";
258
+ // Reset index but keep mate selection
259
+ mentionAtIdx = -1;
260
+ removeInputMentionChip();
261
+ selectedMateId = id;
262
+ selectedMateName = name;
263
+ selectedMateColor = color;
264
+ selectedMateAvatar = avatarSrc;
265
+ showInputMentionChip(name, color, avatarSrc);
266
+ }
267
+
236
268
  export function sendMention(mateId, text, pastes, images) {
237
269
  if (!ctx.ws || !ctx.connected) return;
238
270
  var payload = { type: "mention", mateId: mateId, text: text };
@@ -274,8 +306,8 @@ export function handleMentionStart(msg) {
274
306
 
275
307
  var avatarSrc = buildMentionAvatarUrl(msg);
276
308
 
277
- if (isMateDm()) {
278
- // Mate DM: render as DM-style assistant message
309
+ if (isDmLayout()) {
310
+ // DM-style: render as DM-style assistant message (Mate DM or Wide view)
279
311
  currentMentionEl = document.createElement("div");
280
312
  currentMentionEl.className = "msg-assistant msg-mention-dm";
281
313
 
@@ -519,6 +551,28 @@ function isMateDm() {
519
551
  return document.body.classList.contains("mate-dm-active");
520
552
  }
521
553
 
554
+ function isWideView() {
555
+ return document.body.classList.contains("wide-view");
556
+ }
557
+
558
+ function isDmLayout() {
559
+ return isMateDm() || isWideView();
560
+ }
561
+
562
+ function getMyAvatarSrc() {
563
+ if (document.body.dataset.myAvatarUrl) return document.body.dataset.myAvatarUrl;
564
+ var myUser = null;
565
+ try { myUser = JSON.parse(localStorage.getItem("clay_my_user") || "null"); } catch (e) {}
566
+ return userAvatarUrl(myUser || {}, 36);
567
+ }
568
+
569
+ function getMyDisplayName() {
570
+ if (document.body.dataset.myDisplayName) return document.body.dataset.myDisplayName;
571
+ var myUser = null;
572
+ try { myUser = JSON.parse(localStorage.getItem("clay_my_user") || "null"); } catch (e) {}
573
+ return (myUser && (myUser.displayName || myUser.username)) || "Me";
574
+ }
575
+
522
576
  function timeStr() {
523
577
  var now = new Date();
524
578
  return String(now.getHours()).padStart(2, "0") + ":" + String(now.getMinutes()).padStart(2, "0");
@@ -590,32 +644,28 @@ export function renderMentionUser(entry) {
590
644
  textEl.innerHTML = '<span class="mention-chip">@' + escapeHtml(entry.mateName || "Mate") + '</span> ' + escapeHtml(entry.text || "");
591
645
  bubble.appendChild(textEl);
592
646
 
593
- // In Mate DM: use DM-style layout with avatar + name header
594
- if (isMateDm() && document.body.dataset.myAvatarUrl) {
595
- var avi = document.createElement("img");
596
- avi.className = "dm-bubble-avatar dm-bubble-avatar-me";
597
- avi.src = document.body.dataset.myAvatarUrl;
598
- div.appendChild(avi);
599
-
600
- var contentWrap = document.createElement("div");
601
- contentWrap.className = "dm-bubble-content";
602
-
603
- var header = document.createElement("div");
604
- header.className = "dm-bubble-header";
605
- var nameSpan = document.createElement("span");
606
- nameSpan.className = "dm-bubble-name";
607
- nameSpan.textContent = document.body.dataset.myDisplayName || "Me";
608
- header.appendChild(nameSpan);
609
- var ts = document.createElement("span");
610
- ts.className = "dm-bubble-time";
611
- ts.textContent = timeStr();
612
- header.appendChild(ts);
613
- contentWrap.appendChild(header);
614
- contentWrap.appendChild(bubble);
615
- div.appendChild(contentWrap);
616
- } else {
617
- div.appendChild(bubble);
618
- }
647
+ // Always render avatar + header structure (CSS controls visibility)
648
+ var avi = document.createElement("img");
649
+ avi.className = "dm-bubble-avatar dm-bubble-avatar-me";
650
+ avi.src = getMyAvatarSrc();
651
+ div.appendChild(avi);
652
+
653
+ var contentWrap = document.createElement("div");
654
+ contentWrap.className = "dm-bubble-content";
655
+
656
+ var header = document.createElement("div");
657
+ header.className = "dm-bubble-header";
658
+ var nameSpan = document.createElement("span");
659
+ nameSpan.className = "dm-bubble-name";
660
+ nameSpan.textContent = getMyDisplayName();
661
+ header.appendChild(nameSpan);
662
+ var ts = document.createElement("span");
663
+ ts.className = "dm-bubble-time";
664
+ ts.textContent = timeStr();
665
+ header.appendChild(ts);
666
+ contentWrap.appendChild(header);
667
+ contentWrap.appendChild(bubble);
668
+ div.appendChild(contentWrap);
619
669
 
620
670
  // Action bar below bubble (same as regular user messages)
621
671
  var actions = document.createElement("div");
@@ -647,8 +697,8 @@ export function renderMentionUser(entry) {
647
697
  export function renderMentionResponse(entry) {
648
698
  var avatarSrc = buildMentionAvatarUrl(entry);
649
699
 
650
- // In Mate DM: render as DM-style message (like assistant messages)
651
- if (isMateDm()) {
700
+ // DM-style message layout (Mate DM or Wide view)
701
+ if (isDmLayout()) {
652
702
  var el = document.createElement("div");
653
703
  el.className = "msg-assistant msg-mention-dm";
654
704
 
@@ -72,6 +72,10 @@ export function initNotifications(_ctx) {
72
72
  if (window.visualViewport) {
73
73
  var layout = $("layout");
74
74
  var mobileTabBar = document.getElementById("mobile-tab-bar");
75
+ // Capture initial viewport height before any keyboard interaction.
76
+ // In iOS PWA standalone mode, window.innerHeight shrinks when the
77
+ // keyboard opens, so we need a stable baseline for comparison.
78
+ var stableViewportHeight = window.innerHeight;
75
79
  function onViewportChange() {
76
80
  var vv = window.visualViewport;
77
81
  // Shrink layout to visual viewport height so input area sits above keyboard
@@ -80,7 +84,7 @@ export function initNotifications(_ctx) {
80
84
  layout.style.top = vv.offsetTop + "px";
81
85
  document.documentElement.scrollTop = 0;
82
86
  // Toggle class so CSS can remove the tab-bar bottom padding while keyboard is up
83
- var keyboardOpen = vv.height < window.innerHeight - 100;
87
+ var keyboardOpen = vv.height < stableViewportHeight - 100;
84
88
  document.body.classList.toggle("keyboard-open", keyboardOpen);
85
89
  if (!keyboardOpen) ctx.scrollToBottom();
86
90
  // Hide tab bar when software keyboard is open
@@ -157,11 +157,11 @@ function performSearch(query) {
157
157
 
158
158
  function highlightLoadedMessages() {
159
159
  var messagesEl = ctx.messagesEl;
160
- var msgEls = messagesEl.querySelectorAll(".msg-user, .msg-assistant");
160
+ var msgEls = messagesEl.querySelectorAll(".msg-user, .msg-assistant, .debate-turn, .debate-user-comment");
161
161
  var queryLower = currentQuery.toLowerCase();
162
162
 
163
163
  for (var i = 0; i < msgEls.length; i++) {
164
- var contentEl = msgEls[i].querySelector(".bubble") || msgEls[i].querySelector(".md-content");
164
+ var contentEl = msgEls[i].querySelector(".bubble") || msgEls[i].querySelector(".md-content") || msgEls[i].querySelector(".debate-comment-text");
165
165
  if (!contentEl) continue;
166
166
  highlightInElement(contentEl, queryLower);
167
167
  }
@@ -328,12 +328,12 @@ function scrollToSearchHit(historyIndex, snippet, query) {
328
328
  function findAndScrollToMatch(snippet, query) {
329
329
  var messagesEl = ctx.messagesEl;
330
330
  var q = query.toLowerCase();
331
- var allMsgs = messagesEl.querySelectorAll(".msg-user, .msg-assistant");
331
+ var allMsgs = messagesEl.querySelectorAll(".msg-user, .msg-assistant, .debate-turn, .debate-user-comment");
332
332
  var cleanSnippet = snippet.replace(/^\u2026/, "").replace(/\u2026$/, "");
333
333
 
334
334
  for (var i = 0; i < allMsgs.length; i++) {
335
335
  var msgEl = allMsgs[i];
336
- var textEl = msgEl.querySelector(".bubble") || msgEl.querySelector(".md-content");
336
+ var textEl = msgEl.querySelector(".bubble") || msgEl.querySelector(".md-content") || msgEl.querySelector(".debate-comment-text");
337
337
  if (!textEl) continue;
338
338
  var text = textEl.textContent || "";
339
339
  if (text.indexOf(cleanSnippet) !== -1) {
@@ -347,7 +347,7 @@ function findAndScrollToMatch(snippet, query) {
347
347
  // Fallback: any element containing the query
348
348
  for (var j = 0; j < allMsgs.length; j++) {
349
349
  var el = allMsgs[j];
350
- var tEl = el.querySelector(".bubble") || el.querySelector(".md-content");
350
+ var tEl = el.querySelector(".bubble") || el.querySelector(".md-content") || el.querySelector(".debate-comment-text");
351
351
  if (!tEl) continue;
352
352
  if ((tEl.textContent || "").toLowerCase().indexOf(q) !== -1) {
353
353
  el.scrollIntoView({ behavior: "smooth", block: "center" });
@@ -2879,26 +2879,8 @@ function showIconCtxMenu(anchorEl, slug, name) {
2879
2879
  showWorktreeModal(slug, name || slug);
2880
2880
  });
2881
2881
  menu.appendChild(wtItem);
2882
-
2883
- if (!ctx.permissions || ctx.permissions.deleteProject !== false) {
2884
- // --- Separator ---
2885
- var sep = document.createElement("div");
2886
- sep.className = "project-ctx-separator";
2887
- menu.appendChild(sep);
2888
-
2889
- // --- Remove Project ---
2890
- var removeItem = document.createElement("button");
2891
- removeItem.className = "project-ctx-item project-ctx-delete";
2892
- removeItem.innerHTML = iconHtml("trash-2") + " <span>Remove Project</span>";
2893
- removeItem.addEventListener("click", function (e) {
2894
- e.stopPropagation();
2895
- closeProjectCtxMenu();
2896
- if (ctx.ws && ctx.connected) {
2897
- ctx.ws.send(JSON.stringify({ type: "remove_project_check", slug: slug, name: name || slug }));
2898
- }
2899
- });
2900
- menu.appendChild(removeItem);
2901
- }
2882
+ // Remove Project intentionally omitted from right-click.
2883
+ // Destructive actions only live in the chevron menu.
2902
2884
  }
2903
2885
 
2904
2886
  document.body.appendChild(menu);
@@ -2928,6 +2910,17 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
2928
2910
  var menu = document.createElement("div");
2929
2911
  menu.className = "project-ctx-menu";
2930
2912
 
2913
+ // --- Set Icon ---
2914
+ var iconItem = document.createElement("button");
2915
+ iconItem.className = "project-ctx-item";
2916
+ iconItem.innerHTML = iconHtml("smile") + " <span>Set Icon</span>";
2917
+ iconItem.addEventListener("click", function (e) {
2918
+ e.stopPropagation();
2919
+ closeProjectCtxMenu();
2920
+ showEmojiPicker(slug, anchorEl);
2921
+ });
2922
+ menu.appendChild(iconItem);
2923
+
2931
2924
  // --- Project Settings ---
2932
2925
  if (!ctx.permissions || ctx.permissions.projectSettings !== false) {
2933
2926
  var settingsItem = document.createElement("button");
@@ -2941,6 +2934,11 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
2941
2934
  menu.appendChild(settingsItem);
2942
2935
  }
2943
2936
 
2937
+ // --- Separator: collaboration ---
2938
+ var sep1 = document.createElement("div");
2939
+ sep1.className = "project-ctx-separator";
2940
+ menu.appendChild(sep1);
2941
+
2944
2942
  // --- Share ---
2945
2943
  var shareItem = document.createElement("button");
2946
2944
  shareItem.className = "project-ctx-item";
@@ -2969,20 +2967,35 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
2969
2967
  }
2970
2968
  }
2971
2969
 
2970
+ // --- Separator: development ---
2971
+ var sep2 = document.createElement("div");
2972
+ sep2.className = "project-ctx-separator";
2973
+ menu.appendChild(sep2);
2974
+
2975
+ // --- Add Worktree ---
2976
+ var wtItem = document.createElement("button");
2977
+ wtItem.className = "project-ctx-item";
2978
+ wtItem.innerHTML = iconHtml("git-branch") + " <span>Add Worktree</span>";
2979
+ wtItem.addEventListener("click", function (e) {
2980
+ e.stopPropagation();
2981
+ closeProjectCtxMenu();
2982
+ showWorktreeModal(slug, name || slug);
2983
+ });
2984
+ menu.appendChild(wtItem);
2985
+
2972
2986
  if (!ctx.permissions || ctx.permissions.deleteProject !== false) {
2973
- // --- Separator ---
2974
- var sep = document.createElement("div");
2975
- sep.className = "project-ctx-separator";
2976
- menu.appendChild(sep);
2987
+ // --- Separator: danger zone ---
2988
+ var sep3 = document.createElement("div");
2989
+ sep3.className = "project-ctx-separator";
2990
+ menu.appendChild(sep3);
2977
2991
 
2978
- // --- Delete ---
2992
+ // --- Remove Project ---
2979
2993
  var deleteItem = document.createElement("button");
2980
2994
  deleteItem.className = "project-ctx-item project-ctx-delete";
2981
2995
  deleteItem.innerHTML = iconHtml("trash-2") + " <span>Remove Project</span>";
2982
2996
  deleteItem.addEventListener("click", function (e) {
2983
2997
  e.stopPropagation();
2984
2998
  closeProjectCtxMenu();
2985
- // Check for tasks/schedules first before removing
2986
2999
  if (ctx.ws && ctx.connected) {
2987
3000
  ctx.ws.send(JSON.stringify({ type: "remove_project_check", slug: slug, name: name }));
2988
3001
  }
@@ -266,6 +266,7 @@ var changeCallbacks = [];
266
266
  var STORAGE_KEY = "clay-theme";
267
267
  var MODE_KEY = "clay-mode"; // "light" | "dark" | null (system)
268
268
  var SKIN_KEY = "clay-skin"; // theme id within current variant pair
269
+ var WIDE_KEY = "clay-wide-view"; // cached from server, "bubble" | "channel"
269
270
 
270
271
  // --- Helpers ---
271
272
 
@@ -485,6 +486,32 @@ function themeIdForMode(mode) {
485
486
  }
486
487
  }
487
488
 
489
+ // --- Wide view ---
490
+
491
+ export function isWideView() {
492
+ try {
493
+ var v = localStorage.getItem(WIDE_KEY);
494
+ return v === null ? true : v !== "bubble"; // default: Channel (wide)
495
+ } catch (e) { return true; }
496
+ }
497
+
498
+ export function getChatLayout() {
499
+ try {
500
+ var v = localStorage.getItem(WIDE_KEY);
501
+ return v === "bubble" ? "bubble" : "channel";
502
+ } catch (e) { return "channel"; }
503
+ }
504
+
505
+ export function setChatLayout(layout) {
506
+ var val = (layout === "bubble") ? "bubble" : "channel";
507
+ try { localStorage.setItem(WIDE_KEY, val); } catch (e) {}
508
+ document.body.classList.toggle("wide-view", val === "channel");
509
+ }
510
+
511
+ export function setWideView(enabled) {
512
+ setChatLayout(enabled ? "channel" : "bubble");
513
+ }
514
+
488
515
  // Toggle between light and dark
489
516
  export function toggleDarkMode() {
490
517
  var current = getEffectiveMode();
@@ -671,6 +698,9 @@ export function initTheme() {
671
698
  currentThemeId = mode === "light" ? "ayu-light" : "dracula";
672
699
  }
673
700
 
701
+ // Apply wide view state from localStorage
702
+ document.body.classList.toggle("wide-view", isWideView());
703
+
674
704
  // Load all themes from server, then apply properly
675
705
  loadThemes();
676
706
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { refreshIcons } from './icons.js';
5
5
  import { showToast } from './utils.js';
6
- import { toggleDarkMode, getCurrentTheme } from './theme.js';
6
+ import { toggleDarkMode, getCurrentTheme, getChatLayout, setChatLayout } from './theme.js';
7
7
 
8
8
  var ctx = null;
9
9
  var settingsEl = null;
@@ -93,12 +93,42 @@ export function initUserSettings(appCtx) {
93
93
  });
94
94
  }
95
95
 
96
- // Theme toggle (light/dark)
97
- var themeToggle = document.getElementById('us-theme-toggle');
98
- if (themeToggle) {
99
- themeToggle.addEventListener('change', function () {
100
- toggleDarkMode();
101
- });
96
+ // Theme switcher (Light / Dark)
97
+ var themeSwitcher = document.getElementById('us-theme-switcher');
98
+ if (themeSwitcher) {
99
+ var themeBtns = themeSwitcher.querySelectorAll('.layout-option');
100
+ for (var ti = 0; ti < themeBtns.length; ti++) {
101
+ themeBtns[ti].addEventListener('click', function () {
102
+ var mode = this.dataset.theme;
103
+ var current = getCurrentTheme();
104
+ var currentMode = (current && current.variant) || 'dark';
105
+ if (mode !== currentMode) toggleDarkMode();
106
+ for (var tj = 0; tj < themeBtns.length; tj++) {
107
+ themeBtns[tj].classList.toggle('selected', themeBtns[tj].dataset.theme === mode);
108
+ }
109
+ });
110
+ }
111
+ }
112
+
113
+ // Layout switcher (Bubble / Channel)
114
+ var layoutSwitcher = document.getElementById('us-layout-switcher');
115
+ if (layoutSwitcher) {
116
+ var layoutBtns = layoutSwitcher.querySelectorAll('.layout-option');
117
+ for (var li = 0; li < layoutBtns.length; li++) {
118
+ layoutBtns[li].addEventListener('click', function () {
119
+ var layout = this.dataset.layout;
120
+ setChatLayout(layout);
121
+ for (var lj = 0; lj < layoutBtns.length; lj++) {
122
+ layoutBtns[lj].classList.toggle('selected', layoutBtns[lj].dataset.layout === layout);
123
+ }
124
+ // Save to server
125
+ fetch('/api/user/chat-layout', {
126
+ method: 'PUT',
127
+ headers: { 'Content-Type': 'application/json' },
128
+ body: JSON.stringify({ layout: layout }),
129
+ }).catch(function () {});
130
+ });
131
+ }
102
132
  }
103
133
 
104
134
  // Logout button
@@ -166,11 +196,30 @@ function populateAccount() {
166
196
  // Auto-continue toggle
167
197
  var acToggle = document.getElementById('us-auto-continue');
168
198
  if (acToggle) acToggle.checked = !!data.autoContinueOnRateLimit;
169
- // Theme toggle
170
- var thToggle = document.getElementById('us-theme-toggle');
171
- if (thToggle) {
172
- var theme = getCurrentTheme();
173
- thToggle.checked = theme && theme.variant === 'light';
199
+ // Theme switcher
200
+ var tSwitcher = document.getElementById('us-theme-switcher');
201
+ if (tSwitcher) {
202
+ var currentMode = (getCurrentTheme() && getCurrentTheme().variant) || 'dark';
203
+ var tBtns = tSwitcher.querySelectorAll('.layout-option');
204
+ for (var ti = 0; ti < tBtns.length; ti++) {
205
+ tBtns[ti].classList.toggle('selected', tBtns[ti].dataset.theme === currentMode);
206
+ }
207
+ }
208
+ // Layout switcher: sync from server response
209
+ // Sync mate onboarding state from server
210
+ if (data.mateOnboardingShown) {
211
+ try { localStorage.setItem("clay-mate-onboarding-shown", "1"); } catch (e) {}
212
+ }
213
+ if (data.chatLayout) {
214
+ setChatLayout(data.chatLayout); // update local cache + CSS
215
+ }
216
+ var lSwitcher = document.getElementById('us-layout-switcher');
217
+ if (lSwitcher) {
218
+ var currentLayout = getChatLayout();
219
+ var lBtns = lSwitcher.querySelectorAll('.layout-option');
220
+ for (var li = 0; li < lBtns.length; li++) {
221
+ lBtns[li].classList.toggle('selected', lBtns[li].dataset.layout === currentLayout);
222
+ }
174
223
  }
175
224
  }).catch(function () {});
176
225
  }