SimpleCodeTM commited on
Commit
e1620b2
·
verified ·
1 Parent(s): 262c881

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +454 -664
  2. prompts.txt +6 -1
index.html CHANGED
@@ -3,708 +3,498 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Интерактивное дерево с плавным перетаскиванием</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
- .tree-node {
11
- transition: all 0.2s ease;
12
- position: relative;
13
- }
14
- .tree-node:hover {
15
- background-color: #f3f4f6;
16
  }
17
- .tree-node.dragging {
18
- opacity: 0.5;
19
- background-color: #e5e7eb;
20
  }
21
- .tree-node-placeholder {
22
- border: 2px dashed #3b82f6;
23
- background-color: #eff6ff;
24
- height: 40px;
25
- margin: 4px 0;
26
- border-radius: 4px;
27
- transition: all 0.1s ease;
28
  }
29
- .nested {
30
  display: none;
 
 
31
  transition: all 0.3s ease;
32
  }
33
- .nested.active {
34
- display: block;
35
- animation: fadeIn 0.3s ease-in-out;
 
 
36
  }
37
- @keyframes fadeIn {
38
- from { opacity: 0; transform: translateY(-10px); }
39
- to { opacity: 1; transform: translateY(0); }
 
40
  }
41
- .drag-handle {
42
- cursor: move;
43
- opacity: 0.5;
44
- transition: opacity 0.2s ease;
 
45
  }
46
- .drag-handle:hover {
47
- opacity: 1;
48
  }
49
- .drag-ghost {
50
- position: absolute;
51
- z-index: 1000;
52
- opacity: 0.8;
53
- pointer-events: none;
54
- background: white;
55
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
56
- border-radius: 0.375rem;
57
- border: 1px solid #e5e7eb;
58
- transform: translate(0, 0);
59
- transition: transform 0.1s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
  </style>
62
  </head>
63
- <body class="bg-gray-50 font-sans p-6">
64
- <div class="max-w-4xl mx-auto">
65
- <div class="bg-white rounded-xl shadow-md overflow-hidden">
66
- <div class="p-6">
67
- <h1 class="text-2xl font-bold text-gray-800 mb-6">Интерактивное дерево с плавным перетаскиванием</h1>
68
-
69
- <div class="flex space-x-4 mb-6">
70
- <button id="addRootNode" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center space-x-2">
71
- <i class="fas fa-plus"></i>
72
- <span>Добавить корневой элемент</span>
73
- </button>
74
- <button id="expandAll" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg flex items-center space-x-2">
75
- <i class="fas fa-expand"></i>
76
- <span>Развернуть все</span>
77
- </button>
78
- <button id="collapseAll" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg flex items-center space-x-2">
79
- <i class="fas fa-compress"></i>
80
- <span>Свернуть все</span>
81
- </button>
82
- </div>
83
-
84
- <div id="treeContainer" class="border border-gray-200 rounded-lg p-4 min-h-40">
85
- <!-- Дерево будет сгенерировано здесь -->
86
- <div id="treeRoot" class="space-y-1"></div>
87
  </div>
88
- </div>
89
- </div>
90
- </div>
91
-
92
- <!-- Модальное окно для добавления/редактирования узла -->
93
- <div id="nodeModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
94
- <div class="bg-white rounded-lg p-6 max-w-md w-full">
95
- <div class="flex justify-between items-start mb-4">
96
- <h3 class="text-lg font-medium text-gray-900" id="modalTitle">Добавить узел</h3>
97
- <button id="closeNodeModal" class="text-gray-400 hover:text-gray-500">
98
- <i class="fas fa-times"></i>
99
  </button>
100
  </div>
101
- <div class="mb-4">
102
- <label for="nodeName" class="block text-sm font-medium text-gray-700 mb-1">Название узла</label>
103
- <input type="text" id="nodeName" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
104
- </div>
105
- <div class="flex justify-end space-x-3">
106
- <button id="cancelNode" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">
107
- Отмена
108
- </button>
109
- <button id="saveNode" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
110
- Сохранить
111
- </button>
112
  </div>
113
- </div>
114
- </div>
115
-
116
- <script>
117
- // Инициализация дерева
118
- let treeData = [
119
- {
120
- id: 1,
121
- name: "Корневой элемент 1",
122
- children: [
123
- {
124
- id: 2,
125
- name: "Дочерний элемент 1.1",
126
- children: [
127
- {
128
- id: 3,
129
- name: "Вложенный элемент 1.1.1",
130
- children: []
131
- },
132
- {
133
- id: 4,
134
- name: "Вложенный элемент 1.1.2",
135
- children: []
136
- }
137
- ]
138
- },
139
- {
140
- id: 5,
141
- name: "Дочерний элемент 1.2",
142
- children: []
143
- }
144
- ]
145
- },
146
- {
147
- id: 6,
148
- name: "Корневой элемент 2",
149
- children: []
150
- }
151
- ];
152
-
153
- // Переменные для управления состоянием
154
- let nextId = 7;
155
- let currentNodeId = null;
156
- let currentParentId = null;
157
- let isEditing = false;
158
- let draggedNode = null;
159
- let draggedNodeParent = null;
160
- let draggedNodeIndex = null;
161
- let dragGhost = null;
162
- let lastDragPosition = { x: 0, y: 0 };
163
- let placeholder = null;
164
- let isDragging = false;
165
- let targetParentId = null;
166
- let targetIndex = null;
167
-
168
- // DOM элементы
169
- const treeRoot = document.getElementById('treeRoot');
170
- const nodeModal = document.getElementById('nodeModal');
171
- const nodeNameInput = document.getElementById('nodeName');
172
- const modalTitle = document.getElementById('modalTitle');
173
- const addRootNodeBtn = document.getElementById('addRootNode');
174
- const expandAllBtn = document.getElementById('expandAll');
175
- const collapseAllBtn = document.getElementById('collapseAll');
176
-
177
- // Инициализация дерева при загрузке
178
- document.addEventListener('DOMContentLoaded', () => {
179
- renderTree();
180
- setupEventListeners();
181
- });
182
-
183
- // Рендер дерева
184
- function renderTree(data = treeData, parentElement = treeRoot, level = 0) {
185
- parentElement.innerHTML = '';
186
 
187
- if (data.length === 0 && parentElement === treeRoot) {
188
- parentElement.innerHTML = '<p class="text-gray-500 italic">Дерево пустое</p>';
189
- return;
190
- }
191
-
192
- data.forEach((node, index) => {
193
- const hasChildren = node.children && node.children.length > 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
- const nodeElement = document.createElement('div');
196
- nodeElement.className = 'tree-node pl-' + (level * 4);
197
- nodeElement.dataset.id = node.id;
198
- nodeElement.dataset.parentId = parentElement.dataset.id || 'root';
199
- nodeElement.dataset.index = index;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
- nodeElement.innerHTML = `
202
- <div class="flex items-center py-2 px-3 rounded-lg border border-gray-200">
203
- <div class="flex items-center flex-1">
204
- <span class="drag-handle mr-2 text-gray-400 cursor-move">
205
- <i class="fas fa-grip-vertical"></i>
206
- </span>
207
- ${hasChildren ? `
208
- <button class="toggle-node mr-2 text-gray-500 hover:text-gray-700" data-id="${node.id}">
209
- <i class="fas fa-caret-right"></i>
210
- </button>
211
- ` : '<span class="w-6"></span>'}
212
- <span class="node-name">${node.name}</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  </div>
214
- <div class="flex space-x-2">
215
- <button class="edit-node p-1 text-blue-500 hover:text-blue-700" data-id="${node.id}">
216
- <i class="fas fa-edit"></i>
217
- </button>
218
- <button class="add-child p-1 text-green-500 hover:text-green-700" data-id="${node.id}">
219
- <i class="fas fa-plus"></i>
220
- </button>
221
- <button class="delete-node p-1 text-red-500 hover:text-red-700" data-id="${node.id}">
222
- <i class="fas fa-trash"></i>
223
- </button>
 
 
 
 
224
  </div>
225
  </div>
226
- ${hasChildren ? `
227
- <div class="nested pl-4" data-parent-id="${node.id}"></div>
228
- ` : ''}
229
- `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
- parentElement.appendChild(nodeElement);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
- // Рендерим детей, если они есть
234
- if (hasChildren) {
235
- const nestedContainer = nodeElement.querySelector('.nested');
236
- renderTree(node.children, nestedContainer, level + 1);
237
- }
238
- });
239
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
 
241
- // Настройка обработчиков событий
242
- function setupEventListeners() {
243
- // Кнопки модального окна
244
- document.getElementById('closeNodeModal').addEventListener('click', closeNodeModal);
245
- document.getElementById('cancelNode').addEventListener('click', closeNodeModal);
246
- document.getElementById('saveNode').addEventListener('click', saveNode);
247
-
248
- // Кнопки управления деревом
249
- addRootNodeBtn.addEventListener('click', () => {
250
- openNodeModal(null, null, false);
251
- });
252
-
253
- expandAllBtn.addEventListener('click', expandAllNodes);
254
- collapseAllBtn.addEventListener('click', collapseAllNodes);
255
-
256
- // Делегирование событий для динамически созданных элементов
257
- treeRoot.addEventListener('click', (e) => {
258
- const target = e.target.closest('.toggle-node');
259
- if (target) {
260
- toggleNode(target.dataset.id);
261
- return;
262
- }
263
-
264
- const editBtn = e.target.closest('.edit-node');
265
- if (editBtn) {
266
- openNodeModal(editBtn.dataset.id, null, true);
267
- return;
268
- }
269
-
270
- const addChildBtn = e.target.closest('.add-child');
271
- if (addChildBtn) {
272
- openNodeModal(null, addChildBtn.dataset.id, false);
273
- return;
274
- }
275
-
276
- const deleteBtn = e.target.closest('.delete-node');
277
- if (deleteBtn) {
278
- deleteNode(deleteBtn.dataset.id);
279
- return;
280
- }
281
- });
282
-
283
- // Перетаскивание
284
- setupDragAndDrop();
285
- }
286
 
287
- // Настройка плавного перетаскивания
288
- function setupDragAndDrop() {
289
- document.addEventListener('mousedown', (e) => {
290
- const handle = e.target.closest('.drag-handle');
291
- if (!handle) return;
292
-
293
- const nodeElement = handle.closest('.tree-node');
294
- if (!nodeElement) return;
295
-
296
- draggedNode = findNodeById(treeData, nodeElement.dataset.id);
297
- draggedNodeParent = nodeElement.dataset.parentId === 'root' ? treeData :
298
- findNodeById(treeData, nodeElement.dataset.parentId).children;
299
- draggedNodeIndex = parseInt(nodeElement.dataset.index);
300
-
301
- // Создаем призрачный элемент для перетаскивания
302
- dragGhost = nodeElement.cloneNode(true);
303
- dragGhost.classList.add('drag-ghost');
304
- dragGhost.style.width = nodeElement.offsetWidth + 'px';
305
- dragGhost.style.left = nodeElement.getBoundingClientRect().left + 'px';
306
- dragGhost.style.top = nodeElement.getBoundingClientRect().top + 'px';
307
- document.body.appendChild(dragGhost);
308
-
309
- // Сохраняем начальную позицию
310
- lastDragPosition = { x: e.clientX, y: e.clientY };
311
- isDragging = true;
312
-
313
- // Добавляем класс для визуального эффекта
314
- nodeElement.classList.add('dragging');
315
-
316
- // Отключаем выделение текста при перетаскивании
317
- document.body.style.userSelect = 'none';
318
-
319
- // Обработчики для плавного перетаскивания
320
- document.addEventListener('mousemove', handleDragMove);
321
- document.addEventListener('mouseup', handleDragEnd);
322
-
323
- e.preventDefault();
324
- });
325
-
326
- function handleDragMove(e) {
327
- if (!isDragging || !dragGhost) return;
328
-
329
- // Вычисляем смещение
330
- const dx = e.clientX - lastDragPosition.x;
331
- const dy = e.clientY - lastDragPosition.y;
332
-
333
- // Обновляем позицию призрака
334
- const ghostRect = dragGhost.getBoundingClientRect();
335
- dragGhost.style.left = (ghostRect.left + dx) + 'px';
336
- dragGhost.style.top = (ghostRect.top + dy) + 'px';
337
-
338
- // Обновляем последнюю позицию
339
- lastDragPosition = { x: e.clientX, y: e.clientY };
340
-
341
- // Определяем элемент под курсором
342
- const elements = document.elementsFromPoint(e.clientX, e.clientY);
343
- let targetElement = null;
344
-
345
- for (const el of elements) {
346
- if (el.classList.contains('tree-node') || el.classList.contains('nested') || el.id === 'treeRoot') {
347
- targetElement = el;
348
- break;
349
  }
350
- }
351
-
352
- // Обработка позиционирования плейсхолдера
353
- if (targetElement) {
354
- // Удаляем старый плейсхолдер
355
- removePlaceholder();
356
-
357
- if (targetElement.classList.contains('tree-node')) {
358
- const rect = targetElement.getBoundingClientRect();
359
- const midpoint = rect.top + rect.height / 2;
360
-
361
- // Определяем, куда вставлять - выше или ниже узла
362
- if (e.clientY < midpoint) {
363
- showPlaceholder(targetElement, 'before');
364
- targetParentId = targetElement.dataset.parentId;
365
- targetIndex = parseInt(targetElement.dataset.index);
366
- } else {
367
- const hasChildren = targetElement.querySelector('.toggle-node') !== null;
368
-
369
- if (hasChildren) {
370
- const nested = targetElement.querySelector('.nested');
371
- if (!nested.classList.contains('active')) {
372
- // Если узел свернут, показывае�� плейсхолдер внутри
373
- showPlaceholder(nested, 'first');
374
- targetParentId = targetElement.dataset.id;
375
- targetIndex = 0;
376
- } else {
377
- // Если узел развернут, показываем плейсхолдер после
378
- showPlaceholder(targetElement, 'after');
379
- targetParentId = targetElement.dataset.parentId;
380
- targetIndex = parseInt(targetElement.dataset.index) + 1;
381
- }
382
- } else {
383
- showPlaceholder(targetElement, 'after');
384
- targetParentId = targetElement.dataset.parentId;
385
- targetIndex = parseInt(targetElement.dataset.index) + 1;
386
  }
387
  }
388
- }
389
- else if (targetElement.classList.contains('nested')) {
390
- const children = Array.from(targetElement.children).filter(el => el.classList.contains('tree-node'));
391
-
392
- if (children.length === 0) {
393
- showPlaceholder(targetElement, 'first');
394
- targetParentId = targetElement.dataset.parentId;
395
- targetIndex = 0;
396
- } else {
397
- const lastChild = children[children.length - 1];
398
- showPlaceholder(lastChild, 'after');
399
- targetParentId = targetElement.dataset.parentId;
400
- targetIndex = children.length;
401
- }
402
- }
403
- else if (targetElement.id === 'treeRoot') {
404
- const children = Array.from(targetElement.children).filter(el => el.classList.contains('tree-node'));
405
-
406
- if (children.length === 0) {
407
- showPlaceholder(targetElement, 'first');
408
- targetParentId = 'root';
409
- targetIndex = 0;
410
- } else {
411
- const lastChild = children[children.length - 1];
412
- showPlaceholder(lastChild, 'after');
413
- targetParentId = 'root';
414
- targetIndex = children.length;
415
- }
416
- }
417
- }
418
- }
419
-
420
- function handleDragEnd(e) {
421
- if (!isDragging) return;
422
-
423
- // Удаляем призрака
424
- if (dragGhost) {
425
- dragGhost.remove();
426
- dragGhost = null;
427
- }
428
-
429
- // Удаляем плейсхолдер
430
- removePlaceholder();
431
-
432
- // Восстанавливаем выделение текста
433
- document.body.style.userSelect = '';
434
-
435
- // Удаляем обработчики
436
- document.removeEventListener('mousemove', handleDragMove);
437
- document.removeEventListener('mouseup', handleDragEnd);
438
-
439
- // Если есть перетаскиваемый узел и целевая позиция
440
- if (draggedNode && targetParentId !== null && targetIndex !== null) {
441
- // Определяем новый родительский массив
442
- let newParentArray;
443
- if (targetParentId === 'root') {
444
- newParentArray = treeData;
445
- } else {
446
- const parentNode = findNodeById(treeData, targetParentId);
447
- if (parentNode) {
448
- newParentArray = parentNode.children;
449
- } else {
450
- newParentArray = treeData;
451
- }
452
- }
453
-
454
- // Проверяем, что перемещение допустимо (не в самого себя или своих потомков)
455
- if (!isDescendant(draggedNode, targetParentId === 'root' ? null : findNodeById(treeData, targetParentId))) {
456
- // Удаляем узел из старого мес��а
457
- const oldIndex = draggedNodeParent.indexOf(draggedNode);
458
- if (oldIndex !== -1) {
459
- draggedNodeParent.splice(oldIndex, 1);
460
- }
461
-
462
- // Вставляем узел в новое место
463
- if (targetIndex > newParentArray.length) {
464
- targetIndex = newParentArray.length;
465
- }
466
- newParentArray.splice(targetIndex, 0, draggedNode);
467
-
468
- // Перерисовываем дерево
469
- renderTree();
470
-
471
- // Автоматически раскрываем родительский узел, если нужно
472
- if (targetParentId !== 'root') {
473
- const parentElement = document.querySelector(`.tree-node[data-id="${targetParentId}"]`);
474
- if (parentElement) {
475
- const nested = parentElement.querySelector('.nested');
476
- if (nested && !nested.classList.contains('active')) {
477
- toggleNode(targetParentId);
478
- }
479
- }
480
  }
481
  }
482
  }
483
-
484
- // Сбрасываем состояние перетаскивания
485
- resetDragState();
486
-
487
- // Удаляем класс dragging со всех элементов
488
- document.querySelectorAll('.tree-node.dragging').forEach(el => {
489
- el.classList.remove('dragging');
490
- });
491
-
492
- isDragging = false;
493
- targetParentId = null;
494
- targetIndex = null;
495
- }
496
- }
497
-
498
- // Показать плейсхолдер для перетаскивания
499
- function showPlaceholder(element, position) {
500
- removePlaceholder();
501
-
502
- placeholder = document.createElement('div');
503
- placeholder.className = 'tree-node-placeholder';
504
- placeholder.dataset.position = position;
505
-
506
- if (position === 'before') {
507
- element.parentNode.insertBefore(placeholder, element);
508
- }
509
- else if (position === 'after') {
510
- element.parentNode.insertBefore(placeholder, element.nextSibling);
511
- }
512
- else if (position === 'first') {
513
- element.insertBefore(placeholder, element.firstChild);
514
- }
515
- else if (position === 'last') {
516
- element.appendChild(placeholder);
517
- }
518
- }
519
-
520
- // Удалить плейсхолдер
521
- function removePlaceholder() {
522
- if (placeholder) {
523
- placeholder.remove();
524
- placeholder = null;
525
- }
526
- }
527
-
528
- // Сбросить состояние перетаскивания
529
- function resetDragState() {
530
- draggedNode = null;
531
- draggedNodeParent = null;
532
- draggedNodeIndex = null;
533
- }
534
-
535
- // Проверить, является ли узел потомком другого узла
536
- function isDescendant(node, parentNode) {
537
- if (!parentNode) return false;
538
- if (node.id === parentNode.id) return true;
539
-
540
- // Проверяем всех детей родительского узла
541
- for (const child of parentNode.children) {
542
- if (isDescendant(node, child)) {
543
- return true;
544
- }
545
- }
546
-
547
- return false;
548
- }
549
-
550
- // Найти узел по ID
551
- function findNodeById(data, id) {
552
- for (let i = 0; i < data.length; i++) {
553
- if (data[i].id == id) {
554
- return data[i];
555
- }
556
-
557
- if (data[i].children && data[i].children.length > 0) {
558
- const found = findNodeById(data[i].children, id);
559
- if (found) return found;
560
- }
561
- }
562
-
563
- return null;
564
- }
565
-
566
- // Найти родительский узел
567
- function findParentNode(data, id, parent = null) {
568
- for (let i = 0; i < data.length; i++) {
569
- if (data[i].id == id) {
570
- return parent;
571
- }
572
-
573
- if (data[i].children && data[i].children.length > 0) {
574
- const found = findParentNode(data[i].children, id, data[i]);
575
- if (found) return found;
576
- }
577
- }
578
-
579
- return null;
580
- }
581
-
582
- // Открыть модальное окно для добавления/редактирования узла
583
- function openNodeModal(nodeId, parentId, editMode) {
584
- currentNodeId = nodeId;
585
- currentParentId = parentId;
586
- isEditing = editMode;
587
-
588
- if (editMode) {
589
- modalTitle.textContent = 'Редактировать узел';
590
- const node = findNodeById(treeData, nodeId);
591
- nodeNameInput.value = node.name;
592
- } else {
593
- modalTitle.textContent = parentId ? 'Добавить дочерний узел' : 'Добавить корневой узел';
594
- nodeNameInput.value = '';
595
- }
596
-
597
- nodeModal.classList.remove('hidden');
598
- nodeNameInput.focus();
599
- }
600
-
601
- // Закрыть модальное окно
602
- function closeNodeModal() {
603
- nodeModal.classList.add('hidden');
604
- }
605
-
606
- // Сохранить узел
607
- function saveNode() {
608
- const name = nodeNameInput.value.trim();
609
-
610
- if (!name) {
611
- alert('Пожалуйста, введите название узла');
612
- return;
613
- }
614
-
615
- if (isEditing) {
616
- // Редактирование существующего узла
617
- const node = findNodeById(treeData, currentNodeId);
618
- if (node) {
619
- node.name = name;
620
- }
621
- } else {
622
- // Добавление нового узла
623
- const newNode = {
624
- id: nextId++,
625
- name: name,
626
- children: []
627
- };
628
-
629
- if (currentParentId) {
630
- // Добавляем как дочерний узел
631
- const parentNode = findNodeById(treeData, currentParentId);
632
- if (parentNode) {
633
- parentNode.children.push(newNode);
634
- }
635
- } else {
636
- // Добавляем как корневой узел
637
- treeData.push(newNode);
638
- }
639
- }
640
-
641
- // Перерисовываем дерево
642
- renderTree();
643
- closeNodeModal();
644
- }
645
-
646
- // Удалить узел
647
- function deleteNode(nodeId) {
648
- if (!confirm('Вы уверены, что хотите удалить этот узел и все его дочерние элементы?')) {
649
- return;
650
  }
651
-
652
- const parent = findParentNode(treeData, nodeId);
653
-
654
- if (parent) {
655
- // Удаляем из дочерних элементов родителя
656
- parent.children = parent.children.filter(node => node.id != nodeId);
657
- } else {
658
- // Удаляем из корневых элементов
659
- treeData = treeData.filter(node => node.id != nodeId);
660
- }
661
-
662
- // Перерисовываем дерево
663
- renderTree();
664
- }
665
-
666
- // Переключить видимость дочерних узлов
667
- function toggleNode(nodeId) {
668
- const nodeElement = document.querySelector(`.tree-node[data-id="${nodeId}"]`);
669
- if (!nodeElement) return;
670
-
671
- const nestedContainer = nodeElement.querySelector('.nested');
672
- if (!nestedContainer) return;
673
-
674
- const toggleBtn = nodeElement.querySelector('.toggle-node');
675
-
676
- if (nestedContainer.classList.contains('active')) {
677
- // Скрываем
678
- nestedContainer.classList.remove('active');
679
- toggleBtn.innerHTML = '<i class="fas fa-caret-right"></i>';
680
- } else {
681
- // Показываем
682
- nestedContainer.classList.add('active');
683
- toggleBtn.innerHTML = '<i class="fas fa-caret-down"></i>';
684
- }
685
- }
686
-
687
- // Развернуть все узлы
688
- function expandAllNodes() {
689
- document.querySelectorAll('.nested').forEach(nested => {
690
- nested.classList.add('active');
691
- });
692
-
693
- document.querySelectorAll('.toggle-node').forEach(btn => {
694
- btn.innerHTML = '<i class="fas fa-caret-down"></i>';
695
- });
696
- }
697
 
698
- // Свернуть все узлы
699
- function collapseAllNodes() {
700
- document.querySelectorAll('.nested').forEach(nested => {
701
- nested.classList.remove('active');
702
- });
703
-
704
- document.querySelectorAll('.toggle-node').forEach(btn => {
705
- btn.innerHTML = '<i class="fas fa-caret-right"></i>';
706
- });
707
- }
708
  </script>
709
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=SimpleCodeTM/tree-moved" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
710
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Админпанель | Интернет-магазин</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ .sidebar {
11
+ transition: all 0.3s ease;
12
+ z-index: 50;
 
 
 
13
  }
14
+ .sidebar.collapsed {
15
+ width: 70px;
 
16
  }
17
+ .sidebar.collapsed .nav-text {
18
+ display: none;
 
 
 
 
 
19
  }
20
+ .sidebar.collapsed .logo-text {
21
  display: none;
22
+ }
23
+ .main-content {
24
  transition: all 0.3s ease;
25
  }
26
+ .sidebar.collapsed + .main-content {
27
+ margin-left: 70px;
28
+ }
29
+ .chart-container {
30
+ height: 300px;
31
  }
32
+ .order-status-badge {
33
+ font-size: 12px;
34
+ padding: 3px 8px;
35
+ border-radius: 12px;
36
  }
37
+ .product-image-thumb {
38
+ width: 60px;
39
+ height: 60px;
40
+ object-fit: cover;
41
+ border-radius: 4px;
42
  }
43
+ .mobile-menu-button {
44
+ display: none;
45
  }
46
+ @media (max-width: 1024px) {
47
+ .sidebar {
48
+ transform: translateX(-100%);
49
+ position: fixed;
50
+ height: 100vh;
51
+ }
52
+ .sidebar.active {
53
+ transform: translateX(0);
54
+ }
55
+ .main-content {
56
+ margin-left: 0 !important;
57
+ }
58
+ .mobile-menu-button {
59
+ display: block;
60
+ }
61
+ .stats-grid {
62
+ grid-template-columns: repeat(2, 1fr) !important;
63
+ }
64
+ }
65
+ @media (max-width: 640px) {
66
+ .stats-grid {
67
+ grid-template-columns: 1fr !important;
68
+ }
69
+ .charts-grid {
70
+ grid-template-columns: 1fr !important;
71
+ }
72
+ .order-table th, .order-table td {
73
+ padding: 0.5rem !important;
74
+ font-size: 0.875rem;
75
+ }
76
+ .header-title {
77
+ font-size: 1.25rem !important;
78
+ }
79
  }
80
  </style>
81
  </head>
82
+ <body class="bg-gray-100 font-sans">
83
+ <div class="flex h-screen overflow-hidden">
84
+ <!-- Боковая панель -->
85
+ <div class="sidebar bg-indigo-800 text-white w-64 flex flex-col fixed h-full">
86
+ <div class="p-4 flex items-center justify-between border-b border-indigo-700">
87
+ <div class="flex items-center">
88
+ <i class="fas fa-store text-2xl mr-3"></i>
89
+ <span class="logo-text text-xl font-bold">Магазин PRO</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  </div>
91
+ <button id="toggleSidebar" class="text-white focus:outline-none">
92
+ <i class="fas fa-bars"></i>
 
 
 
 
 
 
 
 
 
93
  </button>
94
  </div>
95
+
96
+ <div class="p-4 border-b border-indigo-700 flex items-center">
97
+ <div class="w-10 h-10 rounded-full bg-indigo-600 flex items-center justify-center mr-3">
98
+ <i class="fas fa-user"></i>
99
+ </div>
100
+ <div class="nav-text">
101
+ <div class="font-medium">Администратор</div>
102
+ <div class="text-xs text-indigo-300">admin@example.com</div>
103
+ </div>
 
 
104
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
+ <nav class="flex-1 overflow-y-auto">
107
+ <div class="p-2">
108
+ <div class="text-indigo-300 uppercase text-xs font-bold px-4 py-2 nav-text">Главное</div>
109
+ <a href="#" class="flex items-center px-4 py-3 text-white bg-indigo-900 rounded-lg mx-2">
110
+ <i class="fas fa-tachometer-alt mr-3"></i>
111
+ <span class="nav-text">Панель управления</span>
112
+ </a>
113
+ <a href="#" class="flex items-center px-4 py-3 text-indigo-200 hover:bg-indigo-700 rounded-lg mx-2 mt-1">
114
+ <i class="fas fa-shopping-cart mr-3"></i>
115
+ <span class="nav-text">Заказы</span>
116
+ <span class="ml-auto bg-red-500 text-white text-xs px-2 py-1 rounded-full">15</span>
117
+ </a>
118
+ <a href="#" class="flex items-center px-4 py-3 text-indigo-200 hover:bg-indigo-700 rounded-lg mx-2 mt-1">
119
+ <i class="fas fa-box-open mr-3"></i>
120
+ <span class="nav-text">Товары</span>
121
+ </a>
122
+ <a href="#" class="flex items-center px-4 py-3 text-indigo-200 hover:bg-indigo-700 rounded-lg mx-2 mt-1">
123
+ <i class="fas fa-users mr-3"></i>
124
+ <span class="nav-text">Клиенты</span>
125
+ </a>
126
+ <a href="#" class="flex items-center px-4 py-3 text-indigo-200 hover:bg-indigo-700 rounded-lg mx-2 mt-1">
127
+ <i class="fas fa-tags mr-3"></i>
128
+ <span class="nav-text">Категории</span>
129
+ </a>
130
+ </div>
131
 
132
+ <div class="p-2 mt-4">
133
+ <div class="text-indigo-300 uppercase text-xs font-bold px-4 py-2 nav-text">Дополнительно</div>
134
+ <a href="#" class="flex items-center px-4 py-3 text-indigo-200 hover:bg-indigo-700 rounded-lg mx-2 mt-1">
135
+ <i class="fas fa-chart-line mr-3"></i>
136
+ <span class="nav-text">Аналитика</span>
137
+ </a>
138
+ <a href="#" class="flex items-center px-4 py-3 text-indigo-200 hover:bg-indigo-700 rounded-lg mx-2 mt-1">
139
+ <i class="fas fa-comment-alt mr-3"></i>
140
+ <span class="nav-text">Отзывы</span>
141
+ <span class="ml-auto bg-yellow-500 text-white text-xs px-2 py-1 rounded-full">3</span>
142
+ </a>
143
+ <a href="#" class="flex items-center px-4 py-3 text-indigo-200 hover:bg-indigo-700 rounded-lg mx-2 mt-1">
144
+ <i class="fas fa-cog mr-3"></i>
145
+ <span class="nav-text">Настройки</span>
146
+ </a>
147
+ </div>
148
+ </nav>
149
+
150
+ <div class="p-4 border-t border-indigo-700">
151
+ <a href="#" class="flex items-center px-4 py-2 text-indigo-200 hover:bg-indigo-700 rounded-lg">
152
+ <i class="fas fa-sign-out-alt mr-3"></i>
153
+ <span class="nav-text">Выйти</span>
154
+ </a>
155
+ </div>
156
+ </div>
157
+
158
+ <!-- Основное содержимое -->
159
+ <div class="main-content flex-1 overflow-auto ml-64">
160
+ <!-- Верхняя панель -->
161
+ <header class="bg-white shadow-sm py-4 px-6 flex items-center justify-between">
162
+ <div class="flex items-center">
163
+ <button id="mobileMenuButton" class="mobile-menu-button text-gray-500 mr-4 focus:outline-none">
164
+ <i class="fas fa-bars text-xl"></i>
165
+ </button>
166
+ <h1 class="header-title text-2xl font-bold text-gray-800">Панель управления</h1>
167
+ </div>
168
 
169
+ <div class="flex items-center space-x-4">
170
+ <div class="relative hidden sm:block">
171
+ <button class="text-gray-500 hover:text-gray-700 focus:outline-none">
172
+ <i class="fas fa-bell text-xl"></i>
173
+ <span class="absolute top-0 right-0 h-2 w-2 rounded-full bg-red-500"></span>
174
+ </button>
175
+ </div>
176
+
177
+ <div class="relative">
178
+ <button class="flex items-center focus:outline-none">
179
+ <div class="w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center">
180
+ <i class="fas fa-user text-indigo-600"></i>
181
+ </div>
182
+ <span class="ml-2 text-gray-700 hidden md:inline">Администратор</span>
183
+ <i class="fas fa-chevron-down ml-1 text-gray-500 text-xs hidden md:inline"></i>
184
+ </button>
185
+ </div>
186
+ </div>
187
+ </header>
188
+
189
+ <!-- Основное содержимое -->
190
+ <main class="p-4 sm:p-6">
191
+ <!-- Статистика -->
192
+ <div class="stats-grid grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6 mb-6">
193
+ <div class="bg-white rounded-lg shadow p-4 sm:p-6">
194
+ <div class="flex items-center justify-between">
195
+ <div>
196
+ <p class="text-gray-500 text-sm sm:text-base">Общий доход</p>
197
+ <h3 class="text-xl sm:text-2xl font-bold">245,890 ₽</h3>
198
+ <p class="text-green-500 text-xs sm:text-sm mt-1">
199
+ <i class="fas fa-arrow-up mr-1"></i> 12% с прошлого месяца
200
+ </p>
201
+ </div>
202
+ <div class="bg-green-100 p-2 sm:p-3 rounded-full">
203
+ <i class="fas fa-wallet text-green-600 text-lg sm:text-xl"></i>
204
+ </div>
205
  </div>
206
+ </div>
207
+
208
+ <div class="bg-white rounded-lg shadow p-4 sm:p-6">
209
+ <div class="flex items-center justify-between">
210
+ <div>
211
+ <p class="text-gray-500 text-sm sm:text-base">Новые заказы</p>
212
+ <h3 class="text-xl sm:text-2xl font-bold">124</h3>
213
+ <p class="text-red-500 text-xs sm:text-sm mt-1">
214
+ <i class="fas fa-arrow-down mr-1"></i> 3% с прошлого месяца
215
+ </p>
216
+ </div>
217
+ <div class="bg-blue-100 p-2 sm:p-3 rounded-full">
218
+ <i class="fas fa-shopping-cart text-blue-600 text-lg sm:text-xl"></i>
219
+ </div>
220
  </div>
221
  </div>
222
+
223
+ <div class="bg-white rounded-lg shadow p-4 sm:p-6">
224
+ <div class="flex items-center justify-between">
225
+ <div>
226
+ <p class="text-gray-500 text-sm sm:text-base">Посетители</p>
227
+ <h3 class="text-xl sm:text-2xl font-bold">8,549</h3>
228
+ <p class="text-green-500 text-xs sm:text-sm mt-1">
229
+ <i class="fas fa-arrow-up mr-1"></i> 22% с прошлого месяца
230
+ </p>
231
+ </div>
232
+ <div class="bg-purple-100 p-2 sm:p-3 rounded-full">
233
+ <i class="fas fa-users text-purple-600 text-lg sm:text-xl"></i>
234
+ </div>
235
+ </div>
236
+ </div>
237
+
238
+ <div class="bg-white rounded-lg shadow p-4 sm:p-6">
239
+ <div class="flex items-center justify-between">
240
+ <div>
241
+ <p class="text-gray-500 text-sm sm:text-base">Конверсия</p>
242
+ <h3 class="text-xl sm:text-2xl font-bold">3.42%</h3>
243
+ <p class="text-green-500 text-xs sm:text-sm mt-1">
244
+ <i class="fas fa-arrow-up mr-1"></i> 1.2% с прошлого месяца
245
+ </p>
246
+ </div>
247
+ <div class="bg-yellow-100 p-2 sm:p-3 rounded-full">
248
+ <i class="fas fa-chart-pie text-yellow-600 text-lg sm:text-xl"></i>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ </div>
253
 
254
+ <!-- Графики и таблицы -->
255
+ <div class="charts-grid grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6 mb-6">
256
+ <div class="bg-white rounded-lg shadow p-4 sm:p-6 lg:col-span-2">
257
+ <div class="flex items-center justify-between mb-4">
258
+ <h2 class="text-lg font-semibold text-gray-800">Продажи за последние 30 дней</h2>
259
+ <select class="border border-gray-300 rounded-md px-2 py-1 text-xs sm:text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
260
+ <option>30 дней</option>
261
+ <option>7 дней</option>
262
+ <option>90 дней</option>
263
+ </select>
264
+ </div>
265
+ <div class="chart-container">
266
+ <canvas id="salesChart"></canvas>
267
+ </div>
268
+ </div>
269
+
270
+ <div class="bg-white rounded-lg shadow p-4 sm:p-6">
271
+ <h2 class="text-lg font-semibold text-gray-800 mb-4">Топ товары</h2>
272
+ <div class="space-y-3 sm:space-y-4">
273
+ <div class="flex items-center">
274
+ <img src="https://via.placeholder.com/60" alt="Product" class="w-10 h-10 sm:w-12 sm:h-12 object-cover rounded mr-2 sm:mr-3">
275
+ <div class="flex-1 min-w-0">
276
+ <h4 class="text-sm sm:text-base font-medium truncate">Смартфон X Pro</h4>
277
+ <p class="text-gray-500 text-xs sm:text-sm">Продано: 245 шт.</p>
278
+ </div>
279
+ <div class="ml-2 font-bold text-indigo-600 text-sm sm:text-base">24%</div>
280
+ </div>
281
+
282
+ <div class="flex items-center">
283
+ <img src="https://via.placeholder.com/60" alt="Product" class="w-10 h-10 sm:w-12 sm:h-12 object-cover rounded mr-2 sm:mr-3">
284
+ <div class="flex-1 min-w-0">
285
+ <h4 class="text-sm sm:text-base font-medium truncate">Ноутбук Ultra</h4>
286
+ <p class="text-gray-500 text-xs sm:text-sm">Продано: 189 шт.</p>
287
+ </div>
288
+ <div class="ml-2 font-bold text-indigo-600 text-sm sm:text-base">18%</div>
289
+ </div>
290
+
291
+ <div class="flex items-center">
292
+ <img src="https://via.placeholder.com/60" alt="Product" class="w-10 h-10 sm:w-12 sm:h-12 object-cover rounded mr-2 sm:mr-3">
293
+ <div class="flex-1 min-w-0">
294
+ <h4 class="text-sm sm:text-base font-medium truncate">Наушники Pro</h4>
295
+ <p class="text-gray-500 text-xs sm:text-sm">Продано: 156 шт.</p>
296
+ </div>
297
+ <div class="ml-2 font-bold text-indigo-600 text-sm sm:text-base">15%</div>
298
+ </div>
299
+
300
+ <div class="flex items-center">
301
+ <img src="https://via.placeholder.com/60" alt="Product" class="w-10 h-10 sm:w-12 sm:h-12 object-cover rounded mr-2 sm:mr-3">
302
+ <div class="flex-1 min-w-0">
303
+ <h4 class="text-sm sm:text-base font-medium truncate">Часы Smart</h4>
304
+ <p class="text-gray-500 text-xs sm:text-sm">Продано: 132 шт.</p>
305
+ </div>
306
+ <div class="ml-2 font-bold text-indigo-600 text-sm sm:text-base">12%</div>
307
+ </div>
308
+
309
+ <div class="flex items-center">
310
+ <img src="https://via.placeholder.com/60" alt="Product" class="w-10 h-10 sm:w-12 sm:h-12 object-cover rounded mr-2 sm:mr-3">
311
+ <div class="flex-1 min-w-0">
312
+ <h4 class="text-sm sm:text-base font-medium truncate">Камера 4K</h4>
313
+ <p class="text-gray-500 text-xs sm:text-sm">Продано: 98 шт.</p>
314
+ </div>
315
+ <div class="ml-2 font-bold text-indigo-600 text-sm sm:text-base">9%</div>
316
+ </div>
317
+ </div>
318
+ </div>
319
+ </div>
320
 
321
+ <!-- Последние заказы -->
322
+ <div class="bg-white rounded-lg shadow overflow-hidden mb-6">
323
+ <div class="px-4 sm:px-6 py-3 sm:py-4 border-b border-gray-200 flex items-center justify-between">
324
+ <h2 class="text-lg font-semibold text-gray-800">Последние заказы</h2>
325
+ <button class="text-indigo-600 hover:text-indigo-800 text-sm font-medium">
326
+ Показать все
327
+ </button>
328
+ </div>
329
+ <div class="overflow-x-auto">
330
+ <table class="min-w-full divide-y divide-gray-200 order-table">
331
+ <thead class="bg-gray-50">
332
+ <tr>
333
+ <th class="px-3 sm:px-6 py-2 sm:py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
334
+ <th class="px-3 sm:px-6 py-2 sm:py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden sm:table-cell">Клиент</th>
335
+ <th class="px-3 sm:px-6 py-2 sm:py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Дата</th>
336
+ <th class="px-3 sm:px-6 py-2 sm:py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Сумма</th>
337
+ <th class="px-3 sm:px-6 py-2 sm:py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Статус</th>
338
+ <th class="px-3 sm:px-6 py-2 sm:py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Действия</th>
339
+ </tr>
340
+ </thead>
341
+ <tbody class="bg-white divide-y divide-gray-200">
342
+ <tr>
343
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm font-medium text-gray-900">#78945</td>
344
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500 hidden sm:table-cell">Иван Петров</td>
345
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">15.06</td>
346
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">24,990 ₽</td>
347
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap">
348
+ <span class="order-status-badge bg-green-100 text-green-800">Доставлен</span>
349
+ </td>
350
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">
351
+ <button class="text-indigo-600 hover:text-indigo-900 mr-2 sm:mr-3">
352
+ <i class="fas fa-eye"></i>
353
+ </button>
354
+ <button class="text-gray-600 hover:text-gray-900 hidden sm:inline-block">
355
+ <i class="fas fa-print"></i>
356
+ </button>
357
+ </td>
358
+ </tr>
359
+ <tr>
360
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm font-medium text-gray-900">#78944</td>
361
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500 hidden sm:table-cell">Елена Смирнова</td>
362
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">15.06</td>
363
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">15,490 ₽</td>
364
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap">
365
+ <span class="order-status-badge bg-yellow-100 text-yellow-800">В обработке</span>
366
+ </td>
367
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">
368
+ <button class="text-indigo-600 hover:text-indigo-900 mr-2 sm:mr-3">
369
+ <i class="fas fa-eye"></i>
370
+ </button>
371
+ <button class="text-gray-600 hover:text-gray-900 hidden sm:inline-block">
372
+ <i class="fas fa-print"></i>
373
+ </button>
374
+ </td>
375
+ </tr>
376
+ <tr>
377
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm font-medium text-gray-900">#78943</td>
378
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500 hidden sm:table-cell">Алексей Иванов</td>
379
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">14.06</td>
380
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">32,990 ₽</td>
381
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap">
382
+ <span class="order-status-badge bg-blue-100 text-blue-800">Отправлен</span>
383
+ </td>
384
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">
385
+ <button class="text-indigo-600 hover:text-indigo-900 mr-2 sm:mr-3">
386
+ <i class="fas fa-eye"></i>
387
+ </button>
388
+ <button class="text-gray-600 hover:text-gray-900 hidden sm:inline-block">
389
+ <i class="fas fa-print"></i>
390
+ </button>
391
+ </td>
392
+ </tr>
393
+ <tr>
394
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm font-medium text-gray-900">#78942</td>
395
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500 hidden sm:table-cell">Ольга Кузнецова</td>
396
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">14.06</td>
397
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">18,750 ₽</td>
398
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap">
399
+ <span class="order-status-badge bg-red-100 text-red-800">Отменен</span>
400
+ </td>
401
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">
402
+ <button class="text-indigo-600 hover:text-indigo-900 mr-2 sm:mr-3">
403
+ <i class="fas fa-eye"></i>
404
+ </button>
405
+ <button class="text-gray-600 hover:text-gray-900 hidden sm:inline-block">
406
+ <i class="fas fa-print"></i>
407
+ </button>
408
+ </td>
409
+ </tr>
410
+ <tr>
411
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm font-medium text-gray-900">#78941</td>
412
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500 hidden sm:table-cell">Дмитрий Соколов</td>
413
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">13.06</td>
414
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">42,300 ₽</td>
415
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap">
416
+ <span class="order-status-badge bg-purple-100 text-purple-800">Ожидает оплаты</span>
417
+ </td>
418
+ <td class="px-3 sm:px-6 py-3 whitespace-nowrap text-sm text-gray-500">
419
+ <button class="text-indigo-600 hover:text-indigo-900 mr-2 sm:mr-3">
420
+ <i class="fas fa-eye"></i>
421
+ </button>
422
+ <button class="text-gray-600 hover:text-gray-900 hidden sm:inline-block">
423
+ <i class="fas fa-print"></i>
424
+ </button>
425
+ </td>
426
+ </tr>
427
+ </tbody>
428
+ </table>
429
+ </div>
430
+ </div>
431
+ </main>
432
+ </div>
433
+ </div>
434
 
435
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
436
+ <script>
437
+ // Сворачивание/разворачивание боковой панели
438
+ document.getElementById('toggleSidebar').addEventListener('click', function() {
439
+ document.querySelector('.sidebar').classList.toggle('collapsed');
440
+ document.querySelector('.main-content').classList.toggle('ml-64');
441
+ document.querySelector('.main-content').classList.toggle('ml-[70px]');
442
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
 
444
+ // Мобильное меню
445
+ document.getElementById('mobileMenuButton').addEventListener('click', function() {
446
+ document.querySelector('.sidebar').classList.toggle('active');
447
+ });
448
+
449
+ // Инициализация графика продаж
450
+ const salesCtx = document.getElementById('salesChart').getContext('2d');
451
+ const salesChart = new Chart(salesCtx, {
452
+ type: 'line',
453
+ data: {
454
+ labels: ['1 июн', '5 июн', '10 июн', '15 июн', '20 июн', '25 июн', '30 июн'],
455
+ datasets: [{
456
+ label: 'Продажи',
457
+ data: [12000, 19000, 15000, 22000, 18000, 25000, 30000],
458
+ backgroundColor: 'rgba(79, 70, 229, 0.05)',
459
+ borderColor: 'rgba(79, 70, 229, 1)',
460
+ borderWidth: 2,
461
+ tension: 0.4,
462
+ fill: true
463
+ }]
464
+ },
465
+ options: {
466
+ responsive: true,
467
+ maintainAspectRatio: false,
468
+ plugins: {
469
+ legend: {
470
+ display: false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  }
472
+ },
473
+ scales: {
474
+ y: {
475
+ beginAtZero: true,
476
+ grid: {
477
+ drawBorder: false
478
+ },
479
+ ticks: {
480
+ callback: function(value) {
481
+ return value / 1000 + 'k';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
482
  }
483
  }
484
+ },
485
+ x: {
486
+ grid: {
487
+ display: false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  }
489
  }
490
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  }
492
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
 
494
+ // Адаптация графика при изменении размера окна
495
+ window.addEventListener('resize', function() {
496
+ salesChart.resize();
497
+ });
 
 
 
 
 
 
498
  </script>
499
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=SimpleCodeTM/tree-moved" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
500
  </html>
prompts.txt CHANGED
@@ -1,4 +1,9 @@
1
  выделить ВСЕ и поиск не функционируют
2
  дерево с возможностью углубления на любую глубину и плавным перетаскиванием элементов за левую иконку в любое место дерева и на любую в т.ч. и новую глубину
3
  скачет все сильно, очень дискомфортно
4
- уже лучше , не дергается но не запоминает конечную позицию ( не перемещает )
 
 
 
 
 
 
1
  выделить ВСЕ и поиск не функционируют
2
  дерево с возможностью углубления на любую глубину и плавным перетаскиванием элементов за левую иконку в любое место дерева и на любую в т.ч. и новую глубину
3
  скачет все сильно, очень дискомфортно
4
+ уже лучше , не дергается но не запоминает конечную позицию ( не перемещает )
5
+ адаптивная верстка секции 1 элемент на строке 2 элемента на строке 3 элемента на строке 4 элемента на строке 5 элементов в строке 6 4 элемента в двух строках 7 6 элементов в двух строках 8 8 элементов в двух строках
6
+ адаптивная верстка секции (одна секция = одна строка ): 1 элемент на строке 2 элемента на строке 3 элемента на строке 4 элемента на строке 5 элементов в строке 6 4 элемента в двух строках 7 6 элементов в двух строках 8 8 элементов в двух строках
7
+ начиная со строки 346 в коде бардак
8
+ админпанель интернет-магазина
9
+ хорошо, а что с адаптацией ? можешь добавить ?