Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Я хочу перевести эту .html страницу на nuxt приложение.
- Напиши полноценное точное техническое задание для этого, в деталях, какой интерфейс страницы должен быть, опираясь на предоставленный код.
- <!DOCTYPE html>
- <html lang="ru">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Модерация тем форума</title>
- <script src="https://cdn.tailwindcss.com"></script>
- <script>
- tailwind.config = {
- darkMode: 'class',
- theme: {
- extend: {
- transitionProperty: {
- 'height': 'height',
- 'spacing': 'margin, padding',
- },
- keyframes: {
- 'fade-in-down': {
- '0%': {
- opacity: '0',
- transform: 'translateY(-10px)'
- },
- '100%': {
- opacity: '1',
- transform: 'translateY(0)'
- },
- },
- 'fade-in': {
- '0%': { opacity: '0' },
- '100%': { opacity: '1' },
- },
- 'fade-out': {
- '0%': { opacity: '1' },
- '100%': { opacity: '0' },
- }
- },
- animation: {
- 'fade-in-down': 'fade-in-down 0.3s ease-out',
- 'fade-in': 'fade-in 0.3s ease-out',
- 'fade-out': 'fade-out 0.3s ease-out'
- }
- }
- }
- }
- </script>
- <style type="text/css">
- .content-row {
- overflow: hidden;
- transition: all 0.3s ease;
- max-height: 0;
- opacity: 0;
- }
- .content-row.open {
- max-height: 500px;
- opacity: 1;
- }
- .toast {
- animation: fade-in 0.3s ease-out;
- }
- .toast.hide {
- animation: fade-out 0.3s ease-out;
- opacity: 0;
- }
- /* Явно задаем стили для скрытых строк */
- tr.content-row {
- display: none;
- opacity: 0;
- transition: opacity 0.3s ease;
- }
- tr.content-row.open {
- display: table-row;
- opacity: 1;
- }
- /* Стили для модального окна */
- .modal {
- transition: opacity 0.3s ease, transform 0.3s ease;
- transform: translateY(-20px);
- opacity: 0;
- }
- .modal.open {
- transform: translateY(0);
- opacity: 1;
- }
- .modal-backdrop {
- transition: opacity 0.3s ease;
- opacity: 0;
- }
- .modal-backdrop.open {
- opacity: 1;
- }
- .volume-control-group:hover .volume-slider {
- opacity: 1;
- visibility: visible;
- transform: scale(1);
- }
- .volume-slider {
- transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
- }
- </style>
- <style>
- .volume-control-container {
- z-index: 10;
- }
- .volume-control-container:hover .volume-slider {
- opacity: 1;
- visibility: visible;
- transform: scale(1);
- }
- .volume-slider {
- opacity: 0;
- visibility: hidden;
- transform: scale(0.95);
- transform-origin: top right; /* Изменено на top right */
- transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
- z-index: 20;
- }
- /* Вертикальный ползунок */
- input[type="range"][orient="vertical"] {
- -webkit-appearance: slider-vertical;
- writing-mode: bt-lr;
- width: 8px;
- height: 100px;
- padding: 0 12px;
- }
- </style>
- <style>
- .modal-backdrop {
- opacity: 0;
- }
- .modal-content {
- opacity: 0;
- transform: translateY(-20px) scale(0.95);
- }
- #reject-modal.open .modal-backdrop {
- opacity: 1;
- }
- #reject-modal.open .modal-content {
- opacity: 1;
- transform: translateY(0) scale(1);
- }
- </style>
- </head>
- <body class="bg-gray-100 dark:bg-gray-900 p-8 transition-colors duration-200">
- <!-- Toaster контейнер -->
- <div id="toaster" class="fixed top-4 right-4 z-50 space-y-2 w-80"></div>
- <!-- Модальное окно отклонения -->
- <div id="reject-modal" class="fixed inset-0 z-50 flex items-center justify-center p-4 hidden">
- <div class="fixed inset-0 bg-black bg-opacity-50 transition-opacity duration-300 opacity-0 modal-backdrop"></div>
- <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">
- <div class="p-6">
- <div class="flex justify-between items-center mb-4">
- <h3 class="text-xl font-bold text-gray-800 dark:text-gray-200">Причина отклонения</h3>
- <button onclick="closeRejectModal()" class="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition-colors">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
- </svg>
- </button>
- </div>
- <div class="space-y-3 mb-6">
- <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">
- <input type="radio" name="reject-reason" class="h-4 w-4 text-red-500 focus:ring-red-400">
- <span class="text-gray-700 dark:text-gray-300">Нарушение правил сообщества</span>
- </label>
- <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">
- <input type="radio" name="reject-reason" class="h-4 w-4 text-red-500 focus:ring-red-400">
- <span class="text-gray-700 dark:text-gray-300">Некорректный контент</span>
- </label>
- <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">
- <input type="radio" name="reject-reason" class="h-4 w-4 text-red-500 focus:ring-red-400">
- <span class="text-gray-700 dark:text-gray-300">Дубликат существующей темы</span>
- </label>
- <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">
- <input type="radio" name="reject-reason" class="h-4 w-4 text-red-500 focus:ring-red-400">
- <span class="text-gray-700 dark:text-gray-300">Несоответствие разделу</span>
- </label>
- <div class="mt-4">
- <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Другая причина</label>
- <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>
- </div>
- </div>
- <div class="flex justify-end space-x-3">
- <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">
- Отмена
- </button>
- <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">
- Подтвердить отклонение
- </button>
- </div>
- </div>
- </div>
- </div>
- <!-- Модальное окно настроек -->
- <div id="settings-modal" class="modal fixed inset-0 z-50 flex items-center justify-center p-4 hidden">
- <div class="modal-backdrop fixed inset-0 bg-black bg-opacity-50"></div>
- <div class="relative bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md max-h-[90vh] overflow-y-auto">
- <div class="p-6">
- <div class="flex justify-between items-center mb-4">
- <h3 class="text-xl font-bold text-gray-800 dark:text-gray-200">Настройки</h3>
- <button id="close-settings" class="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
- </svg>
- </button>
- </div>
- <!-- Секция аккаунта -->
- <div class="mb-6">
- <h4 class="text-lg font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- Аккаунт
- </h4>
- <div class="flex items-center mb-4">
- <div class="relative w-12 h-12 mr-4">
- <img src="https://music.esbot.ru/ava.jpg" alt="Аватар" class="rounded-full w-full h-full object-cover">
- <button class="absolute bottom-0 right-0 bg-blue-500 text-white rounded-full p-1 hover:bg-blue-600">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- </button>
- </div>
- <div>
- <div class="text-sm font-medium text-gray-500 dark:text-gray-400">Никнейм</div>
- <div class="text-lg font-semibold text-gray-800 dark:text-gray-200">kusehsup</div>
- </div>
- </div>
- <div class="mb-4">
- <div class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Статус подключения форума</div>
- <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">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- Подключён
- </div>
- </div>
- </div>
- <!-- Секция темы -->
- <div class="mb-6">
- <h4 class="text-lg font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- Внешний вид
- </h4>
- <div class="flex items-center justify-between mb-3">
- <span class="text-gray-700 dark:text-gray-300">Тёмная тема</span>
- <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">
- <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>
- </button>
- </div>
- </div>
- <!-- Секция настроек модерации -->
- <div class="mb-6">
- <h4 class="text-lg font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- Настройки модерации
- </h4>
- <div class="flex items-center justify-between mb-3">
- <div>
- <div class="text-gray-700 dark:text-gray-300">Отправлять ответ с форумного аккаунта</div>
- <div class="text-xs text-gray-500 dark:text-gray-400">При модерации темы будет отправлен автоматический ответ</div>
- </div>
- <label class="inline-flex items-center cursor-pointer">
- <input type="checkbox" class="sr-only peer" checked>
- <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>
- </label>
- </div>
- </div>
- <!-- Секция системы загрузки треков -->
- <div>
- <h4 class="text-lg font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- Система загрузки треков
- </h4>
- <div class="space-y-2">
- <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">
- <input type="radio" name="music-service" class="h-4 w-4 text-blue-600" checked>
- <div class="flex items-center">
- <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">
- <span class="text-gray-700 dark:text-gray-300">Yandex Music</span>
- </div>
- </label>
- <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">
- <input type="radio" name="music-service" class="h-4 w-4 text-blue-600">
- <div class="flex items-center">
- <img src="https://music.esbot.ru/icons8-youtube-144.png" class="h-6 w-6 mr-2" alt="YouTube Music">
- <span class="text-gray-700 dark:text-gray-300">YouTube Music</span>
- </div>
- </label>
- <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">
- <input type="radio" name="music-service" class="h-4 w-4 text-blue-600">
- <div class="flex items-center">
- <img src="https://cdn-icons-png.freepik.com/512/11893/11893152.png" class="h-6 w-6 mr-2" alt="YouTube Music">
- <span class="text-gray-700 dark:text-gray-300">Spotify</span>
- </div>
- </label>
- </div>
- </div>
- </div>
- <div class="bg-gray-50 dark:bg-gray-700 px-6 py-3 rounded-b-lg flex justify-end">
- <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">
- Сохранить
- </button>
- </div>
- </div>
- </div>
- <div class="max-w-4xl mx-auto bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 transition-colors duration-200">
- <div class="flex justify-between items-center mb-6">
- <h1 class="text-2xl font-bold text-gray-800 dark:text-gray-200">Модерация тем форума</h1>
- <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">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- </button>
- </div>
- <!-- Таблица с темами -->
- <div class="overflow-x-auto">
- <table class="min-w-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700">
- <thead>
- <tr class="bg-gray-50 dark:bg-gray-700">
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">ID</th>
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Название темы</th>
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Автор</th>
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Дата создания</th>
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Действия</th>
- </tr>
- </thead>
- <tbody class="divide-y divide-gray-200 dark:divide-gray-700">
- <!-- Пример строки темы -->
- <tr class="hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer" onclick="toggleRow(this, 1)">
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">1</td>
- <td class="px-6 py-4 whitespace-nowrap">
- <div class="text-sm font-medium text-gray-900 dark:text-gray-200">EXNLXDE feat. QMIIR - SLAVIC FUNK 2</div>
- </td>
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">user123</td>
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">2023-05-15</td>
- <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
- <div class="flex space-x-2">
- <!-- Кнопка одобрения -->
- <button id="approve-btn-1" onclick="approveTopic(1, event)"
- 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">
- <span class="absolute inset-0 flex items-center justify-center transition-opacity duration-200" id="approve-text-1">
- Одобрить
- </span>
- <span id="approve-spinner-1" class="absolute inset-0 flex items-center justify-center hidden">
- <span class="h-5 w-5 animate-spin rounded-full border-2 border-solid border-white border-r-transparent"></span>
- </span>
- </button>
- <!-- Кнопка отклонения -->
- <button id="reject-btn-1" onclick="rejectTopic(1, event)"
- 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">
- <span class="absolute inset-0 flex items-center justify-center transition-opacity duration-200" id="reject-text-1">
- Отклонить
- </span>
- <span id="reject-spinner-1" class="absolute inset-0 flex items-center justify-center hidden">
- <span class="h-5 w-5 animate-spin rounded-full border-2 border-solid border-white border-r-transparent"></span>
- </span>
- </button>
- </div>
- </td>
- </tr>
- <!-- Скрытый контент (текст песни) -->
- <tr id="content-1" class="content-row">
- <td colspan="5" class="px-6 py-4 bg-gray-50 dark:bg-gray-700">
- <div class="flex flex-col md:flex-row gap-6">
- <!-- Левая колонка с обложкой и проигрывателем -->
- <div class="flex-shrink-0 w-full md:w-48">
- <div class="bg-white dark:bg-gray-600 rounded-lg overflow-hidden shadow-md">
- <!-- Обложка трека с элементами управления -->
- <div class="relative group">
- <img src="https://avatars.yandex.net/get-music-content/9737237/7574f29f.a.25875175-1/m1000x1000?webp=false" alt="Обложка трека"
- class="w-full h-48 object-cover transition-transform duration-300 group-hover:scale-105">
- <!-- Кнопка воспроизведения -->
- <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">
- <svg id="play-icon-1" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- <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">
- <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" />
- </svg>
- </button>
- <!-- Кнопка громкости с выпадающим ползунком ВНИЗ -->
- <div class="absolute top-2 right-2 volume-control-container">
- <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">
- <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">
- <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" />
- </svg>
- <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">
- <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" />
- </svg>
- </button>
- <!-- Ползунок громкости (появляется ВНИЗ при наведении) -->
- <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">
- <input id="volume-1" type="range" min="0" max="100" value="80"
- 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"
- orient="vertical">
- </div>
- </div>
- <!-- Жанр (адаптивный бейдж) -->
- <div class="absolute bottom-2 left-2 max-w-[90%]">
- <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">
- Славянский фанк
- </div>
- </div>
- </div>
- <!-- Компактный проигрыватель -->
- <div class="p-4">
- <!-- Прогресс-бар с временем -->
- <div class="mb-2">
- <input id="progress-1" type="range" min="0" max="100" value="0"
- 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">
- <div class="flex justify-between text-xs text-gray-500 dark:text-gray-400 mt-1">
- <span id="current-time-1">0:00</span>
- <span id="duration-1">3:24</span>
- </div>
- </div>
- </div>
- <!-- Метаданные -->
- <div class="p-4 border-t border-gray-200 dark:border-gray-500">
- <div class="mb-1">
- <div class="text-sm font-semibold text-gray-800 dark:text-gray-200 truncate">SLAVIC FUNK 2</div>
- <div class="text-xs text-gray-500 dark:text-gray-400 truncate">EXNLXDE feat. QMIIR</div>
- </div>
- <div class="text-xs text-gray-500 dark:text-gray-400">Релиз: 15 мая 2023</div>
- </div>
- </div>
- <!-- Ссылки на стриминговые сервисы -->
- <div class="mt-3 grid grid-cols-2 gap-2">
- <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">
- <img src="https://music.esbot.ru/icons8-youtube-144.png" class="h-4 w-4 mr-1" alt="YouTube">
- YouTube
- </a>
- <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">
- <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">
- Yandex
- </a>
- </div>
- </div>
- <!-- Правая колонка с текстом песни -->
- <div class="flex-grow">
- <div class="bg-white dark:bg-gray-600 rounded-lg shadow-md p-4 h-full">
- <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>
- <div class="prose dark:prose-invert max-w-none text-gray-700 dark:text-gray-300">
- <p class="font-medium mb-4 text-blue-600 dark:text-blue-400">[Куплет 1]</p>
- <p>Это пример текста песни, который будет отображаться при раскрытии строки.</p>
- <p>В реальном приложении этот текст будет подгружаться из базы данных.</p>
- <p class="font-medium mt-6 mb-4 text-blue-600 dark:text-blue-400">[Припев]</p>
- <p>Славянский фанк, мы зажигаем,</p>
- <p>Бит такой мощный, все танцуют.</p>
- <p>Наши ритмы — как удар молнии,</p>
- <p>Звук летит сквозь все препоны.</p>
- </div>
- </div>
- </div>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <!-- Пагинация (пример) -->
- <div class="flex items-center justify-between mt-4">
- <div class="text-sm text-gray-700 dark:text-gray-300">
- Показано <span class="font-medium">1</span> из <span class="font-medium">10</span> тем
- </div>
- <div class="flex space-x-2">
- <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">
- Назад
- </button>
- <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">
- Вперед
- </button>
- </div>
- </div>
- </div>
- <script>
- // Тёмная тема
- let darkMode = localStorage.getItem('darkMode') === 'true';
- // Применяем текущую тему при загрузке
- if (darkMode) {
- document.documentElement.classList.add('dark');
- document.getElementById('theme-toggle-ball').classList.add('dark:translate-x-6');
- }
- // Переключатель темы
- document.getElementById('theme-toggle').addEventListener('click', () => {
- darkMode = !darkMode;
- localStorage.setItem('darkMode', darkMode);
- if (darkMode) {
- document.documentElement.classList.add('dark');
- } else {
- document.documentElement.classList.remove('dark');
- }
- });
- // Управление модальным окном
- const modal = document.getElementById('settings-modal');
- const backdrop = modal.querySelector('.modal-backdrop');
- document.getElementById('open-settings').addEventListener('click', () => {
- modal.classList.remove('hidden');
- setTimeout(() => {
- modal.classList.add('open');
- backdrop.classList.add('open');
- }, 10);
- });
- document.getElementById('close-settings').addEventListener('click', closeModal);
- document.getElementById('save-settings').addEventListener('click', closeModal);
- backdrop.addEventListener('click', closeModal);
- function closeModal() {
- modal.classList.remove('open');
- backdrop.classList.remove('open');
- setTimeout(() => {
- modal.classList.add('hidden');
- }, 300);
- }
- // Функция для раскрытия/скрытия строки с текстом песни
- function toggleRow(row, rowId) {
- event.stopPropagation();
- const contentRow = document.getElementById(`content-${rowId}`);
- // Закрываем все открытые строки
- document.querySelectorAll('.content-row.open').forEach(el => {
- if (el.id !== `content-${rowId}`) {
- el.classList.remove('open');
- }
- });
- // Переключаем текущую строку
- if (contentRow) {
- contentRow.classList.toggle('open');
- }
- }
- // Функция для показа toast-уведомления
- function showToast(message, type = 'success') {
- const toaster = document.getElementById('toaster');
- const toastId = Date.now();
- const toast = document.createElement('div');
- toast.id = `toast-${toastId}`;
- toast.className = `toast p-4 rounded-md shadow-lg ${
- type === 'success'
- ? 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200'
- : 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200'
- }`;
- toast.innerHTML = `
- <div class="flex justify-between items-center">
- <div>${message}</div>
- <button onclick="dismissToast('${toastId}')" class="text-gray-500 hover:text-gray-700">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
- <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" />
- </svg>
- </button>
- </div>
- `;
- toaster.appendChild(toast);
- // Автоматическое закрытие через 5 секунд
- setTimeout(() => dismissToast(toastId), 5000);
- }
- // Функция для скрытия toast-уведомления
- function dismissToast(toastId) {
- const toast = document.getElementById(`toast-${toastId}`);
- if (toast) {
- toast.classList.add('hide');
- setTimeout(() => toast.remove(), 300);
- }
- }
- function approveTopic(topicId, event) {
- event.stopPropagation();
- const btn = document.getElementById(`approve-btn-${topicId}`);
- const text = document.getElementById(`approve-text-${topicId}`);
- const spinner = document.getElementById(`approve-spinner-${topicId}`);
- // Блокируем кнопку и показываем спиннер
- btn.disabled = true;
- text.classList.add('opacity-0');
- spinner.classList.remove('hidden');
- // Эмулируем запрос к серверу
- setTimeout(() => {
- // В реальном приложении здесь будет обработка ответа
- const row = document.querySelector(`tr[onclick="toggleRow(this, ${topicId})"]`);
- const contentRow = document.getElementById(`content-${topicId}`);
- if (row) row.remove();
- if (contentRow) contentRow.remove();
- showToast(`Тема #${topicId} одобрена`, 'success');
- }, 1000);
- }
- function rejectTopic(topicId, event) {
- event.stopPropagation();
- const btn = document.getElementById(`reject-btn-${topicId}`);
- const text = document.getElementById(`reject-text-${topicId}`);
- const spinner = document.getElementById(`reject-spinner-${topicId}`);
- // Блокируем кнопку и показываем спиннер
- btn.disabled = true;
- text.classList.add('opacity-0');
- spinner.classList.remove('hidden');
- // Эмулируем запрос к серверу
- setTimeout(() => {
- // В реальном приложении здесь будет обработка ответа
- const row = document.querySelector(`tr[onclick="toggleRow(this, ${topicId})"]`);
- const contentRow = document.getElementById(`content-${topicId}`);
- if (row) row.remove();
- if (contentRow) contentRow.remove();
- showToast(`Тема #${topicId} отклонена`, 'error');
- }, 1000);
- }
- // Закрытие toast по клику вне его
- document.addEventListener('click', (event) => {
- if (!event.target.closest('.toast') && !event.target.closest('button[onclick^="dismissToast"]')) {
- document.querySelectorAll('.toast').forEach(toast => {
- const toastId = toast.id.replace('toast-', '');
- dismissToast(toastId);
- });
- }
- });
- </script>
- <script>
- // Управление проигрывателем
- function initPlayer(playerId) {
- const playBtn = document.getElementById(`play-btn-${playerId}`);
- const playIcon = document.getElementById(`play-icon-${playerId}`);
- const pauseIcon = document.getElementById(`pause-icon-${playerId}`);
- const progress = document.getElementById(`progress-${playerId}`);
- const volumeBtn = document.getElementById(`volume-btn-${playerId}`);
- const volumeOnIcon = document.getElementById(`volume-on-icon-${playerId}`);
- const volumeOffIcon = document.getElementById(`volume-off-icon-${playerId}`);
- const volumeSlider = document.getElementById(`volume-${playerId}`);
- const currentTime = document.getElementById(`current-time-${playerId}`);
- const duration = document.getElementById(`duration-${playerId}`);
- let isPlaying = false;
- let isMuted = false;
- let currentVolume = 80;
- // Форматирование времени (секунды в мм:сс)
- function formatTime(seconds) {
- const mins = Math.floor(seconds / 60);
- const secs = Math.floor(seconds % 60);
- return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
- }
- // Установка длительности трека (в реальном приложении будет из аудиофайла)
- duration.textContent = formatTime(204); // 3:24
- // Управление воспроизведением
- playBtn.addEventListener('click', () => {
- isPlaying = !isPlaying;
- if (isPlaying) {
- playIcon.classList.add('hidden');
- pauseIcon.classList.remove('hidden');
- // В реальном приложении: audioElement.play()
- } else {
- playIcon.classList.remove('hidden');
- pauseIcon.classList.add('hidden');
- // В реальном приложении: audioElement.pause()
- }
- });
- // Перемотка трека
- progress.addEventListener('input', (e) => {
- const percent = e.target.value;
- const time = (percent / 100) * 204; // 204 - длительность трека в секундах
- currentTime.textContent = formatTime(time);
- // В реальном приложении: audioElement.currentTime = time
- });
- // Управление громкостью
- volumeSlider.addEventListener('input', (e) => {
- currentVolume = e.target.value;
- if (currentVolume == 0) {
- isMuted = true;
- volumeOnIcon.classList.add('hidden');
- volumeOffIcon.classList.remove('hidden');
- } else {
- isMuted = false;
- volumeOnIcon.classList.remove('hidden');
- volumeOffIcon.classList.add('hidden');
- }
- // В реальном приложении: audioElement.volume = currentVolume / 100
- });
- // Кнопка mute/unmute
- volumeBtn.addEventListener('click', () => {
- isMuted = !isMuted;
- if (isMuted) {
- volumeSlider.value = 0;
- volumeOnIcon.classList.add('hidden');
- volumeOffIcon.classList.remove('hidden');
- // В реальном приложении: audioElement.volume = 0
- } else {
- volumeSlider.value = currentVolume;
- volumeOnIcon.classList.remove('hidden');
- volumeOffIcon.classList.add('hidden');
- // В реальном приложении: audioElement.volume = currentVolume / 100
- }
- });
- // Эмуляция прогресса воспроизведения (в реальном приложении будет из audioElement)
- if (isPlaying) {
- setInterval(() => {
- const currentProgress = parseFloat(progress.value);
- if (currentProgress < 100) {
- progress.value = currentProgress + 0.5;
- const time = (progress.value / 100) * 204;
- currentTime.textContent = formatTime(time);
- } else {
- isPlaying = false;
- playIcon.classList.remove('hidden');
- pauseIcon.classList.add('hidden');
- }
- }, 1000);
- }
- }
- // Инициализация проигрывателей при загрузке страницы
- document.addEventListener('DOMContentLoaded', () => {
- initPlayer(1);
- initPlayer(2);
- });
- </script>
- <script>
- document.addEventListener('DOMContentLoaded', function() {
- const volumeControls = document.querySelectorAll('.volume-control-container');
- volumeControls.forEach(control => {
- const btn = control.querySelector('.volume-btn');
- const slider = control.querySelector('.volume-slider');
- btn.addEventListener('mouseenter', () => {
- slider.style.opacity = '1';
- slider.style.visibility = 'visible';
- slider.style.transform = 'scale(1)';
- });
- control.addEventListener('mouseleave', () => {
- slider.style.opacity = '0';
- slider.style.visibility = 'hidden';
- slider.style.transform = 'scale(0.95)';
- });
- slider.addEventListener('mouseenter', () => {
- slider.style.opacity = '1';
- slider.style.visibility = 'visible';
- slider.style.transform = 'scale(1)';
- });
- });
- });
- </script>
- <script>
- let currentRejectTopicId = null;
- function showRejectModal(topicId) {
- currentRejectTopicId = topicId;
- const modal = document.getElementById('reject-modal');
- modal.classList.remove('hidden');
- setTimeout(() => {
- modal.classList.add('open');
- }, 10);
- }
- function closeRejectModal() {
- const modal = document.getElementById('reject-modal');
- modal.classList.remove('open');
- setTimeout(() => {
- modal.classList.add('hidden');
- currentRejectTopicId = null;
- }, 300);
- }
- function rejectTopic(topicId, event) {
- event.stopPropagation();
- showRejectModal(topicId);
- }
- document.getElementById('confirm-reject-btn').addEventListener('click', function() {
- const spinner = document.getElementById(`reject-spinner-${currentRejectTopicId}`);
- const text = document.getElementById(`reject-text-${currentRejectTopicId}`);
- const btn = document.getElementById(`reject-btn-${currentRejectTopicId}`);
- btn.disabled = true;
- text.classList.add('opacity-0');
- spinner.classList.remove('hidden');
- closeRejectModal();
- setTimeout(() => {
- const row = document.querySelector(`tr[onclick="toggleRow(this, ${currentRejectTopicId})"]`);
- const contentRow = document.getElementById(`content-${currentRejectTopicId}`);
- if (row) row.remove();
- if (contentRow) contentRow.remove();
- showToast(`Тема #${currentRejectTopicId} отклонена`, 'error');
- }, 1000);
- });
- </script>
- </body>
- </html>
- Напиши более точное техническое задание, учитывая всеразличные детали страницы. Допустим, ты не указал, что при нажатии на кнопку одобрить или отклонить, форма должна оставаться статичной, не менять свои размеры, а вместо текста на кнопке должен появлятся спиннер.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement