Advertisement
kusehsup

Untitled

Jun 10th, 2025
730
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 53.13 KB | None | 0 0
  1. Я хочу перевести эту .html страницу на nuxt приложение.
  2. Напиши полноценное точное техническое задание для этого, в деталях, какой интерфейс страницы должен быть, опираясь на предоставленный код.
  3.  
  4. <!DOCTYPE html>
  5. <html lang="ru">
  6. <head>
  7.     <meta charset="UTF-8">
  8.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  9.     <title>Модерация тем форума</title>
  10.     <script src="https://cdn.tailwindcss.com"></script>
  11.     <script>
  12.         tailwind.config = {
  13.             darkMode: 'class',
  14.             theme: {
  15.                 extend: {
  16.                     transitionProperty: {
  17.                         'height': 'height',
  18.                         'spacing': 'margin, padding',
  19.                     },
  20.                     keyframes: {
  21.                         'fade-in-down': {
  22.                             '0%': {
  23.                                 opacity: '0',
  24.                                 transform: 'translateY(-10px)'
  25.                             },
  26.                             '100%': {
  27.                                 opacity: '1',
  28.                                 transform: 'translateY(0)'
  29.                             },
  30.                         },
  31.                         'fade-in': {
  32.                             '0%': { opacity: '0' },
  33.                             '100%': { opacity: '1' },
  34.                         },
  35.                         'fade-out': {
  36.                             '0%': { opacity: '1' },
  37.                             '100%': { opacity: '0' },
  38.                         }
  39.                     },
  40.                     animation: {
  41.                         'fade-in-down': 'fade-in-down 0.3s ease-out',
  42.                         'fade-in': 'fade-in 0.3s ease-out',
  43.                         'fade-out': 'fade-out 0.3s ease-out'
  44.                     }
  45.                 }
  46.             }
  47.         }
  48.     </script>
  49.     <style type="text/css">
  50.         .content-row {
  51.             overflow: hidden;
  52.             transition: all 0.3s ease;
  53.             max-height: 0;
  54.             opacity: 0;
  55.         }
  56.         .content-row.open {
  57.             max-height: 500px;
  58.             opacity: 1;
  59.         }
  60.        
  61.         .toast {
  62.             animation: fade-in 0.3s ease-out;
  63.         }
  64.        
  65.         .toast.hide {
  66.             animation: fade-out 0.3s ease-out;
  67.             opacity: 0;
  68.         }
  69.        
  70.         /* Явно задаем стили для скрытых строк */
  71.         tr.content-row {
  72.             display: none;
  73.             opacity: 0;
  74.             transition: opacity 0.3s ease;
  75.         }
  76.        
  77.         tr.content-row.open {
  78.             display: table-row;
  79.             opacity: 1;
  80.         }
  81.        
  82.         /* Стили для модального окна */
  83.         .modal {
  84.             transition: opacity 0.3s ease, transform 0.3s ease;
  85.             transform: translateY(-20px);
  86.             opacity: 0;
  87.         }
  88.        
  89.         .modal.open {
  90.             transform: translateY(0);
  91.             opacity: 1;
  92.         }
  93.        
  94.         .modal-backdrop {
  95.             transition: opacity 0.3s ease;
  96.             opacity: 0;
  97.         }
  98.        
  99.         .modal-backdrop.open {
  100.             opacity: 1;
  101.         }
  102.        
  103.         .volume-control-group:hover .volume-slider {
  104.             opacity: 1;
  105.             visibility: visible;
  106.             transform: scale(1);
  107.         }
  108.        
  109.         .volume-slider {
  110.             transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
  111.         }
  112.     </style>
  113.     <style>
  114. .volume-control-container {
  115.     z-index: 10;
  116. }
  117.  
  118. .volume-control-container:hover .volume-slider {
  119.     opacity: 1;
  120.     visibility: visible;
  121.     transform: scale(1);
  122. }
  123.  
  124. .volume-slider {
  125.     opacity: 0;
  126.     visibility: hidden;
  127.     transform: scale(0.95);
  128.     transform-origin: top right; /* Изменено на top right */
  129.     transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
  130.     z-index: 20;
  131. }
  132.  
  133. /* Вертикальный ползунок */
  134. input[type="range"][orient="vertical"] {
  135.     -webkit-appearance: slider-vertical;
  136.     writing-mode: bt-lr;
  137.     width: 8px;
  138.     height: 100px;
  139.     padding: 0 12px;
  140. }
  141. </style>
  142. <style>
  143. .modal-backdrop {
  144.     opacity: 0;
  145. }
  146. .modal-content {
  147.     opacity: 0;
  148.     transform: translateY(-20px) scale(0.95);
  149. }
  150.  
  151. #reject-modal.open .modal-backdrop {
  152.     opacity: 1;
  153. }
  154. #reject-modal.open .modal-content {
  155.     opacity: 1;
  156.     transform: translateY(0) scale(1);
  157. }
  158. </style>
  159. </head>
  160. <body class="bg-gray-100 dark:bg-gray-900 p-8 transition-colors duration-200">
  161.     <!-- Toaster контейнер -->
  162.     <div id="toaster" class="fixed top-4 right-4 z-50 space-y-2 w-80"></div>
  163.    
  164.     <!-- Модальное окно отклонения -->
  165.     <div id="reject-modal" class="fixed inset-0 z-50 flex items-center justify-center p-4 hidden">
  166.         <div class="fixed inset-0 bg-black bg-opacity-50 transition-opacity duration-300 opacity-0 modal-backdrop"></div>
  167.        
  168.         <div class="relative bg-white dark:bg-gray-800 rounded-xl shadow-xl w-full max-w-md transform transition-all duration-300 scale-95 modal-content">
  169.             <div class="p-6">
  170.                 <div class="flex justify-between items-center mb-4">
  171.                     <h3 class="text-xl font-bold text-gray-800 dark:text-gray-200">Причина отклонения</h3>
  172.                     <button onclick="closeRejectModal()" class="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition-colors">
  173.                         <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  174.                             <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
  175.                         </svg>
  176.                     </button>
  177.                 </div>
  178.                
  179.                 <div class="space-y-3 mb-6">
  180.                     <label class="flex items-center space-x-3 p-3 rounded-lg border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors">
  181.                         <input type="radio" name="reject-reason" class="h-4 w-4 text-red-500 focus:ring-red-400">
  182.                         <span class="text-gray-700 dark:text-gray-300">Нарушение правил сообщества</span>
  183.                     </label>
  184.                    
  185.                     <label class="flex items-center space-x-3 p-3 rounded-lg border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors">
  186.                         <input type="radio" name="reject-reason" class="h-4 w-4 text-red-500 focus:ring-red-400">
  187.                         <span class="text-gray-700 dark:text-gray-300">Некорректный контент</span>
  188.                     </label>
  189.                    
  190.                     <label class="flex items-center space-x-3 p-3 rounded-lg border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors">
  191.                         <input type="radio" name="reject-reason" class="h-4 w-4 text-red-500 focus:ring-red-400">
  192.                         <span class="text-gray-700 dark:text-gray-300">Дубликат существующей темы</span>
  193.                     </label>
  194.                    
  195.                     <label class="flex items-center space-x-3 p-3 rounded-lg border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors">
  196.                         <input type="radio" name="reject-reason" class="h-4 w-4 text-red-500 focus:ring-red-400">
  197.                         <span class="text-gray-700 dark:text-gray-300">Несоответствие разделу</span>
  198.                     </label>
  199.                    
  200.                     <div class="mt-4">
  201.                         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Другая причина</label>
  202.                         <textarea class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-red-500 focus:border-red-500 dark:bg-gray-700 dark:text-white" rows="2" placeholder="Укажите причину..."></textarea>
  203.                     </div>
  204.                 </div>
  205.                
  206.                 <div class="flex justify-end space-x-3">
  207.                     <button onclick="closeRejectModal()" class="px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
  208.                         Отмена
  209.                     </button>
  210.                     <button id="confirm-reject-btn" class="px-4 py-2 bg-gradient-to-r from-red-500 to-red-600 text-white rounded-md shadow hover:from-red-600 hover:to-red-700 transition-all transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50">
  211.                         Подтвердить отклонение
  212.                     </button>
  213.                 </div>
  214.             </div>
  215.         </div>
  216.     </div>
  217.    
  218.     <!-- Модальное окно настроек -->
  219.     <div id="settings-modal" class="modal fixed inset-0 z-50 flex items-center justify-center p-4 hidden">
  220.         <div class="modal-backdrop fixed inset-0 bg-black bg-opacity-50"></div>
  221.        
  222.         <div class="relative bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md max-h-[90vh] overflow-y-auto">
  223.             <div class="p-6">
  224.                 <div class="flex justify-between items-center mb-4">
  225.                     <h3 class="text-xl font-bold text-gray-800 dark:text-gray-200">Настройки</h3>
  226.                     <button id="close-settings" class="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
  227.                         <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  228.                             <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
  229.                         </svg>
  230.                     </button>
  231.                 </div>
  232.                
  233.                 <!-- Секция аккаунта -->
  234.                 <div class="mb-6">
  235.                     <h4 class="text-lg font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
  236.                         <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
  237.                             <path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd" />
  238.                         </svg>
  239.                         Аккаунт
  240.                     </h4>
  241.                    
  242.                     <div class="flex items-center mb-4">
  243.                         <div class="relative w-12 h-12 mr-4">
  244.                             <img src="https://music.esbot.ru/ava.jpg" alt="Аватар" class="rounded-full w-full h-full object-cover">
  245.                             <button class="absolute bottom-0 right-0 bg-blue-500 text-white rounded-full p-1 hover:bg-blue-600">
  246.                                 <svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor">
  247.                                     <path fill-rule="evenodd" d="M4 5a2 2 0 00-2 2v8a2 2 0 002 2h12a2 2 0 002-2V7a2 2 0 00-2-2h-1.586a1 1 0 01-.707-.293l-1.121-1.121A2 2 0 0011.172 3H8.828a2 2 0 00-1.414.586L6.293 4.707A1 1 0 015.586 5H4zm6 9a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd" />
  248.                                 </svg>
  249.                             </button>
  250.                         </div>
  251.                        
  252.                         <div>
  253.                             <div class="text-sm font-medium text-gray-500 dark:text-gray-400">Никнейм</div>
  254.                             <div class="text-lg font-semibold text-gray-800 dark:text-gray-200">kusehsup</div>
  255.                         </div>
  256.                     </div>
  257.                    
  258.                     <div class="mb-4">
  259.                         <div class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Статус подключения форума</div>
  260.                         <div class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
  261.                             <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" viewBox="0 0 20 20" fill="currentColor">
  262.                                 <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
  263.                             </svg>
  264.                             Подключён
  265.                         </div>
  266.                     </div>
  267.                 </div>
  268.                
  269.                 <!-- Секция темы -->
  270.                 <div class="mb-6">
  271.                     <h4 class="text-lg font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
  272.                         <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
  273.                             <path d="M5 4a1 1 0 00-2 0v7.268a2 2 0 000 3.464V16a1 1 0 102 0v-1.268a2 2 0 000-3.464V4zM11 4a1 1 0 10-2 0v1.268a2 2 0 000 3.464V16a1 1 0 102 0V8.732a2 2 0 000-3.464V4zM16 3a1 1 0 011 1v7.268a2 2 0 010 3.464V16a1 1 0 11-2 0v-1.268a2 2 0 010-3.464V4a1 1 0 011-1z" />
  274.                         </svg>
  275.                         Внешний вид
  276.                     </h4>
  277.                    
  278.                     <div class="flex items-center justify-between mb-3">
  279.                         <span class="text-gray-700 dark:text-gray-300">Тёмная тема</span>
  280.                         <button type="checkbox" id="theme-toggle" class="relative inline-flex items-center h-6 rounded-full w-11 bg-gray-200 dark:bg-gray-700 transition-colors duration-200">
  281.                             <span id="theme-toggle-ball" class="inline-block w-4 h-4 transform transition-transform duration-200 translate-x-1 dark:translate-x-6 bg-white rounded-full"></span>
  282.                         </button>
  283.                     </div>
  284.                 </div>
  285.                
  286.                 <!-- Секция настроек модерации -->
  287.                 <div class="mb-6">
  288.                     <h4 class="text-lg font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
  289.                         <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
  290.                             <path fill-rule="evenodd" d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd" />
  291.                         </svg>
  292.                         Настройки модерации
  293.                     </h4>
  294.                    
  295.                     <div class="flex items-center justify-between mb-3">
  296.                         <div>
  297.                             <div class="text-gray-700 dark:text-gray-300">Отправлять ответ с форумного аккаунта</div>
  298.                             <div class="text-xs text-gray-500 dark:text-gray-400">При модерации темы будет отправлен автоматический ответ</div>
  299.                         </div>
  300.                         <label class="inline-flex items-center cursor-pointer">
  301.                             <input type="checkbox" class="sr-only peer" checked>
  302.                             <div class="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
  303.                         </label>
  304.                     </div>
  305.                 </div>
  306.                
  307.                 <!-- Секция системы загрузки треков -->
  308.                 <div>
  309.                     <h4 class="text-lg font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
  310.                         <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
  311.                             <path d="M18 3a1 1 0 00-1.447-.894L8.763 6H5a3 3 0 000 6h.28l1.771 5.316A1 1 0 008 18h1a1 1 0 001-1v-4.382l6.553 3.276A1 1 0 0018 15V3z" />
  312.                         </svg>
  313.                         Система загрузки треков
  314.                     </h4>
  315.                    
  316.                     <div class="space-y-2">
  317.                         <label class="flex items-center space-x-3 p-3 rounded-lg border border-gray-200 dark:border-gray-700 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700">
  318.                             <input type="radio" name="music-service" class="h-4 w-4 text-blue-600" checked>
  319.                             <div class="flex items-center">
  320.                                 <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Yandex_Music_icon.svg/640px-Yandex_Music_icon.svg.png" class="h-6 w-6 mr-2" alt="Yandex Music">
  321.                                 <span class="text-gray-700 dark:text-gray-300">Yandex Music</span>
  322.                             </div>
  323.                         </label>
  324.                        
  325.                         <label class="flex items-center space-x-3 p-3 rounded-lg border border-gray-200 dark:border-gray-700 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700">
  326.                             <input type="radio" name="music-service" class="h-4 w-4 text-blue-600">
  327.                             <div class="flex items-center">
  328.                                 <img src="https://music.esbot.ru/icons8-youtube-144.png" class="h-6 w-6 mr-2" alt="YouTube Music">
  329.                                 <span class="text-gray-700 dark:text-gray-300">YouTube Music</span>
  330.                             </div>
  331.                         </label>
  332.                        
  333.                         <label class="flex items-center space-x-3 p-3 rounded-lg border border-gray-200 dark:border-gray-700 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700">
  334.                             <input type="radio" name="music-service" class="h-4 w-4 text-blue-600">
  335.                             <div class="flex items-center">
  336.                                 <img src="https://cdn-icons-png.freepik.com/512/11893/11893152.png" class="h-6 w-6 mr-2" alt="YouTube Music">
  337.                                 <span class="text-gray-700 dark:text-gray-300">Spotify</span>
  338.                             </div>
  339.                         </label>
  340.                     </div>
  341.                 </div>
  342.             </div>
  343.            
  344.             <div class="bg-gray-50 dark:bg-gray-700 px-6 py-3 rounded-b-lg flex justify-end">
  345.                 <button id="save-settings" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500">
  346.                     Сохранить
  347.                 </button>
  348.             </div>
  349.         </div>
  350.     </div>
  351.    
  352.     <div class="max-w-4xl mx-auto bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 transition-colors duration-200">
  353.         <div class="flex justify-between items-center mb-6">
  354.             <h1 class="text-2xl font-bold text-gray-800 dark:text-gray-200">Модерация тем форума</h1>
  355.             <button id="open-settings" class="p-2 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-600">
  356.                 <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  357.                     <path fill-rule="evenodd" d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd" />
  358.                 </svg>
  359.             </button>
  360.         </div>
  361.        
  362.         <!-- Таблица с темами -->
  363.         <div class="overflow-x-auto">
  364.             <table class="min-w-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700">
  365.                 <thead>
  366.                     <tr class="bg-gray-50 dark:bg-gray-700">
  367.                         <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">ID</th>
  368.                         <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Название темы</th>
  369.                         <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Автор</th>
  370.                         <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Дата создания</th>
  371.                         <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Действия</th>
  372.                     </tr>
  373.                 </thead>
  374.                 <tbody class="divide-y divide-gray-200 dark:divide-gray-700">
  375.                     <!-- Пример строки темы -->
  376.                     <tr class="hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer" onclick="toggleRow(this, 1)">
  377.                         <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">1</td>
  378.                         <td class="px-6 py-4 whitespace-nowrap">
  379.                             <div class="text-sm font-medium text-gray-900 dark:text-gray-200">EXNLXDE feat. QMIIR - SLAVIC FUNK 2</div>
  380.                         </td>
  381.                         <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">user123</td>
  382.                         <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">2023-05-15</td>
  383.                         <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
  384.                             <div class="flex space-x-2">
  385.                                 <!-- Кнопка одобрения -->
  386.                                 <button id="approve-btn-1" onclick="approveTopic(1, event)"
  387.                                         class="relative w-24 h-10 overflow-hidden bg-gradient-to-r from-green-500 to-green-600 text-white rounded-full shadow-md hover:from-green-600 hover:to-green-700 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-opacity-50">
  388.                                     <span class="absolute inset-0 flex items-center justify-center transition-opacity duration-200" id="approve-text-1">
  389.                                         Одобрить
  390.                                     </span>
  391.                                     <span id="approve-spinner-1" class="absolute inset-0 flex items-center justify-center hidden">
  392.                                         <span class="h-5 w-5 animate-spin rounded-full border-2 border-solid border-white border-r-transparent"></span>
  393.                                     </span>
  394.                                 </button>
  395.                                
  396.                                 <!-- Кнопка отклонения -->
  397.                                 <button id="reject-btn-1" onclick="rejectTopic(1, event)"
  398.                                         class="relative w-24 h-10 overflow-hidden bg-gradient-to-r from-red-500 to-red-600 text-white rounded-full shadow-md hover:from-red-600 hover:to-red-700 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-red-400 focus:ring-opacity-50">
  399.                                     <span class="absolute inset-0 flex items-center justify-center transition-opacity duration-200" id="reject-text-1">
  400.                                         Отклонить
  401.                                     </span>
  402.                                     <span id="reject-spinner-1" class="absolute inset-0 flex items-center justify-center hidden">
  403.                                         <span class="h-5 w-5 animate-spin rounded-full border-2 border-solid border-white border-r-transparent"></span>
  404.                                     </span>
  405.                                 </button>
  406.                             </div>
  407.                         </td>
  408.                     </tr>
  409.                     <!-- Скрытый контент (текст песни) -->
  410.                     <tr id="content-1" class="content-row">
  411.                         <td colspan="5" class="px-6 py-4 bg-gray-50 dark:bg-gray-700">
  412.                             <div class="flex flex-col md:flex-row gap-6">
  413.                                 <!-- Левая колонка с обложкой и проигрывателем -->
  414.                                 <div class="flex-shrink-0 w-full md:w-48">
  415.                                     <div class="bg-white dark:bg-gray-600 rounded-lg overflow-hidden shadow-md">
  416.                                         <!-- Обложка трека с элементами управления -->
  417.                                         <div class="relative group">
  418.                                             <img src="https://avatars.yandex.net/get-music-content/9737237/7574f29f.a.25875175-1/m1000x1000?webp=false" alt="Обложка трека"
  419.                                                  class="w-full h-48 object-cover transition-transform duration-300 group-hover:scale-105">
  420.                                            
  421.                                             <!-- Кнопка воспроизведения -->
  422.                                             <button id="play-btn-1" class="absolute inset-0 m-auto w-12 h-12 bg-black bg-opacity-60 text-white rounded-full flex items-center justify-center hover:bg-opacity-80 transition-all duration-200 transform hover:scale-110 shadow-lg">
  423.                                                 <svg id="play-icon-1" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 20 20" fill="currentColor">
  424.                                                     <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
  425.                                                 </svg>
  426.                                                 <svg id="pause-icon-1" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 hidden" viewBox="0 0 20 20" fill="currentColor">
  427.                                                     <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
  428.                                                 </svg>
  429.                                             </button>
  430.                                            
  431.                                             <!-- Кнопка громкости с выпадающим ползунком ВНИЗ -->
  432.                                             <div class="absolute top-2 right-2 volume-control-container">
  433.                                                 <button id="volume-btn-1" class="p-1.5 bg-black bg-opacity-50 text-white rounded-full hover:bg-opacity-70 transition-all flex items-center justify-center volume-btn">
  434.                                                     <svg id="volume-on-icon-1" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
  435.                                                         <path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" clip-rule="evenodd" />
  436.                                                     </svg>
  437.                                                     <svg id="volume-off-icon-1" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 hidden" viewBox="0 0 20 20" fill="currentColor">
  438.                                                         <path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM12.293 7.293a1 1 0 011.414 0L15 8.586l1.293-1.293a1 1 0 111.414 1.414L16.414 10l1.293 1.293a1 1 0 01-1.414 1.414L15 11.414l-1.293 1.293a1 1 0 01-1.414-1.414L13.586 10l-1.293-1.293a1 1 0 010-1.414z" clip-rule="evenodd" />
  439.                                                     </svg>
  440.                                                 </button>
  441.                                                
  442.                                                 <!-- Ползунок громкости (появляется ВНИЗ при наведении) -->
  443.                                                 <div class="absolute top-full right-0 mt-2 px-2 py-2 bg-white dark:bg-gray-700 rounded-md shadow-lg opacity-0 invisible transition-all duration-200 origin-top transform scale-95 volume-slider">
  444.                                                     <input id="volume-1" type="range" min="0" max="100" value="80"
  445.                                                            class="w-24 h-2 bg-gray-300 dark:bg-gray-500 rounded-full appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 dark:[&::-webkit-slider-thumb]:bg-blue-500"
  446.                                                            orient="vertical">
  447.                                                 </div>
  448.                                             </div>
  449.                                            
  450.                                             <!-- Жанр (адаптивный бейдж) -->
  451.                                             <div class="absolute bottom-2 left-2 max-w-[90%]">
  452.                                                 <div class="text-xs px-2 py-1 bg-black bg-opacity-60 text-white rounded-full truncate hover:whitespace-normal hover:bg-opacity-80 transition-all">
  453.                                                     Славянский фанк
  454.                                                 </div>
  455.                                             </div>
  456.                                         </div>
  457.                                        
  458.                                         <!-- Компактный проигрыватель -->
  459.                                         <div class="p-4">
  460.                                             <!-- Прогресс-бар с временем -->
  461.                                             <div class="mb-2">
  462.                                                 <input id="progress-1" type="range" min="0" max="100" value="0"
  463.                                                        class="w-full h-1 bg-gray-300 dark:bg-gray-500 rounded-full appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 dark:[&::-webkit-slider-thumb]:bg-blue-500 hover:[&::-webkit-slider-thumb]:scale-125 transition-all">
  464.                                                 <div class="flex justify-between text-xs text-gray-500 dark:text-gray-400 mt-1">
  465.                                                     <span id="current-time-1">0:00</span>
  466.                                                     <span id="duration-1">3:24</span>
  467.                                                 </div>
  468.                                             </div>
  469.                                         </div>
  470.                                        
  471.                                         <!-- Метаданные -->
  472.                                         <div class="p-4 border-t border-gray-200 dark:border-gray-500">
  473.                                             <div class="mb-1">
  474.                                                 <div class="text-sm font-semibold text-gray-800 dark:text-gray-200 truncate">SLAVIC FUNK 2</div>
  475.                                                 <div class="text-xs text-gray-500 dark:text-gray-400 truncate">EXNLXDE feat. QMIIR</div>
  476.                                             </div>
  477.                                             <div class="text-xs text-gray-500 dark:text-gray-400">Релиз: 15 мая 2023</div>
  478.                                         </div>
  479.                                     </div>
  480.                                    
  481.                                     <!-- Ссылки на стриминговые сервисы -->
  482.                                     <div class="mt-3 grid grid-cols-2 gap-2">
  483.                                         <a href="#" class="flex items-center justify-center px-2 py-1.5 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors text-xs">
  484.                                             <img src="https://music.esbot.ru/icons8-youtube-144.png" class="h-4 w-4 mr-1" alt="YouTube">
  485.                                             YouTube
  486.                                         </a>
  487.                                         <a href="#" class="flex items-center justify-center px-2 py-1.5 bg-black text-white rounded-md hover:bg-gray-800 transition-colors text-xs">
  488.                                             <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Yandex_Music_icon.svg/640px-Yandex_Music_icon.svg.png" class="h-4 w-4 mr-1" alt="Yandex">
  489.                                             Yandex
  490.                                         </a>
  491.                                     </div>
  492.                                 </div>
  493.                                
  494.                                 <!-- Правая колонка с текстом песни -->
  495.                                 <div class="flex-grow">
  496.                                     <div class="bg-white dark:bg-gray-600 rounded-lg shadow-md p-4 h-full">
  497.                                         <h3 class="text-lg font-bold text-gray-800 dark:text-gray-200 mb-4 pb-2 border-b border-gray-200 dark:border-gray-500">Текст песни</h3>
  498.                                        
  499.                                         <div class="prose dark:prose-invert max-w-none text-gray-700 dark:text-gray-300">
  500.                                             <p class="font-medium mb-4 text-blue-600 dark:text-blue-400">[Куплет 1]</p>
  501.                                             <p>Это пример текста песни, который будет отображаться при раскрытии строки.</p>
  502.                                             <p>В реальном приложении этот текст будет подгружаться из базы данных.</p>
  503.                                            
  504.                                             <p class="font-medium mt-6 mb-4 text-blue-600 dark:text-blue-400">[Припев]</p>
  505.                                             <p>Славянский фанк, мы зажигаем,</p>
  506.                                             <p>Бит такой мощный, все танцуют.</p>
  507.                                             <p>Наши ритмы — как удар молнии,</p>
  508.                                             <p>Звук летит сквозь все препоны.</p>
  509.                                         </div>
  510.                                     </div>
  511.                                 </div>
  512.                             </div>
  513.                         </td>
  514.                     </tr>
  515.                 </tbody>
  516.             </table>
  517.         </div>
  518.  
  519.         <!-- Пагинация (пример) -->
  520.         <div class="flex items-center justify-between mt-4">
  521.             <div class="text-sm text-gray-700 dark:text-gray-300">
  522.                 Показано <span class="font-medium">1</span> из <span class="font-medium">10</span> тем
  523.             </div>
  524.             <div class="flex space-x-2">
  525.                 <button class="px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-md text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
  526.                     Назад
  527.                 </button>
  528.                 <button class="px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-md text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
  529.                     Вперед
  530.                 </button>
  531.             </div>
  532.         </div>
  533.     </div>
  534.  
  535.     <script>
  536.         // Тёмная тема
  537.         let darkMode = localStorage.getItem('darkMode') === 'true';
  538.        
  539.         // Применяем текущую тему при загрузке
  540.         if (darkMode) {
  541.             document.documentElement.classList.add('dark');
  542.             document.getElementById('theme-toggle-ball').classList.add('dark:translate-x-6');
  543.         }
  544.  
  545.         // Переключатель темы
  546.         document.getElementById('theme-toggle').addEventListener('click', () => {
  547.             darkMode = !darkMode;
  548.             localStorage.setItem('darkMode', darkMode);
  549.            
  550.             if (darkMode) {
  551.                 document.documentElement.classList.add('dark');
  552.             } else {
  553.                 document.documentElement.classList.remove('dark');
  554.             }
  555.         });
  556.  
  557.         // Управление модальным окном
  558.         const modal = document.getElementById('settings-modal');
  559.         const backdrop = modal.querySelector('.modal-backdrop');
  560.        
  561.         document.getElementById('open-settings').addEventListener('click', () => {
  562.             modal.classList.remove('hidden');
  563.             setTimeout(() => {
  564.                 modal.classList.add('open');
  565.                 backdrop.classList.add('open');
  566.             }, 10);
  567.         });
  568.        
  569.         document.getElementById('close-settings').addEventListener('click', closeModal);
  570.         document.getElementById('save-settings').addEventListener('click', closeModal);
  571.        
  572.         backdrop.addEventListener('click', closeModal);
  573.        
  574.         function closeModal() {
  575.             modal.classList.remove('open');
  576.             backdrop.classList.remove('open');
  577.             setTimeout(() => {
  578.                 modal.classList.add('hidden');
  579.             }, 300);
  580.         }
  581.  
  582.         // Функция для раскрытия/скрытия строки с текстом песни
  583.         function toggleRow(row, rowId) {
  584.             event.stopPropagation();
  585.             const contentRow = document.getElementById(`content-${rowId}`);
  586.            
  587.             // Закрываем все открытые строки
  588.             document.querySelectorAll('.content-row.open').forEach(el => {
  589.                 if (el.id !== `content-${rowId}`) {
  590.                     el.classList.remove('open');
  591.                 }
  592.             });
  593.            
  594.             // Переключаем текущую строку
  595.             if (contentRow) {
  596.                 contentRow.classList.toggle('open');
  597.             }
  598.         }
  599.  
  600.         // Функция для показа toast-уведомления
  601.         function showToast(message, type = 'success') {
  602.             const toaster = document.getElementById('toaster');
  603.             const toastId = Date.now();
  604.            
  605.             const toast = document.createElement('div');
  606.             toast.id = `toast-${toastId}`;
  607.             toast.className = `toast p-4 rounded-md shadow-lg ${
  608.                 type === 'success'
  609.                     ? 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200'
  610.                     : 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200'
  611.             }`;
  612.             toast.innerHTML = `
  613.                 <div class="flex justify-between items-center">
  614.                     <div>${message}</div>
  615.                     <button onclick="dismissToast('${toastId}')" class="text-gray-500 hover:text-gray-700">
  616.                         <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  617.                             <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
  618.                         </svg>
  619.                     </button>
  620.                 </div>
  621.             `;
  622.            
  623.             toaster.appendChild(toast);
  624.            
  625.             // Автоматическое закрытие через 5 секунд
  626.             setTimeout(() => dismissToast(toastId), 5000);
  627.         }
  628.  
  629.         // Функция для скрытия toast-уведомления
  630.         function dismissToast(toastId) {
  631.             const toast = document.getElementById(`toast-${toastId}`);
  632.             if (toast) {
  633.                 toast.classList.add('hide');
  634.                 setTimeout(() => toast.remove(), 300);
  635.             }
  636.         }
  637.  
  638.         function approveTopic(topicId, event) {
  639.             event.stopPropagation();
  640.            
  641.             const btn = document.getElementById(`approve-btn-${topicId}`);
  642.             const text = document.getElementById(`approve-text-${topicId}`);
  643.             const spinner = document.getElementById(`approve-spinner-${topicId}`);
  644.            
  645.             // Блокируем кнопку и показываем спиннер
  646.             btn.disabled = true;
  647.             text.classList.add('opacity-0');
  648.             spinner.classList.remove('hidden');
  649.            
  650.             // Эмулируем запрос к серверу
  651.             setTimeout(() => {
  652.                 // В реальном приложении здесь будет обработка ответа
  653.                 const row = document.querySelector(`tr[onclick="toggleRow(this, ${topicId})"]`);
  654.                 const contentRow = document.getElementById(`content-${topicId}`);
  655.                 if (row) row.remove();
  656.                 if (contentRow) contentRow.remove();
  657.                
  658.                 showToast(`Тема #${topicId} одобрена`, 'success');
  659.             }, 1000);
  660.         }
  661.        
  662.         function rejectTopic(topicId, event) {
  663.             event.stopPropagation();
  664.            
  665.             const btn = document.getElementById(`reject-btn-${topicId}`);
  666.             const text = document.getElementById(`reject-text-${topicId}`);
  667.             const spinner = document.getElementById(`reject-spinner-${topicId}`);
  668.            
  669.             // Блокируем кнопку и показываем спиннер
  670.             btn.disabled = true;
  671.             text.classList.add('opacity-0');
  672.             spinner.classList.remove('hidden');
  673.            
  674.             // Эмулируем запрос к серверу
  675.             setTimeout(() => {
  676.                 // В реальном приложении здесь будет обработка ответа
  677.                 const row = document.querySelector(`tr[onclick="toggleRow(this, ${topicId})"]`);
  678.                 const contentRow = document.getElementById(`content-${topicId}`);
  679.                 if (row) row.remove();
  680.                 if (contentRow) contentRow.remove();
  681.                
  682.                 showToast(`Тема #${topicId} отклонена`, 'error');
  683.             }, 1000);
  684.         }
  685.        
  686.             // Закрытие toast по клику вне его
  687.             document.addEventListener('click', (event) => {
  688.                 if (!event.target.closest('.toast') && !event.target.closest('button[onclick^="dismissToast"]')) {
  689.                     document.querySelectorAll('.toast').forEach(toast => {
  690.                         const toastId = toast.id.replace('toast-', '');
  691.                         dismissToast(toastId);
  692.                     });
  693.                 }
  694.             });
  695.         </script>
  696.         <script>
  697.     // Управление проигрывателем
  698.     function initPlayer(playerId) {
  699.         const playBtn = document.getElementById(`play-btn-${playerId}`);
  700.         const playIcon = document.getElementById(`play-icon-${playerId}`);
  701.         const pauseIcon = document.getElementById(`pause-icon-${playerId}`);
  702.         const progress = document.getElementById(`progress-${playerId}`);
  703.         const volumeBtn = document.getElementById(`volume-btn-${playerId}`);
  704.         const volumeOnIcon = document.getElementById(`volume-on-icon-${playerId}`);
  705.         const volumeOffIcon = document.getElementById(`volume-off-icon-${playerId}`);
  706.         const volumeSlider = document.getElementById(`volume-${playerId}`);
  707.         const currentTime = document.getElementById(`current-time-${playerId}`);
  708.         const duration = document.getElementById(`duration-${playerId}`);
  709.        
  710.         let isPlaying = false;
  711.         let isMuted = false;
  712.         let currentVolume = 80;
  713.        
  714.         // Форматирование времени (секунды в мм:сс)
  715.         function formatTime(seconds) {
  716.             const mins = Math.floor(seconds / 60);
  717.             const secs = Math.floor(seconds % 60);
  718.             return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
  719.         }
  720.        
  721.         // Установка длительности трека (в реальном приложении будет из аудиофайла)
  722.         duration.textContent = formatTime(204); // 3:24
  723.        
  724.         // Управление воспроизведением
  725.         playBtn.addEventListener('click', () => {
  726.             isPlaying = !isPlaying;
  727.            
  728.             if (isPlaying) {
  729.                 playIcon.classList.add('hidden');
  730.                 pauseIcon.classList.remove('hidden');
  731.                 // В реальном приложении: audioElement.play()
  732.             } else {
  733.                 playIcon.classList.remove('hidden');
  734.                 pauseIcon.classList.add('hidden');
  735.                 // В реальном приложении: audioElement.pause()
  736.             }
  737.         });
  738.        
  739.         // Перемотка трека
  740.         progress.addEventListener('input', (e) => {
  741.             const percent = e.target.value;
  742.             const time = (percent / 100) * 204; // 204 - длительность трека в секундах
  743.             currentTime.textContent = formatTime(time);
  744.             // В реальном приложении: audioElement.currentTime = time
  745.         });
  746.        
  747.         // Управление громкостью
  748.         volumeSlider.addEventListener('input', (e) => {
  749.             currentVolume = e.target.value;
  750.            
  751.             if (currentVolume == 0) {
  752.                 isMuted = true;
  753.                 volumeOnIcon.classList.add('hidden');
  754.                 volumeOffIcon.classList.remove('hidden');
  755.             } else {
  756.                 isMuted = false;
  757.                 volumeOnIcon.classList.remove('hidden');
  758.                 volumeOffIcon.classList.add('hidden');
  759.             }
  760.            
  761.             // В реальном приложении: audioElement.volume = currentVolume / 100
  762.         });
  763.        
  764.         // Кнопка mute/unmute
  765.         volumeBtn.addEventListener('click', () => {
  766.             isMuted = !isMuted;
  767.            
  768.             if (isMuted) {
  769.                 volumeSlider.value = 0;
  770.                 volumeOnIcon.classList.add('hidden');
  771.                 volumeOffIcon.classList.remove('hidden');
  772.                 // В реальном приложении: audioElement.volume = 0
  773.             } else {
  774.                 volumeSlider.value = currentVolume;
  775.                 volumeOnIcon.classList.remove('hidden');
  776.                 volumeOffIcon.classList.add('hidden');
  777.                 // В реальном приложении: audioElement.volume = currentVolume / 100
  778.             }
  779.         });
  780.        
  781.         // Эмуляция прогресса воспроизведения (в реальном приложении будет из audioElement)
  782.         if (isPlaying) {
  783.             setInterval(() => {
  784.                 const currentProgress = parseFloat(progress.value);
  785.                 if (currentProgress < 100) {
  786.                     progress.value = currentProgress + 0.5;
  787.                     const time = (progress.value / 100) * 204;
  788.                     currentTime.textContent = formatTime(time);
  789.                 } else {
  790.                     isPlaying = false;
  791.                     playIcon.classList.remove('hidden');
  792.                     pauseIcon.classList.add('hidden');
  793.                 }
  794.             }, 1000);
  795.         }
  796.     }
  797.    
  798.     // Инициализация проигрывателей при загрузке страницы
  799.     document.addEventListener('DOMContentLoaded', () => {
  800.         initPlayer(1);
  801.         initPlayer(2);
  802.     });
  803. </script>
  804. <script>
  805. document.addEventListener('DOMContentLoaded', function() {
  806.     const volumeControls = document.querySelectorAll('.volume-control-container');
  807.    
  808.     volumeControls.forEach(control => {
  809.         const btn = control.querySelector('.volume-btn');
  810.         const slider = control.querySelector('.volume-slider');
  811.        
  812.         btn.addEventListener('mouseenter', () => {
  813.             slider.style.opacity = '1';
  814.             slider.style.visibility = 'visible';
  815.             slider.style.transform = 'scale(1)';
  816.         });
  817.        
  818.         control.addEventListener('mouseleave', () => {
  819.             slider.style.opacity = '0';
  820.             slider.style.visibility = 'hidden';
  821.             slider.style.transform = 'scale(0.95)';
  822.         });
  823.        
  824.         slider.addEventListener('mouseenter', () => {
  825.             slider.style.opacity = '1';
  826.             slider.style.visibility = 'visible';
  827.             slider.style.transform = 'scale(1)';
  828.         });
  829.     });
  830. });
  831. </script>
  832. <script>
  833. let currentRejectTopicId = null;
  834.  
  835. function showRejectModal(topicId) {
  836.     currentRejectTopicId = topicId;
  837.     const modal = document.getElementById('reject-modal');
  838.     modal.classList.remove('hidden');
  839.     setTimeout(() => {
  840.         modal.classList.add('open');
  841.     }, 10);
  842. }
  843.  
  844. function closeRejectModal() {
  845.     const modal = document.getElementById('reject-modal');
  846.     modal.classList.remove('open');
  847.     setTimeout(() => {
  848.         modal.classList.add('hidden');
  849.         currentRejectTopicId = null;
  850.     }, 300);
  851. }
  852.  
  853. function rejectTopic(topicId, event) {
  854.     event.stopPropagation();
  855.     showRejectModal(topicId);
  856. }
  857.  
  858. document.getElementById('confirm-reject-btn').addEventListener('click', function() {
  859.     const spinner = document.getElementById(`reject-spinner-${currentRejectTopicId}`);
  860.     const text = document.getElementById(`reject-text-${currentRejectTopicId}`);
  861.     const btn = document.getElementById(`reject-btn-${currentRejectTopicId}`);
  862.    
  863.     btn.disabled = true;
  864.     text.classList.add('opacity-0');
  865.     spinner.classList.remove('hidden');
  866.     closeRejectModal();
  867.    
  868.     setTimeout(() => {
  869.         const row = document.querySelector(`tr[onclick="toggleRow(this, ${currentRejectTopicId})"]`);
  870.         const contentRow = document.getElementById(`content-${currentRejectTopicId}`);
  871.         if (row) row.remove();
  872.         if (contentRow) contentRow.remove();
  873.        
  874.         showToast(`Тема #${currentRejectTopicId} отклонена`, 'error');
  875.     }, 1000);
  876. });
  877. </script>
  878.     </body>
  879. </html>
  880.  
  881. Напиши более точное техническое задание, учитывая всеразличные детали страницы. Допустим, ты не указал, что при нажатии на кнопку одобрить или отклонить, форма должна оставаться статичной, не менять свои размеры, а вместо текста на кнопке должен появлятся спиннер.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement