pinokiod 3.52.0 → 3.53.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.
@@ -12,7 +12,7 @@
12
12
  border-top: none;
13
13
  border-radius: 0 0 5px 5px;
14
14
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
15
- max-height: 300px;
15
+ max-height: 500px;
16
16
  overflow-y: auto;
17
17
  z-index: 1000;
18
18
  display: none;
@@ -25,7 +25,7 @@ body.dark .url-dropdown {
25
25
  box-shadow: 0 2px 8px rgba(255,255,255,0.1);
26
26
  }
27
27
  .url-dropdown-item {
28
- padding: 12px 16px;
28
+ padding: 8px 12px;
29
29
  cursor: pointer;
30
30
  border-bottom: 1px solid #eee;
31
31
  display: flex;
@@ -48,6 +48,8 @@ body.dark .url-dropdown-item:hover {
48
48
  font-weight: bold;
49
49
  color: #2d3748;
50
50
  font-size: 14px;
51
+ display: flex;
52
+ align-items: center;
51
53
  }
52
54
  body.dark .url-dropdown-name {
53
55
  color: #e2e8f0;
@@ -133,7 +135,7 @@ body.minimized header h1 .mobile-link-button {
133
135
  }
134
136
  .url-modal-content {
135
137
  background: white;
136
- padding: 20px;
138
+ padding: 50px 10px 10px;
137
139
  border-radius: 10px;
138
140
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
139
141
  width: 90%;
@@ -172,3 +174,93 @@ body.dark .url-modal-input {
172
174
  border-color: rgba(255, 255, 255, 0.2);
173
175
  color: white;
174
176
  }
177
+
178
+ /* Host categorization styles */
179
+ .url-dropdown-host-header {
180
+ background: royalblue;
181
+ font-weight: bold;
182
+ font-size: 18px;
183
+ color: white;
184
+ border-bottom: 1px solid #e2e8f0;
185
+ display: flex;
186
+ align-items: center;
187
+ gap: 8px;
188
+ }
189
+
190
+ body.dark .url-dropdown-host-header {
191
+ background: royalblue;
192
+ color: white;
193
+ border-bottom-color: rgba(255, 255, 255, 0.1);
194
+ }
195
+
196
+ .url-dropdown-host-header i {
197
+ width: 18px;
198
+ text-align: center;
199
+ }
200
+
201
+ .host-badge {
202
+ display: inline-flex;
203
+ align-items: center;
204
+ gap: 6px;
205
+ background: #edf2f7;
206
+ padding: 2px 8px;
207
+ border-radius: 12px;
208
+ font-size: 18px;
209
+ color: #4a5568;
210
+ }
211
+
212
+ body.dark .host-badge {
213
+ background: rgba(255, 255, 255, 0.1);
214
+ color: #cbd5e0;
215
+ }
216
+
217
+ .host-name {
218
+ font-weight: bold;
219
+ flex-grow: 1;
220
+ text-align: right;
221
+ padding: 5px;
222
+ font-size: 14px;
223
+ color: white;
224
+ }
225
+
226
+ .host-meta {
227
+ padding: 5px 10px;
228
+ color: white;
229
+ }
230
+ .host-arch {
231
+ color: white;
232
+ font-size: 14px;
233
+ }
234
+ .status-circle {
235
+ width: 8px;
236
+ height: 8px;
237
+ border-radius: 50%;
238
+ display: inline-block;
239
+ margin-right: 8px;
240
+ }
241
+
242
+ .status-circle.online {
243
+ background-color: yellowgreen;
244
+ }
245
+
246
+ .status-circle.offline {
247
+ background-color: silver;
248
+ }
249
+
250
+ .peer-network-button:hover {
251
+ color: white !important;
252
+ }
253
+ .peer-network-button {
254
+ background: royalblue;
255
+ color: white;
256
+ border: none;
257
+ padding: 4px 10px;
258
+ border-radius: 4px;
259
+ cursor: pointer;
260
+ margin-right: 10px;
261
+ }
262
+
263
+
264
+ body.dark .host-arch {
265
+ color: #a0aec0;
266
+ }
@@ -55,6 +55,31 @@ function initUrlDropdown(config = {}) {
55
55
  }
56
56
  });
57
57
 
58
+ if (document.querySelector(".urlbar")) {
59
+ document.querySelector(".urlbar").addEventListener("submit", (e) => {
60
+ e.preventDefault()
61
+ e.stopPropagation()
62
+ let el = e.target.querySelector("input[type=url]")
63
+ let val = el.value
64
+ let type = el.getAttribute("data-host-type")
65
+ if (type === "local") {
66
+ let redirect_uri = "/container?url=" + val
67
+ location.href = redirect_uri
68
+ } else {
69
+ let u = new URL(val)
70
+ if (String(u.port) === "42000") {
71
+ // pinokio app => open the url itself
72
+ window.open(val, "_blank")
73
+ } else {
74
+ // other servers => open in pinokio redirect frame
75
+ let redirect_uri = "/container?url=" + val
76
+ location.href = redirect_uri
77
+ }
78
+ }
79
+ })
80
+ }
81
+
82
+
58
83
  function initializeInputValue() {
59
84
  if (options.clearBehavior === 'empty') {
60
85
  urlInput.value = '';
@@ -140,6 +165,111 @@ function initUrlDropdown(config = {}) {
140
165
  dropdown.style.display = 'none';
141
166
  }
142
167
 
168
+ function createHostBadge(host) {
169
+ if (!host || !host.platform) return '';
170
+
171
+ // Get platform icon
172
+ let platformIcon = '';
173
+ switch (host.platform) {
174
+ case 'darwin':
175
+ platformIcon = 'fa-brands fa-apple';
176
+ break;
177
+ case 'win32':
178
+ platformIcon = 'fa-brands fa-windows';
179
+ break;
180
+ case 'linux':
181
+ platformIcon = 'fa-brands fa-linux';
182
+ break;
183
+ default:
184
+ platformIcon = 'fa-solid fa-desktop';
185
+ break;
186
+ }
187
+
188
+ // Create badge HTML
189
+ return `
190
+ <span class="host-badge">
191
+ <i class="${platformIcon}"></i>
192
+ <span class="host-name">${escapeHtml(host.name)}</span>
193
+ </span>
194
+ `;
195
+ }
196
+
197
+ function groupProcessesByHost(processes) {
198
+ const grouped = {};
199
+
200
+ processes.forEach(process => {
201
+ // Create a normalized host key based only on name for grouping
202
+ const hostKey = process.host ? process.host.name : 'Unknown';
203
+
204
+ if (!grouped[hostKey]) {
205
+ grouped[hostKey] = {
206
+ host: process.host || { name: 'Unknown', platform: 'unknown', arch: 'unknown' },
207
+ processes: [],
208
+ isLocal: false
209
+ };
210
+ }
211
+
212
+ // Mark as local if any process from this host is local
213
+ if (process.host.local === true) {
214
+ grouped[hostKey].isLocal = true;
215
+ }
216
+
217
+ grouped[hostKey].processes.push(process);
218
+ });
219
+
220
+ // Sort host keys: local host first, then alphabetically
221
+ return Object.keys(grouped)
222
+ .sort((a, b) => {
223
+ const aIsLocal = grouped[a].isLocal;
224
+ const bIsLocal = grouped[b].isLocal;
225
+
226
+ // Local host always comes first
227
+ if (aIsLocal && !bIsLocal) return 1;
228
+ if (!aIsLocal && bIsLocal) return -1;
229
+
230
+ // Both local or both remote - sort alphabetically
231
+ return a.localeCompare(b);
232
+ })
233
+ .reduce((sortedGrouped, hostKey) => {
234
+ sortedGrouped[hostKey] = grouped[hostKey];
235
+ return sortedGrouped;
236
+ }, {});
237
+ }
238
+
239
+ function createHostHeader(host, isLocal = false) {
240
+ if (!host) return '';
241
+
242
+ // Get platform icon
243
+ let platformIcon = '';
244
+ switch (host.platform) {
245
+ case 'darwin':
246
+ platformIcon = 'fa-brands fa-apple';
247
+ break;
248
+ case 'win32':
249
+ platformIcon = 'fa-brands fa-windows';
250
+ break;
251
+ case 'linux':
252
+ platformIcon = 'fa-brands fa-linux';
253
+ break;
254
+ default:
255
+ platformIcon = 'fa-solid fa-desktop';
256
+ break;
257
+ }
258
+
259
+ console.log({ isLocal, host })
260
+ const hostName = isLocal ? `${host.name} (This Machine)` : `${host.name} (Peer)`;
261
+
262
+ return `
263
+ <div class="url-dropdown-host-header">
264
+ <span class='host-meta'>
265
+ <i class="${platformIcon}"></i>
266
+ <span class="host-arch">${escapeHtml(host.arch)}</span>
267
+ </span>
268
+ <span class="host-name">${escapeHtml(hostName)}</span>
269
+ </div>
270
+ `;
271
+ }
272
+
143
273
  function populateDropdown(processes) {
144
274
  if (processes.length === 0) {
145
275
  const query = urlInput.value.toLowerCase().trim();
@@ -150,28 +280,76 @@ function initUrlDropdown(config = {}) {
150
280
  return;
151
281
  }
152
282
 
153
- const items = processes.map(process => {
154
- const url = `http://${process.ip}`;
155
- return `
156
- <div class="url-dropdown-item" data-url="${url}">
157
- <div class="url-dropdown-name">${escapeHtml(process.name)}</div>
158
- <div class="url-dropdown-url">${escapeHtml(url)}</div>
159
- </div>
160
- `;
161
- }).join('');
283
+ // Group processes by host
284
+ const groupedProcesses = groupProcessesByHost(processes);
285
+
286
+ let html = '';
287
+ Object.keys(groupedProcesses).forEach(hostKey => {
288
+ const hostData = groupedProcesses[hostKey];
289
+ const hostInfo = hostData.host;
290
+ const processes = hostData.processes;
291
+ const isLocal = hostData.isLocal;
292
+
293
+ // Add host header
294
+ html += createHostHeader(hostInfo, isLocal);
295
+
296
+ // Add processes for this host
297
+ processes.forEach(process => {
298
+ const onlineIndicator = process.online ?
299
+ '<div class="status-circle online"></div>' :
300
+ '<div class="status-circle offline"></div>';
301
+
302
+ if (process.ip === null || process.ip === undefined) {
303
+ // Non-selectable item with "turn on peer network" button
304
+ const networkUrl = `http://${process.host.ip}:42000/network`;
305
+ html += `
306
+ <div class="url-dropdown-item non-selectable">
307
+ <div class="url-dropdown-name">
308
+ ${onlineIndicator}
309
+ <button class="peer-network-button" data-network-url="${networkUrl}"><i class="fa-solid fa-toggle-on"></i> Turn on peer network</button>
310
+ ${escapeHtml(process.name)}
311
+ </div>
312
+ </div>
313
+ `;
314
+ } else {
315
+ // Normal selectable item
316
+ const url = `http://${process.ip}`;
317
+ html += `
318
+ <div class="url-dropdown-item" data-url="${url}" data-host-type="${process.host.local ? "local" : "remote"}">
319
+ <div class="url-dropdown-name">
320
+ ${onlineIndicator}
321
+ ${escapeHtml(process.name)}
322
+ </div>
323
+ <div class="url-dropdown-url">${escapeHtml(url)}</div>
324
+ </div>
325
+ `;
326
+ }
327
+ });
328
+ });
162
329
 
163
- dropdown.innerHTML = items;
330
+ dropdown.innerHTML = html;
164
331
 
165
332
  // Add click handlers to dropdown items
166
- dropdown.querySelectorAll('.url-dropdown-item').forEach(item => {
333
+ dropdown.querySelectorAll('.url-dropdown-item:not(.non-selectable)').forEach(item => {
167
334
  item.addEventListener('click', function() {
168
335
  const url = this.getAttribute('data-url');
336
+ const type = this.getAttribute('data-host-type');
169
337
  urlInput.value = url;
338
+ urlInput.setAttribute("data-host-type", type)
170
339
  hideDropdown();
171
340
  // Submit the form
172
341
  urlInput.closest('form').dispatchEvent(new Event('submit'));
173
342
  });
174
343
  });
344
+
345
+ // Add click handlers to peer network buttons
346
+ dropdown.querySelectorAll('.peer-network-button').forEach(button => {
347
+ button.addEventListener('click', function(e) {
348
+ e.stopPropagation();
349
+ const networkUrl = this.getAttribute('data-network-url');
350
+ window.open(networkUrl, '_blank');
351
+ });
352
+ });
175
353
  }
176
354
 
177
355
  // Utility function to escape HTML
@@ -330,19 +508,54 @@ function initUrlDropdown(config = {}) {
330
508
  return;
331
509
  }
332
510
 
333
- const items = processes.map(process => {
334
- const url = `http://${process.ip}`;
335
- return `
336
- <div class="url-dropdown-item" data-url="${url}">
337
- <div class="url-dropdown-name">${escapeHtml(process.name)}</div>
338
- <div class="url-dropdown-url">${escapeHtml(url)}</div>
339
- </div>
340
- `;
341
- }).join('');
511
+ // Group processes by host
512
+ const groupedProcesses = groupProcessesByHost(processes);
513
+
514
+ let html = '';
515
+ Object.keys(groupedProcesses).forEach(hostKey => {
516
+ const hostData = groupedProcesses[hostKey];
517
+ const hostInfo = hostData.host;
518
+ const processes = hostData.processes;
519
+ const isLocal = hostData.isLocal;
520
+
521
+ // Add host header
522
+ html += createHostHeader(hostInfo, isLocal);
523
+
524
+ // Add processes for this host
525
+ processes.forEach(process => {
526
+ const onlineIndicator = process.online ?
527
+ '<div class="status-circle online"></div>' :
528
+ '<div class="status-circle offline"></div>';
529
+
530
+ if (process.ip === null || process.ip === undefined) {
531
+ // Non-selectable item with "turn on peer network" button
532
+ const networkUrl = `http://${process.host.ip}:42000/network`;
533
+ html += `
534
+ <div class="url-dropdown-item non-selectable">
535
+ <div class="url-dropdown-name">
536
+ ${onlineIndicator}
537
+ ${escapeHtml(process.name)}
538
+ </div>
539
+ <button class="peer-network-button" data-network-url="${networkUrl}"><i class="fa-solid fa-toggle-on"></i> Turn on peer network</button>
540
+ </div>
541
+ `;
542
+ } else {
543
+ // Normal selectable item
544
+ const url = `http://${process.ip}`;
545
+ html += `
546
+ <div class="url-dropdown-item" data-url="${url}" data-host-type="${process.host.local ? "local" : "remote"}">
547
+ ${onlineIndicator}
548
+ <div class="url-dropdown-name">${escapeHtml(process.name)}</div>
549
+ <div class="url-dropdown-url">${escapeHtml(url)}</div>
550
+ </div>
551
+ `;
552
+ }
553
+ });
554
+ });
342
555
 
343
- modalDropdown.innerHTML = items;
556
+ modalDropdown.innerHTML = html;
344
557
 
345
- modalDropdown.querySelectorAll('.url-dropdown-item').forEach(item => {
558
+ modalDropdown.querySelectorAll('.url-dropdown-item:not(.non-selectable)').forEach(item => {
346
559
  item.addEventListener('click', function() {
347
560
  const url = this.getAttribute('data-url');
348
561
  modalInput.value = url;
@@ -351,6 +564,15 @@ function initUrlDropdown(config = {}) {
351
564
  closeMobileModal();
352
565
  });
353
566
  });
567
+
568
+ // Add click handlers to peer network buttons in modal
569
+ modalDropdown.querySelectorAll('.peer-network-button').forEach(button => {
570
+ button.addEventListener('click', function(e) {
571
+ e.stopPropagation();
572
+ const networkUrl = this.getAttribute('data-network-url');
573
+ window.open(networkUrl, '_blank');
574
+ });
575
+ });
354
576
  }
355
577
 
356
578
  // Set up mobile button click handler
@@ -393,4 +615,4 @@ if (document.readyState === 'loading') {
393
615
  });
394
616
  } else {
395
617
  // DOM is already loaded, templates can initialize immediately
396
- }
618
+ }
@@ -1833,8 +1833,6 @@ body.minimized #fs-status {
1833
1833
  <div class='app-info-card'>
1834
1834
  <% if (config.icon) { %>
1835
1835
  <img src="<%=config.icon%>" onerror="this.src='/pinokio-black.png'"/>
1836
- <% } else { %>
1837
- <i class="fa-regular fa-circle-dot"></i>
1838
1836
  <% } %>
1839
1837
  <div class='app-info-container'>
1840
1838
  <div class='app-info-title'><%=config.title%></div>
@@ -749,6 +749,9 @@ body.dark .profile td {
749
749
  aside {
750
750
  padding: 0 10px;
751
751
  }
752
+ aside .tab.submenu {
753
+ padding: 10px;
754
+ }
752
755
  aside .tab i {
753
756
  width: 100%;
754
757
  }
@@ -300,6 +300,7 @@ iframe {
300
300
  }
301
301
  */
302
302
  </style>
303
+ <script src="/window_storage.js"></script>
303
304
  <script src="/popper.min.js"></script>
304
305
  <script src="/tippy-bundle.umd.min.js"></script>
305
306
  <script src="/hotkeys.min.js"></script>
@@ -363,7 +364,7 @@ iframe {
363
364
  </button>
364
365
  </h1>
365
366
  </header>
366
- <iframe src="<%=src%>"></iframe>
367
+ <iframe class='mainframe' src="<%=src%>"></iframe>
367
368
  <script src="/urldropdown.js"></script>
368
369
  <script>
369
370
  // Initialize URL Dropdown with restore behavior
@@ -333,6 +333,9 @@ body.dark aside .current.selected {
333
333
  aside {
334
334
  padding: 0 10px;
335
335
  }
336
+ aside .tab.submenu {
337
+ padding: 10px;
338
+ }
336
339
  aside .tab i {
337
340
  width: 100%;
338
341
  }
@@ -1421,6 +1421,9 @@ body.dark .ace-editor {
1421
1421
  aside {
1422
1422
  padding: 0 10px;
1423
1423
  }
1424
+ aside .tab.submenu {
1425
+ padding: 10px;
1426
+ }
1424
1427
  aside .tab i {
1425
1428
  width: 100%;
1426
1429
  }
@@ -280,7 +280,7 @@ body.dark .open-menu, body.dark .browse {
280
280
  }
281
281
  .section-container {
282
282
  display: grid;
283
- grid-template-columns: repeat(3, 1fr); /* Three equal columns */
283
+ grid-template-columns: repeat(2, 1fr); /* Three equal columns */
284
284
  /*
285
285
  grid-template-columns: repeat(3, minmax(0, 1fr));
286
286
  */
@@ -445,6 +445,9 @@ body.dark .net .mark {
445
445
  aside {
446
446
  padding: 0 10px;
447
447
  }
448
+ aside .tab.submenu {
449
+ padding: 10px;
450
+ }
448
451
  aside .tab i {
449
452
  width: 100%;
450
453
  }
@@ -608,7 +611,9 @@ document.addEventListener('DOMContentLoaded', function() {
608
611
  <h3>
609
612
  <div class='item-icon'>
610
613
  <% if (item.icon) { %>
611
- <img src="<%=item.icon%>">
614
+ <div class='placeholder-icon'>
615
+ <img src="<%=item.icon%>" onerror="this.src='/pinokio-black.png'"/>
616
+ </div>
612
617
  <% } else { %>
613
618
  <div class='placeholder-icon'>
614
619
  <i class="fa-solid fa-database"></i>
@@ -619,31 +624,25 @@ document.addEventListener('DOMContentLoaded', function() {
619
624
  <div class='title'><i class="fa-solid fa-circle"></i><span><%=item.title || item.name%></span></div>
620
625
  <div class='grid-3'>
621
626
  <div class='section'>
622
- <% if (item.internal_router.length > 0) { %>
623
- <% item.internal_router.forEach((domain) => { %>
624
- <a class='net' target="_blank" href="https://<%=domain%>"><span class='mark'>HTTPS</span><span><%=domain%></span></a>
625
- <% }) %>
626
- <% } else { %>
627
- <a class='net' target="_blank" href="http://localhost:<%=item.port%>"><span class='mark'>HTTP</span><span>localhost:<%=item.port%></span></a>
627
+ <% item.internal_router.forEach((domain) => { %>
628
+ <a class='net' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
629
+ <% }) %>
630
+ <a class='net' target="_blank" href="http://localhost:<%=item.port%>">http://localhost:<%=item.port%></a>
631
+ </div>
632
+ <div class='section'>
633
+ <% if (item.external_ip) { %>
634
+ <a class='net' target="_blank" href="http://<%=item.external_ip%>">http://<%=item.external_ip%></a>
628
635
  <% } %>
629
636
  </div>
630
- <% if (item.external_router.length > 0) { %>
631
- <div class='section'>
632
- <% item.external_router.forEach((domain) => { %>
633
- <a class='net' target="_blank" href="https://<%=domain%>"><span class='mark'>HTTPS</span><span><%=domain%></span></a>
634
- <% }) %>
635
- </div>
636
- <% } else { %>
637
- <div class='section'>
638
- <% if (item.external_ip) { %>
639
- <a class='net' target="_blank" href="http://<%=item.external_ip%>"><span class='mark'>HTTP</span><span><%=item.external_ip%></span></a>
640
- <% } %>
641
- </div>
642
- <% } %>
637
+ <div class='section'>
638
+ <% item.external_router.forEach((domain) => { %>
639
+ <a class='net' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
640
+ <% }) %>
641
+ </div>
643
642
  </div>
644
643
  </div>
645
- </div>
646
- </h3>
644
+ </h3>
645
+ </div>
647
646
  <% }) %>
648
647
  <% } else { %>
649
648
  <div class='section-container'>
@@ -653,7 +652,7 @@ document.addEventListener('DOMContentLoaded', function() {
653
652
  <div class='col'>
654
653
  <div class='grid-1'>
655
654
  <div class='section'>
656
- <h2>Online</h2><div>Use these URLs to access the online remote servers.</div>
655
+ <h2><i class="fa-solid fa-plug-circle-check"></i> Online</h2><div>Use these URLs to access the online remote servers.</div>
657
656
  </div>
658
657
  </div>
659
658
  </div>
@@ -664,7 +663,7 @@ document.addEventListener('DOMContentLoaded', function() {
664
663
  <h3>
665
664
  <div class='item-icon'>
666
665
  <% if (item[`${protocol}_icon`]) { %>
667
- <img src="<%=item[`${protocol}_icon`]%>">
666
+ <img src="<%=item[`${protocol}_icon`]%>" onerror="this.src='/pinokio-black.png'"/>
668
667
  <% } else { %>
669
668
  <div class='placeholder-icon'>
670
669
  <i class="fa-solid fa-database"></i>
@@ -697,7 +696,7 @@ document.addEventListener('DOMContentLoaded', function() {
697
696
  <div class='col'>
698
697
  <div class='grid-1'>
699
698
  <div class='section'>
700
- <h2>Installed</h2><div>Remotely launch the installed apps.</div>
699
+ <h2><i class="fa-solid fa-folder-tree"></i> Installed</h2><div>Remotely launch the installed apps.</div>
701
700
  </div>
702
701
  </div>
703
702
  </div>
@@ -708,7 +707,7 @@ document.addEventListener('DOMContentLoaded', function() {
708
707
  <h3>
709
708
  <div class='item-icon'>
710
709
  <% if (item[`${protocol}_icon`]) { %>
711
- <img src="<%=item[`${protocol}_icon`]%>">
710
+ <img src="<%=item[`${protocol}_icon`]%>" onerror="this.src='/pinokio-black.png'"/>
712
711
  <% } else { %>
713
712
  <div class='placeholder-icon'>
714
713
  <i class="fa-solid fa-database"></i>
@@ -734,6 +733,7 @@ document.addEventListener('DOMContentLoaded', function() {
734
733
  </h3>
735
734
  <% }) %>
736
735
  </div>
736
+ <!--
737
737
  <div class='section-col'>
738
738
  <div class='section-header'>
739
739
  <h3>
@@ -770,6 +770,7 @@ document.addEventListener('DOMContentLoaded', function() {
770
770
  </h3>
771
771
  <% }) %>
772
772
  </div>
773
+ -->
773
774
  </div>
774
775
  <% } %>
775
776
  </div>
@@ -831,6 +832,7 @@ let filteredCount = list.length
831
832
  let filteredBtnsCount = 0
832
833
 
833
834
  const renderSearch = () => {
835
+ console.log("renderSearch")
834
836
  let target = document.querySelector("form input[type=search]")
835
837
  let result
836
838
  if (target.value.trim().length === 0) {
@@ -841,6 +843,7 @@ const renderSearch = () => {
841
843
  result = search(list, target.value)
842
844
  }
843
845
  let all = document.querySelectorAll(".line.index")
846
+ console.log("all", all)
844
847
  for(let el of all) {
845
848
  el.classList.add("hidden")
846
849
  el.classList.remove("selected")