Mycc commited on
Commit
10e0ed3
·
verified ·
1 Parent(s): 59c87d4

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +183 -87
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Рулетка Отрядов Genshin Impact</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -61,22 +61,22 @@
61
  100% { transform: scale(1.1) rotate(2deg); opacity: 1; }
62
  }
63
 
64
- /* Более объемная и живая анимация выпадения персонажа */
65
  .roulette-item-final-enter {
66
  opacity: 0;
67
- transform: scale(0.7) translateY(50px) rotateX(-90deg);
68
- filter: blur(5px);
69
- box-shadow: 0 0 0 rgba(0,0,0,0);
70
  }
71
  .roulette-item-final-enter-active {
72
  opacity: 1;
73
- transform: scale(1) translateY(0) rotateX(0deg);
74
- filter: blur(0);
75
- transition: opacity 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55),
76
- transform 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55),
77
- filter 0.6s ease-out,
78
- box-shadow 0.6s ease-out;
79
- box-shadow: 0 10px 20px rgba(0,0,0,0.2);
 
 
80
  }
81
 
82
  .player-char-card {
@@ -109,6 +109,42 @@
109
  .player-char-card:hover .remove-btn {
110
  opacity: 1;
111
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  </style>
113
  </head>
114
  <body class="light">
@@ -127,7 +163,7 @@
127
  </svg>
128
  </button>
129
  </div>
130
- <h1 class="text-4xl md:text-5xl font-bold text-[#4A4A4A] dark:text-[#e2e8f0] mb-2">Random Team</h1>
131
  <p class="text-lg text-[#6B6B6B] dark:text-[#a0aec0] max-w-2xl mx-auto">
132
  Сгенерируйте случайный отряд из четырех персонажей Genshin Impact!
133
  </p>
@@ -179,33 +215,28 @@
179
  Крутить отряд!
180
  </button>
181
  </div>
182
- <div id="roulette-result" class="min-h-[180px] bg-[#FDF8F0] dark:bg-gray-800 rounded-xl p-4 flex flex-wrap justify-center items-center gap-4 transition-all duration-300">
183
  <p id="roulette-placeholder" class="text-[#888] dark:text-gray-400">Ваш случайный отряд появится здесь.</p>
184
  <div id="roulette-loader" class="loader hidden"></div>
185
  </div>
186
-
187
- <div id="save-team-section" class="mt-6 p-4 bg-[#FDF8F0] dark:bg-gray-800 rounded-xl shadow-sm hidden">
188
- <h3 class="text-lg font-semibold mb-3 dark:text-white">Сохранить этот отряд</h3>
189
- <div class="flex flex-col sm:flex-row gap-3">
190
- <input type="text" id="team-name-input" placeholder="Название отряда (необязательно)" class="flex-grow p-2 rounded border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
191
- <button id="save-team-button" class="bg-[#A089D0] text-white font-bold py-2 px-6 rounded-lg shadow-md hover:bg-[#8e7abf] transition-transform duration-200 ease-in-out hover:scale-105">
192
- Сохранить
193
- </button>
194
- </div>
195
  </div>
196
-
197
  </section>
198
 
199
  <section id="history-section" class="bg-[#EFEAE4] dark:bg-gray-700 p-6 rounded-2xl shadow-lg">
200
  <div class="flex justify-between items-center mb-8">
201
  <h2 class="text-3xl font-bold text-[#4A4A4A] dark:text-white">История Отрядов</h2>
202
  <div class="flex gap-2">
 
 
 
203
  <button id="clear-history-button" class="bg-[#A089D0] text-white font-bold py-2 px-4 rounded-lg text-sm shadow-md hover:bg-[#8e7abf] transition-transform duration-200 ease-in-out hover:scale-105 focus:outline-none focus:ring-4 focus:ring-[#A089D0]/50 hidden">
204
  Очистить
205
  </button>
206
- <button id="view-full-history-button" class="bg-[#DCA852] text-white font-bold py-2 px-4 rounded-lg text-sm shadow-md hover:bg-[#c3914a] transition-transform duration-200 ease-in-out hover:scale-105 focus:outline-none focus:ring-4 focus:ring-[#DCA852]/50 hidden">
207
- Вся история
208
- </button>
209
  </div>
210
  </div>
211
  <div id="history-content" class="flex flex-col gap-6">
@@ -224,7 +255,7 @@
224
  <div id="confirm-modal" class="fixed inset-0 bg-black bg-opacity-70 z-50 flex justify-center items-center hidden p-4">
225
  <div class="bg-[#FDF8F0] dark:bg-gray-800 rounded-2xl w-full max-w-sm shadow-2xl relative text-center p-6 transform transition-all duration-300 scale-95 opacity-0" id="confirm-modal-content">
226
  <h3 class="text-2xl font-bold mb-4 text-[#4A4A4A] dark:text-white">Подтверждение</h3>
227
- <p id="confirm-modal-message" class="text-lg text-[#6B6B6B] dark:text-gray-300 mb-6"></p>
228
  <div class="flex justify-around gap-4">
229
  <button id="confirm-modal-cancel" class="bg-[#A089D0] text-white font-bold py-2 px-6 rounded-lg hover:bg-[#8e7abf]">Отмена</button>
230
  <button id="confirm-modal-ok" class="bg-red-500 text-white font-bold py-2 px-6 rounded-lg hover:bg-red-600">Очистить</button>
@@ -232,10 +263,21 @@
232
  </div>
233
  </div>
234
 
 
 
 
 
 
 
 
 
 
 
 
235
  <script>
236
  document.addEventListener('DOMContentLoaded', () => {
237
  // Локальные данные персонажей
238
- const LOCAL_CHARACTERS = [
239
  { "name": "Альбедо", "icon": "https://game-cdn.appsample.com/gim/items/albedo.png" },
240
  { "name": "Аль-Хайтам", "icon": "https://game-cdn.appsample.com/gim/items/alhaitham.png" },
241
  { "name": "Алой", "icon": "https://game-cdn.appsample.com/gim/items/aloy.png" },
@@ -334,7 +376,6 @@
334
  { "name": "Мидзуки", "icon": "https://game-cdn.appsample.com/gim/items/yumemizuki_mizuki.png" },
335
  { "name": "Чжун Ли", "icon": "https://game-cdn.appsample.com/gim/items/zhongli.png" }
336
  ];
337
-
338
  // Генерация или получение UID
339
  function getOrCreateUID() {
340
  let uid = localStorage.getItem('genshinRouletteUID');
@@ -359,7 +400,7 @@
359
  let historyTeams = JSON.parse(localStorage.getItem(`${currentUserUID}_genshinTeamsHistory`)) || [];
360
  let playerCharacters = JSON.parse(localStorage.getItem(`${currentUserUID}_playerCharacters`)) || [];
361
  let isSpinning = false;
362
- let currentGeneratedTeam = []; // Для сохранения сгенерированного отряда перед именованием
363
 
364
  // Элементы DOM
365
  const spinButton = document.getElementById('spin-button');
@@ -369,6 +410,7 @@
369
  const historyContent = document.getElementById('history-content');
370
  const historyPlaceholder = document.getElementById('history-placeholder');
371
  const clearHistoryButton = document.getElementById('clear-history-button');
 
372
  const themeToggle = document.getElementById('theme-toggle');
373
  const settingsToggle = document.getElementById('settings-toggle');
374
  const settingsPanel = document.getElementById('settings-panel');
@@ -382,11 +424,15 @@
382
  const playerCharactersSelection = document.getElementById('player-characters-selection');
383
  const characterSearchInput = document.getElementById('character-search');
384
  const clearPlayerCharactersButton = document.getElementById('clear-player-characters');
385
- const saveTeamSection = document.getElementById('save-team-section');
386
- const teamNameInput = document.getElementById('team-name-input');
387
  const saveTeamButton = document.getElementById('save-team-button');
388
- const viewFullHistoryButton = document.getElementById('view-full-history-button');
389
 
 
 
 
 
 
390
 
391
  // Инициализация темы
392
  function initTheme() {
@@ -418,7 +464,7 @@
418
 
419
  card.innerHTML = `
420
  <img src="${character.icon}" alt="${character.name}"
421
- class="w-16 h-16 sm:w-20 sm:h-20 rounded-full mb-1 object-cover border-2 border-[#DCA852]"
422
  onerror="this.onerror=null;this.src='https://placehold.co/80x80/EFEAE4/4A4A4A?text=N/A'">
423
  <p class="font-medium text-sm truncate w-full dark:text-white">${character.name}</p>
424
  `;
@@ -516,6 +562,9 @@
516
  async function renderRouletteResult(team) {
517
  rouletteResult.innerHTML = '';
518
  roulettePlaceholder.classList.add('hidden');
 
 
 
519
 
520
  for (let i = 0; i < team.length; i++) {
521
  const char = team[i];
@@ -524,45 +573,45 @@
524
 
525
  rouletteResult.appendChild(card);
526
 
527
- await new Promise(resolve => setTimeout(resolve, 50));
528
  card.classList.add('roulette-item-final-enter-active');
529
 
530
- await new Promise(resolve => setTimeout(resolve, 200));
531
  }
 
 
 
 
 
532
  }
533
 
534
- // Отображение истории (только последние 3)
535
- function renderHistory() {
536
  historyContent.innerHTML = '';
537
 
538
  if (historyTeams.length === 0) {
539
  historyPlaceholder.classList.remove('hidden');
540
  clearHistoryButton.classList.add('hidden');
541
- viewFullHistoryButton.classList.add('hidden');
542
  } else {
543
  historyPlaceholder.classList.add('hidden');
544
  clearHistoryButton.classList.remove('hidden');
545
- if (historyTeams.length > 3) { // Показываем кнопку "Вся история", если команд больше 3
546
- viewFullHistoryButton.classList.remove('hidden');
547
- } else {
548
- viewFullHistoryButton.classList.add('hidden');
549
- }
550
-
551
- // Показываем только последние 3 отряда на главной странице
552
- const teamsToShow = historyTeams.slice(0, 3);
553
 
554
- teamsToShow.forEach((team, index) => {
 
 
555
  const teamElement = document.createElement('div');
556
  teamElement.className = 'bg-[#FDF8F0] dark:bg-gray-800 rounded-xl p-4 shadow-sm border border-[#EFEAE4] dark:border-gray-600';
557
 
558
  const title = document.createElement('h3');
559
  title.className = 'text-lg font-semibold mb-3 dark:text-white';
560
- // Используем сохраненное имя, если оно есть, иначе генерируем
561
- title.textContent = team.name ? team.name : `Отряд ${historyTeams.length - index} (${new Date(team.date).toLocaleString()})`;
562
  teamElement.appendChild(title);
563
 
564
  const charsContainer = document.createElement('div');
565
- charsContainer.className = 'flex flex-wrap justify-center gap-3';
566
 
567
  team.characters.forEach(char => {
568
  charsContainer.appendChild(createCharacterCard(char));
@@ -574,21 +623,70 @@
574
  }
575
  }
576
 
577
- // Сохранение отряда в историю с возможностью добавления имени
578
- function saveTeamToHistory(team, teamName = '') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
  historyTeams.unshift({
580
  date: new Date().toISOString(),
581
  characters: team,
582
- name: teamName // Добавляем имя
583
  });
584
 
585
- // Ограничиваем историю последними 20 отрядами для общей истории (чтобы не было слишком много данных, но достаточно для просмотра)
586
- if (historyTeams.length > 20) {
587
- historyTeams = historyTeams.slice(0, 20);
588
- }
589
-
590
  localStorage.setItem(`${currentUserUID}_genshinTeamsHistory`, JSON.stringify(historyTeams));
591
- renderHistory();
592
  }
593
 
594
  // Очистка истории
@@ -611,12 +709,11 @@
611
  isSpinning = true;
612
  spinButton.disabled = true;
613
  spinButton.textContent = 'Крутим...';
614
- rouletteResult.innerHTML = '';
615
  roulettePlaceholder.classList.add('hidden');
616
  rouletteLoader.classList.remove('hidden');
617
- saveTeamSection.classList.add('hidden'); // Скрываем секцию сохранения при новом вращении
618
- teamNameInput.value = ''; // Очищаем поле ввода имени
619
-
620
  const teamSize = parseInt(teamSizeSelect.value);
621
  let charsPool = [...availableCharsForSpin];
622
  const selectedTeam = [];
@@ -653,18 +750,19 @@
653
  const selectedChar = charsPool.splice(selectedIndex, 1)[0];
654
  selectedTeam.push(selectedChar);
655
 
656
- tempRouletteDiv.innerHTML = '';
657
  const finalCard = createCharacterCard(selectedChar);
658
- finalCard.classList.add('roulette-item-final-enter');
659
  tempRouletteDiv.appendChild(finalCard);
 
660
  setTimeout(() => {
661
  finalCard.classList.add('roulette-item-final-enter-active');
662
  }, 10);
663
  }
664
  };
665
- animateSpin();
666
 
667
- await new Promise(resolve => setTimeout(resolve, individualSpinTime + 100));
668
  }
669
 
670
  // Завершение рулетки
@@ -673,11 +771,11 @@
673
  spinButton.textContent = 'Крутить ещё!';
674
  isSpinning = false;
675
 
676
- currentGeneratedTeam = selectedTeam; // Сохраняем сгенерированный отряд
677
- saveTeamSection.classList.remove('hidden'); // Показываем секцию сохранения
678
  }
679
 
680
- // Модальное окно подтверждения
681
  function showConfirmModal(message, callback) {
682
  confirmModalMessage.textContent = message;
683
  confirmModal.classList.remove('hidden');
@@ -715,34 +813,32 @@
715
  themeToggle.addEventListener('click', toggleTheme);
716
  settingsToggle.addEventListener('click', toggleSettings);
717
  clearHistoryButton.addEventListener('click', () => {
718
- showConfirmModal(`UID:${currentUserUID} \r\rВы уверены, что хотите очистить всю историю отрядов?`, clearHistory);
719
  });
720
  clearPlayerCharactersButton.addEventListener('click', () => {
721
  showConfirmModal('Вы уверены, что хотите очистить список ваших персонажей?', clearPlayerCharacters);
722
  });
723
- confirmModal.addEventListener('click', (e) => {
724
- if (e.target === confirmModal) hideConfirmModal();
725
- });
726
-
727
- characterSearchInput.addEventListener('input', (e) => {
728
- renderPlayerCharactersSelection(e.target.value);
729
  });
730
 
731
- saveTeamButton.addEventListener('click', () => {
732
  const teamName = teamNameInput.value.trim();
733
  if (currentGeneratedTeam.length > 0) {
734
  saveTeamToHistory(currentGeneratedTeam, teamName);
735
- saveTeamSection.classList.add('hidden'); // Скрываем секцию после сохранения
736
- teamNameInput.value = ''; // Очищаем поле
737
- currentGeneratedTeam = []; // Сбрасываем текущий отряд
738
  }
739
  });
740
 
741
- viewFullHistoryButton.addEventListener('click', () => {
742
- // Открываем новую вкладку для полной истории
743
- showConfirmModal(`${currentUserUID} ${history-content}`);
 
 
 
744
  });
745
-
746
 
747
  // Сохранение настроек при изменении
748
  teamSizeSelect.addEventListener('change', (e) => {
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Random Team</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 
61
  100% { transform: scale(1.1) rotate(2deg); opacity: 1; }
62
  }
63
 
 
64
  .roulette-item-final-enter {
65
  opacity: 0;
66
+ transform: scale(0.5) translateY(20px);
67
+ box-shadow: 0 0 0 rgba(0,0,0,0); /* Начальное состояние для тени */
 
68
  }
69
  .roulette-item-final-enter-active {
70
  opacity: 1;
71
+ transform: scale(1) translateY(0);
72
+ transition: opacity 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55),
73
+ transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55),
74
+ box-shadow 0.5s ease-out; /* Анимация тени */
75
+ box-shadow: 0 5px 15px rgba(0,0,0,0.3); /* Объемная тень */
76
+ }
77
+ .roulette-char-card img {
78
+ border-color: #DCA852; /* Цвет рамки для персонажа */
79
+ box-shadow: 0 0 10px rgba(220, 168, 82, 0.5); /* Золотистое свечение */
80
  }
81
 
82
  .player-char-card {
 
109
  .player-char-card:hover .remove-btn {
110
  opacity: 1;
111
  }
112
+
113
+ /* Styles for the full history modal character cards */
114
+ .full-history-character-card {
115
+ display: flex;
116
+ flex-direction: column;
117
+ align-items: center;
118
+ padding: 8px;
119
+ border-radius: 8px;
120
+ background-color: #ffffff; /* Light mode */
121
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
122
+ text-align: center;
123
+ flex-shrink: 0;
124
+ width: 100px; /* Fixed width for consistency */
125
+ }
126
+ .dark .full-history-character-card {
127
+ background-color: #4a5568; /* Dark mode */
128
+ }
129
+ .full-history-character-card img {
130
+ width: 64px;
131
+ height: 64px;
132
+ border-radius: 50%;
133
+ margin-bottom: 4px;
134
+ object-fit: cover;
135
+ border: 2px solid #DCA852;
136
+ }
137
+ .full-history-character-card p {
138
+ font-size: 0.875rem;
139
+ font-weight: 500;
140
+ text-overflow: ellipsis;
141
+ overflow: hidden;
142
+ white-space: nowrap;
143
+ width: 100%;
144
+ }
145
+ .dark .full-history-character-card p {
146
+ color: #e2e8f0;
147
+ }
148
  </style>
149
  </head>
150
  <body class="light">
 
163
  </svg>
164
  </button>
165
  </div>
166
+ <h1 class="text-4xl md:text-5xl font-bold text-[#4A4A4A] dark:text-[#e2e8f0] mb-2">Рулетка Отрядов Genshin Impact</h1>
167
  <p class="text-lg text-[#6B6B6B] dark:text-[#a0aec0] max-w-2xl mx-auto">
168
  Сгенерируйте случайный отряд из четырех персонажей Genshin Impact!
169
  </p>
 
215
  Крутить отряд!
216
  </button>
217
  </div>
218
+ <div id="roulette-result" class="min-h-[180px] bg-[#FDF8F0] dark:bg-gray-800 rounded-xl p-4 flex flex-wrap justify-center items-center gap-4 transition-all duration-300 flex-col sm:flex-row">
219
  <p id="roulette-placeholder" class="text-[#888] dark:text-gray-400">Ваш случайный отряд появится здесь.</p>
220
  <div id="roulette-loader" class="loader hidden"></div>
221
  </div>
222
+ <div id="save-team-section" class="mt-4 flex flex-col sm:flex-row justify-center items-center gap-4 hidden">
223
+ <input type="text" id="team-name-input" placeholder="Название отряда (необязательно)" class="p-2 rounded border border-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-white w-full sm:w-auto flex-grow">
224
+ <button id="save-team-button" class="bg-[#A089D0] text-white font-bold py-2 px-6 rounded-lg shadow-md hover:bg-[#8e7abf] transition-transform duration-200 ease-in-out hover:scale-105 focus:outline-none focus:ring-4 focus:ring-[#A089D0]/50 w-full sm:w-auto">
225
+ Сохранить отряд
226
+ </button>
 
 
 
 
227
  </div>
 
228
  </section>
229
 
230
  <section id="history-section" class="bg-[#EFEAE4] dark:bg-gray-700 p-6 rounded-2xl shadow-lg">
231
  <div class="flex justify-between items-center mb-8">
232
  <h2 class="text-3xl font-bold text-[#4A4A4A] dark:text-white">История Отрядов</h2>
233
  <div class="flex gap-2">
234
+ <button id="show-full-history-button" class="bg-[#A089D0] text-white font-bold py-2 px-4 rounded-lg text-sm shadow-md hover:bg-[#8e7abf] transition-transform duration-200 ease-in-out hover:scale-105 focus:outline-none focus:ring-4 focus:ring-[#A089D0]/50 hidden">
235
+ Вся история
236
+ </button>
237
  <button id="clear-history-button" class="bg-[#A089D0] text-white font-bold py-2 px-4 rounded-lg text-sm shadow-md hover:bg-[#8e7abf] transition-transform duration-200 ease-in-out hover:scale-105 focus:outline-none focus:ring-4 focus:ring-[#A089D0]/50 hidden">
238
  Очистить
239
  </button>
 
 
 
240
  </div>
241
  </div>
242
  <div id="history-content" class="flex flex-col gap-6">
 
255
  <div id="confirm-modal" class="fixed inset-0 bg-black bg-opacity-70 z-50 flex justify-center items-center hidden p-4">
256
  <div class="bg-[#FDF8F0] dark:bg-gray-800 rounded-2xl w-full max-w-sm shadow-2xl relative text-center p-6 transform transition-all duration-300 scale-95 opacity-0" id="confirm-modal-content">
257
  <h3 class="text-2xl font-bold mb-4 text-[#4A4A4A] dark:text-white">Подтверждение</h3>
258
+ <p id="confirm-modal-message" class="text-lg text-[#6B6B6B] dark:text-gray-300 mb-6">Вы уверены, что хотите очистить историю?</p>
259
  <div class="flex justify-around gap-4">
260
  <button id="confirm-modal-cancel" class="bg-[#A089D0] text-white font-bold py-2 px-6 rounded-lg hover:bg-[#8e7abf]">Отмена</button>
261
  <button id="confirm-modal-ok" class="bg-red-500 text-white font-bold py-2 px-6 rounded-lg hover:bg-red-600">Очистить</button>
 
263
  </div>
264
  </div>
265
 
266
+ <div id="full-history-modal" class="fixed inset-0 bg-black bg-opacity-70 z-50 flex justify-center items-center hidden p-4">
267
+ <div class="bg-[#FDF8F0] dark:bg-gray-800 rounded-2xl w-full max-w-4xl h-[90vh] shadow-2xl relative flex flex-col p-6 transform transition-all duration-300 scale-95 opacity-0" id="full-history-modal-content">
268
+ <h2 class="text-3xl md:text-4xl font-bold text-center mb-6 text-[#4A4A4A] dark:text-[#e2e8f0]">Вся История Отрядов</h2>
269
+ <div id="full-history-modal-content-inner" class="flex flex-col gap-6 overflow-y-auto flex-grow pr-2">
270
+ </div>
271
+ <div class="text-center mt-6">
272
+ <button id="full-history-modal-close" class="bg-[#A089D0] text-white font-bold py-2 px-6 rounded-lg hover:bg-[#8e7abf]">Закрыть</button>
273
+ </div>
274
+ </div>
275
+ </div>
276
+
277
  <script>
278
  document.addEventListener('DOMContentLoaded', () => {
279
  // Локальные данные персонажей
280
+ const LOCAL_CHARACTERS = [
281
  { "name": "Альбедо", "icon": "https://game-cdn.appsample.com/gim/items/albedo.png" },
282
  { "name": "Аль-Хайтам", "icon": "https://game-cdn.appsample.com/gim/items/alhaitham.png" },
283
  { "name": "Алой", "icon": "https://game-cdn.appsample.com/gim/items/aloy.png" },
 
376
  { "name": "Мидзуки", "icon": "https://game-cdn.appsample.com/gim/items/yumemizuki_mizuki.png" },
377
  { "name": "Чжун Ли", "icon": "https://game-cdn.appsample.com/gim/items/zhongli.png" }
378
  ];
 
379
  // Генерация или получение UID
380
  function getOrCreateUID() {
381
  let uid = localStorage.getItem('genshinRouletteUID');
 
400
  let historyTeams = JSON.parse(localStorage.getItem(`${currentUserUID}_genshinTeamsHistory`)) || [];
401
  let playerCharacters = JSON.parse(localStorage.getItem(`${currentUserUID}_playerCharacters`)) || [];
402
  let isSpinning = false;
403
+ let currentGeneratedTeam = []; // Для сохранения текущего сгенерированного отряда перед сохранением по имени
404
 
405
  // Элементы DOM
406
  const spinButton = document.getElementById('spin-button');
 
410
  const historyContent = document.getElementById('history-content');
411
  const historyPlaceholder = document.getElementById('history-placeholder');
412
  const clearHistoryButton = document.getElementById('clear-history-button');
413
+ const showFullHistoryButton = document.getElementById('show-full-history-button');
414
  const themeToggle = document.getElementById('theme-toggle');
415
  const settingsToggle = document.getElementById('settings-toggle');
416
  const settingsPanel = document.getElementById('settings-panel');
 
424
  const playerCharactersSelection = document.getElementById('player-characters-selection');
425
  const characterSearchInput = document.getElementById('character-search');
426
  const clearPlayerCharactersButton = document.getElementById('clear-player-characters');
427
+ const saveTeamSection = document.getElementById('save-team-section');
428
+ const teamNameInput = document.getElementById('team-name-input');
429
  const saveTeamButton = document.getElementById('save-team-button');
 
430
 
431
+ // Full History Modal elements
432
+ const fullHistoryModal = document.getElementById('full-history-modal');
433
+ const fullHistoryModalContent = document.getElementById('full-history-modal-content');
434
+ const fullHistoryModalContentInner = document.getElementById('full-history-modal-content-inner');
435
+ const fullHistoryModalCloseButton = document.getElementById('full-history-modal-close');
436
 
437
  // Инициализация темы
438
  function initTheme() {
 
464
 
465
  card.innerHTML = `
466
  <img src="${character.icon}" alt="${character.name}"
467
+ class="w-16 h-16 sm:w-20 sm:h-20 rounded-full mb-1 object-cover border-2"
468
  onerror="this.onerror=null;this.src='https://placehold.co/80x80/EFEAE4/4A4A4A?text=N/A'">
469
  <p class="font-medium text-sm truncate w-full dark:text-white">${character.name}</p>
470
  `;
 
562
  async function renderRouletteResult(team) {
563
  rouletteResult.innerHTML = '';
564
  roulettePlaceholder.classList.add('hidden');
565
+
566
+ // Скрываем секцию сохранения до того, как команда будет отображена
567
+ saveTeamSection.classList.add('hidden');
568
 
569
  for (let i = 0; i < team.length; i++) {
570
  const char = team[i];
 
573
 
574
  rouletteResult.appendChild(card);
575
 
576
+ await new Promise(resolve => setTimeout(resolve, 50));
577
  card.classList.add('roulette-item-final-enter-active');
578
 
579
+ await new Promise(resolve => setTimeout(resolve, 200));
580
  }
581
+
582
+ // Показываем секцию сохранения после того, как все персонажи отображены
583
+ saveTeamSection.classList.remove('hidden');
584
+ teamNameInput.value = ''; // Очищаем поле ввода
585
+ currentGeneratedTeam = team; // Сохраняем текущий сгенерированный отряд
586
  }
587
 
588
+ // Отображение истории (включая placeholder и кнопки)
589
+ function renderHistory(limit = 3) {
590
  historyContent.innerHTML = '';
591
 
592
  if (historyTeams.length === 0) {
593
  historyPlaceholder.classList.remove('hidden');
594
  clearHistoryButton.classList.add('hidden');
595
+ showFullHistoryButton.classList.add('hidden');
596
  } else {
597
  historyPlaceholder.classList.add('hidden');
598
  clearHistoryButton.classList.remove('hidden');
599
+ showFullHistoryButton.classList.remove('hidden');
 
 
 
 
 
 
 
600
 
601
+ const teamsToShow = historyTeams.slice(0, limit);
602
+
603
+ teamsToShow.forEach((team) => {
604
  const teamElement = document.createElement('div');
605
  teamElement.className = 'bg-[#FDF8F0] dark:bg-gray-800 rounded-xl p-4 shadow-sm border border-[#EFEAE4] dark:border-gray-600';
606
 
607
  const title = document.createElement('h3');
608
  title.className = 'text-lg font-semibold mb-3 dark:text-white';
609
+ const teamName = team.name ? `"${team.name}" - ` : '';
610
+ title.textContent = `${teamName}Отряд (${new Date(team.date).toLocaleString()})`;
611
  teamElement.appendChild(title);
612
 
613
  const charsContainer = document.createElement('div');
614
+ charsContainer.className = 'flex flex-wrap justify-center gap-3'; // Горизонтальное расположение с переносом
615
 
616
  team.characters.forEach(char => {
617
  charsContainer.appendChild(createCharacterCard(char));
 
623
  }
624
  }
625
 
626
+ // Показать модальное окно всей истории
627
+ function showFullHistoryModal() {
628
+ fullHistoryModalContentInner.innerHTML = ''; // Clear previous content
629
+
630
+ if (historyTeams.length === 0) {
631
+ fullHistoryModalContentInner.innerHTML = '<p class="text-center text-[#888] dark:text-gray-400">История отрядов пуста.</p>';
632
+ } else {
633
+ historyTeams.forEach((team) => {
634
+ const teamElement = document.createElement('div');
635
+ teamElement.className = 'bg-[#EFEAE4] dark:bg-gray-700 rounded-xl p-4 shadow-sm border border-[#EFEAE4] dark:border-gray-600';
636
+
637
+ const title = document.createElement('h3');
638
+ title.className = 'text-lg font-semibold mb-3 text-[#4A4A4A] dark:text-white';
639
+ const teamName = team.name ? `"${team.name}" - ` : '';
640
+ title.textContent = `${teamName}Отряд (${new Date(team.date).toLocaleString()})`;
641
+ teamElement.appendChild(title);
642
+
643
+ const charsContainer = document.createElement('div');
644
+ // Изменяем на horizontal scrollable container
645
+ charsContainer.className = 'flex gap-3 overflow-x-auto pb-2 custom-scrollbar';
646
+
647
+ team.characters.forEach(char => {
648
+ const card = document.createElement('div');
649
+ card.className = 'full-history-character-card'; // Используем новый класс для модального окна
650
+ card.innerHTML = `
651
+ <img src="${char.icon}" alt="${char.name}"
652
+ class="w-16 h-16 rounded-full mb-1 object-cover border-2"
653
+ onerror="this.onerror=null;this.src='https://placehold.co/64x64/EFEAE4/4A4A4A?text=N/A'">
654
+ <p class="font-medium text-sm truncate w-full">${char.name}</p>
655
+ `;
656
+ charsContainer.appendChild(card);
657
+ });
658
+
659
+ teamElement.appendChild(charsContainer);
660
+ fullHistoryModalContentInner.appendChild(teamElement);
661
+ });
662
+ }
663
+
664
+ fullHistoryModal.classList.remove('hidden');
665
+ setTimeout(() => {
666
+ fullHistoryModalContent.classList.remove('scale-95', 'opacity-0');
667
+ fullHistoryModalContent.classList.add('scale-100', 'opacity-100');
668
+ }, 10);
669
+ }
670
+
671
+ // Скрыть модальное окно всей истории
672
+ function hideFullHistoryModal() {
673
+ fullHistoryModalContent.classList.add('scale-95', 'opacity-0');
674
+ fullHistoryModalContent.classList.remove('scale-100', 'opacity-100');
675
+ setTimeout(() => {
676
+ fullHistoryModal.classList.add('hidden');
677
+ }, 300);
678
+ }
679
+
680
+ // Сохранение отряда в историю
681
+ function saveTeamToHistory(team, name = '') {
682
  historyTeams.unshift({
683
  date: new Date().toISOString(),
684
  characters: team,
685
+ name: name
686
  });
687
 
 
 
 
 
 
688
  localStorage.setItem(`${currentUserUID}_genshinTeamsHistory`, JSON.stringify(historyTeams));
689
+ renderHistory(); // Отображаем только последние 3
690
  }
691
 
692
  // Очистка истории
 
709
  isSpinning = true;
710
  spinButton.disabled = true;
711
  spinButton.textContent = 'Крутим...';
712
+ rouletteResult.innerHTML = ''; // Очищаем поле результата
713
  roulettePlaceholder.classList.add('hidden');
714
  rouletteLoader.classList.remove('hidden');
715
+ saveTeamSection.classList.add('hidden'); // Скрываем секцию сохранения при новом запуске
716
+
 
717
  const teamSize = parseInt(teamSizeSelect.value);
718
  let charsPool = [...availableCharsForSpin];
719
  const selectedTeam = [];
 
750
  const selectedChar = charsPool.splice(selectedIndex, 1)[0];
751
  selectedTeam.push(selectedChar);
752
 
753
+ tempRouletteDiv.innerHTML = ''; // Очищаем временную карточку
754
  const finalCard = createCharacterCard(selectedChar);
755
+ finalCard.classList.add('roulette-item-final-enter'); // Применяем финальную анимацию
756
  tempRouletteDiv.appendChild(finalCard);
757
+ // Запускаем анимацию после небольшого таймаута для CSS перехода
758
  setTimeout(() => {
759
  finalCard.classList.add('roulette-item-final-enter-active');
760
  }, 10);
761
  }
762
  };
763
+ animateSpin(); // Запускаем анимацию для текущего слота
764
 
765
+ await new Promise(resolve => setTimeout(resolve, individualSpinTime + 100)); // Добавляем небольшую задержку после завершения анимации текущего слота
766
  }
767
 
768
  // Завершение рулетки
 
771
  spinButton.textContent = 'Крутить ещё!';
772
  isSpinning = false;
773
 
774
+ // Отображаем результат и секцию сохранения
775
+ renderRouletteResult(selectedTeam);
776
  }
777
 
778
+ // Модальное окно подтверждения (общее для очистки истории/персонажей)
779
  function showConfirmModal(message, callback) {
780
  confirmModalMessage.textContent = message;
781
  confirmModal.classList.remove('hidden');
 
813
  themeToggle.addEventListener('click', toggleTheme);
814
  settingsToggle.addEventListener('click', toggleSettings);
815
  clearHistoryButton.addEventListener('click', () => {
816
+ showConfirmModal('Вы уверены, что хотите очистить всю историю отрядов?', clearHistory);
817
  });
818
  clearPlayerCharactersButton.addEventListener('click', () => {
819
  showConfirmModal('Вы уверены, что хотите очистить список ваших персонажей?', clearPlayerCharacters);
820
  });
821
+ showFullHistoryButton.addEventListener('click', showFullHistoryModal); // Обработчик для модального окна
822
+ fullHistoryModalCloseButton.addEventListener('click', hideFullHistoryModal); // Закрытие модального окна
823
+ fullHistoryModal.addEventListener('click', (e) => { // Закрытие по клику вне контента
824
+ if (e.target === fullHistoryModal) hideFullHistoryModal();
 
 
825
  });
826
 
827
+ saveTeamButton.addEventListener('click', () => {
828
  const teamName = teamNameInput.value.trim();
829
  if (currentGeneratedTeam.length > 0) {
830
  saveTeamToHistory(currentGeneratedTeam, teamName);
831
+ saveTeamSection.classList.add('hidden');
 
 
832
  }
833
  });
834
 
835
+ confirmModal.addEventListener('click', (e) => {
836
+ if (e.target === confirmModal) hideConfirmModal();
837
+ });
838
+
839
+ characterSearchInput.addEventListener('input', (e) => {
840
+ renderPlayerCharactersSelection(e.target.value);
841
  });
 
842
 
843
  // Сохранение настроек при изменении
844
  teamSizeSelect.addEventListener('change', (e) => {