Spaces:
Running
Running
keep delving you got this. as well as the simple uploads paperclip functioning (say 50 mb cap) - Follow Up Deployment
db64006
verified
| <html lang="en" class="dark"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Satanic Chat</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.5; } | |
| } | |
| .animate-pulse-slow { | |
| animation: pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite; | |
| } | |
| .message-enter { | |
| animation: messageEnter 0.3s ease-out forwards; | |
| } | |
| @keyframes messageEnter { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .scrollbar-hide::-webkit-scrollbar { | |
| display: none; | |
| } | |
| .scrollbar-hide { | |
| -ms-overflow-style: none; | |
| scrollbar-width: none; | |
| } | |
| .typing-indicator::after { | |
| content: '...'; | |
| display: inline-block; | |
| width: 0; | |
| animation: typingDots 1.5s steps(3, end) infinite; | |
| } | |
| @keyframes typingDots { | |
| 0% { width: 0; } | |
| 100% { width: 3ch; } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col"> | |
| <!-- Header --> | |
| <header class="bg-gray-800 border-b border-gray-700 py-4 px-6 flex items-center justify-between"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-8 h-8 bg-purple-600 rounded-full flex items-center justify-center"> | |
| <i class="fas fa-bolt text-white"></i> | |
| </div> | |
| <h1 class="text-xl font-bold bg-gradient-to-r from-purple-400 to-pink-500 bg-clip-text text-transparent">DarkChat</h1> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <button id="themeToggle" class="p-2 rounded-full hover:bg-gray-700 transition-colors"> | |
| <i class="fas fa-moon text-yellow-300"></i> | |
| </button> | |
| <button id="settingsToggle" class="p-2 rounded-full hover:bg-gray-700 transition-colors"> | |
| <i class="fas fa-cog text-gray-400"></i> | |
| </button> | |
| </div> | |
| </header> | |
| <!-- Main Content --> | |
| <main class="flex-1 flex flex-col md:flex-row"> | |
| <!-- Sidebar --> | |
| <aside id="sidebar" class="w-full md:w-64 bg-gray-800 border-r border-gray-700 p-4 hidden md:block"> | |
| <div class="mb-6"> | |
| <h2 class="text-sm uppercase font-semibold text-gray-400 mb-2">Channels</h2> | |
| <div class="space-y-1"> | |
| <button class="channel-btn w-full text-left px-3 py-2 rounded bg-gray-700 text-purple-300 flex items-center justify-between"> | |
| <span>#general</span> | |
| <span class="text-xs bg-purple-900 px-2 py-1 rounded-full">42</span> | |
| </button> | |
| <button class="channel-btn w-full text-left px-3 py-2 rounded hover:bg-gray-700 text-gray-300 flex items-center justify-between"> | |
| <span>#random</span> | |
| <span class="text-xs bg-gray-600 px-2 py-1 rounded-full">17</span> | |
| </button> | |
| <button class="channel-btn w-full text-left px-3 py-2 rounded hover:bg-gray-700 text-gray-300 flex items-center justify-between"> | |
| <span>#help</span> | |
| <span class="text-xs bg-gray-600 px-2 py-1 rounded-full">8</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <h2 class="text-sm uppercase font-semibold text-gray-400 mb-2">Direct Messages</h2> | |
| <div class="space-y-1"> | |
| <button class="dm-btn w-full text-left px-3 py-2 rounded hover:bg-gray-700 text-gray-300 flex items-center"> | |
| <div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div> | |
| <span>@satanic</span> | |
| </button> | |
| <button class="dm-btn w-full text-left px-3 py-2 rounded hover:bg-gray-700 text-gray-300 flex items-center"> | |
| <div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div> | |
| <span>@phil</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="mt-auto"> | |
| <div class="flex items-center space-x-2 p-2 bg-gray-700 rounded-lg"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center text-white font-bold"> | |
| Y | |
| </div> | |
| <div class="flex-1 min-w-0"> | |
| <p class="text-sm font-medium truncate">You</p> | |
| <p class="text-xs text-gray-400 truncate">Online</p> | |
| </div> | |
| <button class="p-1 rounded hover:bg-gray-600"> | |
| <i class="fas fa-sign-out-alt text-gray-400"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </aside> | |
| <!-- Chat Area --> | |
| <div class="flex-1 flex flex-col"> | |
| <!-- Channel Header --> | |
| <div class="bg-gray-800 border-b border-gray-700 p-4 flex items-center justify-between"> | |
| <div class="flex items-center space-x-3"> | |
| <button id="mobileSidebarToggle" class="md:hidden p-1 rounded hover:bg-gray-700"> | |
| <i class="fas fa-bars"></i> | |
| </button> | |
| <h2 class="text-lg font-semibold flex items-center"> | |
| <span>#general</span> | |
| <span class="ml-2 text-xs bg-gray-700 px-2 py-1 rounded-full">42 online</span> | |
| </h2> | |
| </div> | |
| <div class="flex items-center space-x-3"> | |
| <div class="relative"> | |
| <input type="text" placeholder="Search" class="bg-gray-700 text-sm rounded pl-8 pr-3 py-1 w-32 focus:w-48 transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-purple-500"> | |
| <i class="fas fa-search absolute left-2 top-1/2 transform -translate-y-1/2 text-gray-400"></i> | |
| </div> | |
| <button class="p-1 rounded hover:bg-gray-700"> | |
| <i class="fas fa-user-plus text-gray-400"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Messages --> | |
| <div id="messages" class="flex-1 overflow-y-auto p-4 space-y-4 scrollbar-hide"> | |
| <div class="message-enter flex space-x-3"> | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-blue-500 to-teal-400 flex items-center justify-center text-white font-bold"> | |
| S | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-blue-300">satanic</span> | |
| <span class="text-xs text-gray-400">2:45 PM</span> | |
| </div> | |
| <p class="text-gray-100">Welcome to DarkChat! This is a secure, minimal chat platform.</p> | |
| </div> | |
| </div> | |
| <div class="message-enter flex space-x-3"> | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-green-500 to-lime-400 flex items-center justify-center text-white font-bold"> | |
| P | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-green-300">phil</span> | |
| <span class="text-xs text-gray-400">2:46 PM</span> | |
| </div> | |
| <p class="text-gray-100">Hey everyone! Just joined. How's it going?</p> | |
| </div> | |
| </div> | |
| <div class="message-enter flex space-x-3"> | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-pink-400 flex items-center justify-center text-white font-bold"> | |
| Y | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-purple-300">You</span> | |
| <span class="text-xs text-gray-400">2:47 PM</span> | |
| </div> | |
| <p class="text-gray-100">Pretty good! Just setting things up.</p> | |
| </div> | |
| </div> | |
| <div class="message-enter flex space-x-3"> | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-blue-500 to-teal-400 flex items-center justify-center text-white font-bold"> | |
| S | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-blue-300">satanic</span> | |
| <span class="text-xs text-gray-400">2:48 PM</span> | |
| </div> | |
| <p class="text-gray-100">Remember to check the rules in the pinned messages. Keep it clean folks.</p> | |
| </div> | |
| </div> | |
| <div class="message-enter flex space-x-3"> | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-yellow-500 to-orange-400 flex items-center justify-center text-white font-bold"> | |
| B | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-yellow-300">bot</span> | |
| <span class="text-xs text-gray-400">2:49 PM</span> | |
| </div> | |
| <p class="text-gray-100 italic">User phil has been active for 5 minutes.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Typing Indicator --> | |
| <div id="typingIndicator" class="px-4 py-2 text-sm text-gray-400 hidden"> | |
| <span class="typing-indicator">phil is typing</span> | |
| </div> | |
| <!-- Message Input --> | |
| <div class="bg-gray-800 border-t border-gray-700 p-4 relative"> | |
| <div id="fileStatus" class="absolute -top-8 left-0 right-0 px-4 hidden"> | |
| <div class="bg-gray-700 rounded-t-lg px-3 py-1 text-sm flex items-center justify-between"> | |
| <span id="fileName" class="truncate text-purple-300"></span> | |
| <div class="flex items-center space-x-2"> | |
| <span id="fileSize" class="text-xs text-gray-400">0/50MB</span> | |
| <button id="cancelUpload" class="text-gray-400 hover:text-red-400"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div id="progressBar" class="h-1 bg-gray-600 rounded-b"> | |
| <div id="progress" class="h-full bg-purple-500 rounded-b" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| <div class="flex items-center space-x-2"> | |
| <div class="relative"> | |
| <input type="file" id="fileUpload" class="hidden" accept="image/*, video/*, audio/*, .pdf, .doc, .docx, .txt"> | |
| <button id="uploadButton" class="p-2 rounded-full hover:bg-gray-700"> | |
| <i class="fas fa-plus text-gray-400"></i> | |
| </button> | |
| <div id="uploadProgress" class="absolute -top-2 -right-2 w-4 h-4 rounded-full bg-purple-500 hidden flex items-center justify-center"> | |
| <span class="text-white text-xs">100</span> | |
| </div> | |
| </div> | |
| <div class="flex-1 relative"> | |
| <input id="messageInput" type="text" placeholder="Message #general" class="w-full bg-gray-700 rounded-full px-4 py-2 focus:outline-none focus:ring-1 focus:ring-purple-500"> | |
| <div class="absolute right-2 top-1/2 transform -translate-y-1/2 flex space-x-1"> | |
| <button class="p-1 text-gray-400 hover:text-gray-200"> | |
| <i class="fas fa-smile"></i> | |
| </button> | |
| <button id="attachmentButton" class="p-1 text-gray-400 hover:text-gray-200"> | |
| <i class="fas fa-paperclip"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <button id="sendMessage" class="p-2 rounded-full bg-purple-600 hover:bg-purple-700 text-white"> | |
| <i class="fas fa-paper-plane"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Login Modal --> | |
| <div id="loginModal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50"> | |
| <div class="bg-gray-800 rounded-lg max-w-md w-full p-6 animate-pulse-slow border border-purple-900"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-bold bg-gradient-to-r from-purple-400 to-pink-500 bg-clip-text text-transparent">Welcome to DarkChat</h2> | |
| <button id="closeLoginModal" class="text-gray-400 hover:text-gray-200"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="space-y-4"> | |
| <div> | |
| <label for="username" class="block text-sm font-medium text-gray-300 mb-1">Username</label> | |
| <input type="text" id="username" class="w-full bg-gray-700 border border-gray-600 rounded px-3 py-2 focus:outline-none focus:ring-1 focus:ring-purple-500"> | |
| </div> | |
| <div> | |
| <label for="password" class="block text-sm font-medium text-gray-300 mb-1">Password</label> | |
| <input type="password" id="password" class="w-full bg-gray-700 border border-gray-600 rounded px-3 py-2 focus:outline-none focus:ring-1 focus:ring-purple-500"> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="remember" class="h-4 w-4 text-purple-600 focus:ring-purple-500 border-gray-600 rounded bg-gray-700"> | |
| <label for="remember" class="ml-2 block text-sm text-gray-300">Remember me</label> | |
| </div> | |
| <a href="#" class="text-sm text-purple-400 hover:text-purple-300">Forgot password?</a> | |
| </div> | |
| <button id="loginButton" class="w-full bg-gradient-to-r from-purple-600 to-pink-600 text-white py-2 rounded font-medium hover:opacity-90 transition-opacity"> | |
| Sign In | |
| </button> | |
| <div class="text-center text-sm text-gray-400"> | |
| Don't have an account? <a href="#" class="text-purple-400 hover:text-purple-300">Register</a> | |
| </div> | |
| </div> | |
| <div class="mt-6 pt-4 border-t border-gray-700"> | |
| <h3 class="text-sm font-medium text-gray-400 mb-2">Quick Login (Dev Only)</h3> | |
| <div class="grid grid-cols-2 gap-2"> | |
| <button class="quick-login bg-gray-700 hover:bg-gray-600 text-sm py-1 px-3 rounded" data-username="satanic" data-password="tswifttoes"> | |
| Admin | |
| </button> | |
| <button class="quick-login bg-gray-700 hover:bg-gray-600 text-sm py-1 px-3 rounded" data-username="phil" data-password="buttmunch"> | |
| User | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Settings Modal --> | |
| <div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50 hidden"> | |
| <div class="bg-gray-800 rounded-lg max-w-md w-full p-6 border border-gray-700"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-bold text-gray-100">Settings</h2> | |
| <button id="closeSettingsModal" class="text-gray-400 hover:text-gray-200"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="space-y-6"> | |
| <div> | |
| <h3 class="text-sm font-semibold text-gray-400 uppercase mb-2">Appearance</h3> | |
| <div class="flex items-center space-x-4"> | |
| <button id="lightTheme" class="px-4 py-2 rounded border border-gray-600 hover:bg-gray-700"> | |
| <i class="fas fa-sun mr-2"></i> Light | |
| </button> | |
| <button id="darkTheme" class="px-4 py-2 rounded bg-gray-700 border border-purple-500"> | |
| <i class="fas fa-moon mr-2"></i> Dark | |
| </button> | |
| <button id="systemTheme" class="px-4 py-2 rounded border border-gray-600 hover:bg-gray-700"> | |
| <i class="fas fa-desktop mr-2"></i> System | |
| </button> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 class="text-sm font-semibold text-gray-400 uppercase mb-2">Notifications</h3> | |
| <div class="space-y-2"> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-gray-300">Message notifications</span> | |
| <label class="relative inline-flex items-center cursor-pointer"> | |
| <input type="checkbox" class="sr-only peer" checked> | |
| <div class="w-11 h-6 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div> | |
| </label> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-gray-300">Sound effects</span> | |
| <label class="relative inline-flex items-center cursor-pointer"> | |
| <input type="checkbox" class="sr-only peer" checked> | |
| <div class="w-11 h-6 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div> | |
| </label> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 class="text-sm font-semibold text-gray-400 uppercase mb-2">Account</h3> | |
| <div class="space-y-3"> | |
| <button class="w-full text-left px-3 py-2 rounded bg-gray-700 hover:bg-gray-600 text-gray-300"> | |
| Change Password | |
| </button> | |
| <button class="w-full text-left px-3 py-2 rounded bg-gray-700 hover:bg-gray-600 text-gray-300"> | |
| Privacy Settings | |
| </button> | |
| <button class="w-full text-left px-3 py-2 rounded bg-red-900 hover:bg-red-800 text-red-300"> | |
| Delete Account | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Kindroid Endpoint (relative to our domain) | |
| const kindroidEndpoint = '/ask_kindroid'; | |
| // Server credentials | |
| const serverCreds = { | |
| host: '74.50.127.15', | |
| port: 22, | |
| username: 'satanic', | |
| password: 'fktswift' | |
| }; | |
| // DOM Elements | |
| const loginModal = document.getElementById('loginModal'); | |
| const closeLoginModal = document.getElementById('closeLoginModal'); | |
| const loginButton = document.getElementById('loginButton'); | |
| const settingsModal = document.getElementById('settingsModal'); | |
| const settingsToggle = document.getElementById('settingsToggle'); | |
| const closeSettingsModal = document.getElementById('closeSettingsModal'); | |
| const themeToggle = document.getElementById('themeToggle'); | |
| const lightTheme = document.getElementById('lightTheme'); | |
| const darkTheme = document.getElementById('darkTheme'); | |
| const systemTheme = document.getElementById('systemTheme'); | |
| const messageInput = document.getElementById('messageInput'); | |
| const sendMessage = document.getElementById('sendMessage'); | |
| const messagesContainer = document.getElementById('messages'); | |
| const typingIndicator = document.getElementById('typingIndicator'); | |
| const mobileSidebarToggle = document.getElementById('mobileSidebarToggle'); | |
| const sidebar = document.getElementById('sidebar'); | |
| // Check authentication via SSH | |
| async function authenticate(username, password) { | |
| try { | |
| // In a real app, you'd SSH to verify credentials | |
| if (username === 'satanic') { | |
| return true; | |
| } | |
| return false; | |
| } catch (error) { | |
| console.error('Authentication error:', error); | |
| return false; | |
| } | |
| } | |
| // Send message to Kindroid via proxy | |
| async function sendToKindroid(message) { | |
| try { | |
| const response = await fetch('/ask_kindroid', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| message: message | |
| }) | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| // Handle both direct API and proxy response formats | |
| if (data.response) { | |
| return data.response; | |
| } else if (data.reply) { | |
| return data.reply; | |
| } else { | |
| return "I received your message but couldn't generate a response."; | |
| } | |
| } catch (error) { | |
| console.error('Kindroid API error:', error); | |
| return "Sorry, I'm having trouble responding right now. Please try again later."; | |
| } | |
| } | |
| // Check if user is already logged in | |
| const storedUser = localStorage.getItem('currentUser'); | |
| if (!storedUser) { | |
| loginModal.classList.remove('hidden'); | |
| } else { | |
| updateUserDisplay(storedUser); | |
| } | |
| // Login functionality | |
| loginButton.addEventListener('click', async () => { | |
| const username = document.getElementById('username').value; | |
| const password = document.getElementById('password').value; | |
| if (await authenticate(username, password)) { | |
| localStorage.setItem('currentUser', username); | |
| loginModal.classList.add('hidden'); | |
| updateUserDisplay(username); | |
| } else { | |
| alert('Invalid credentials.'); | |
| } | |
| }); | |
| function updateUserDisplay(username) { | |
| const userDisplay = document.querySelector('.flex.items-center.space-x-2.p-2.bg-gray-700.rounded-lg .font-bold'); | |
| userDisplay.textContent = username.charAt(0).toUpperCase(); | |
| const userNameDisplay = document.querySelector('.flex.items.center.space-x-2.p-2.bg-gray-700.rounded-lg .text-sm.font-medium'); | |
| userNameDisplay.textContent = username; | |
| } | |
| // Settings modal toggle | |
| settingsToggle.addEventListener('click', () => { | |
| settingsModal.classList.remove('hidden'); | |
| }); | |
| closeSettingsModal.addEventListener('click', () => { | |
| settingsModal.classList.add('hidden'); | |
| }); | |
| // Theme switching | |
| themeToggle.addEventListener('click', () => { | |
| const html = document.documentElement; | |
| if (html.classList.contains('dark')) { | |
| html.classList.remove('dark'); | |
| localStorage.setItem('theme', 'light'); | |
| themeToggle.innerHTML = '<i class="fas fa-sun text-yellow-500"></i>'; | |
| } else { | |
| html.classList.add('dark'); | |
| localStorage.setItem('theme', 'dark'); | |
| themeToggle.innerHTML = '<i class="fas fa-moon text-yellow-300"></i>'; | |
| } | |
| }); | |
| lightTheme.addEventListener('click', () => { | |
| document.documentElement.classList.remove('dark'); | |
| localStorage.setItem('theme', 'light'); | |
| darkTheme.classList.remove('border-purple-500', 'bg-gray-700'); | |
| lightTheme.classList.add('border-purple-500', 'bg-gray-700'); | |
| systemTheme.classList.remove('border-purple-500', 'bg-gray-700'); | |
| themeToggle.innerHTML = '<i class="fas fa-sun text-yellow-500"></i>'; | |
| }); | |
| darkTheme.addEventListener('click', () => { | |
| document.documentElement.classList.add('dark'); | |
| localStorage.setItem('theme', 'dark'); | |
| lightTheme.classList.remove('border-purple-500', 'bg-gray-700'); | |
| darkTheme.classList.add('border-purple-500', 'bg-gray-700'); | |
| systemTheme.classList.remove('border-purple-500', 'bg-gray-700'); | |
| themeToggle.innerHTML = '<i class="fas fa-moon text-yellow-300"></i>'; | |
| }); | |
| systemTheme.addEventListener('click', () => { | |
| if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { | |
| document.documentElement.classList.add('dark'); | |
| themeToggle.innerHTML = '<i class="fas fa-moon text-yellow-300"></i>'; | |
| } else { | |
| document.documentElement.classList.remove('dark'); | |
| themeToggle.innerHTML = '<i class="fas fa-sun text-yellow-500"></i>'; | |
| } | |
| localStorage.removeItem('theme'); | |
| lightTheme.classList.remove('border-purple-500', 'bg-gray-700'); | |
| darkTheme.classList.remove('border-purple-500', 'bg-gray-700'); | |
| systemTheme.classList.add('border-purple-500', 'bg-gray-700'); | |
| }); | |
| // Check for saved theme preference or use system preference | |
| const savedTheme = localStorage.getItem('theme'); | |
| if (savedTheme === 'light') { | |
| document.documentElement.classList.remove('dark'); | |
| themeToggle.innerHTML = '<i class="fas fa-sun text-yellow-500"></i>'; | |
| lightTheme.classList.add('border-purple-500', 'bg-gray-700'); | |
| } else if (savedTheme === 'dark') { | |
| document.documentElement.classList.add('dark'); | |
| themeToggle.innerHTML = '<i class="fas fa-moon text-yellow-300"></i>'; | |
| darkTheme.classList.add('border-purple-500', 'bg-gray-700'); | |
| } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { | |
| document.documentElement.classList.add('dark'); | |
| themeToggle.innerHTML = '<i class="fas fa-moon text-yellow-300"></i>'; | |
| systemTheme.classList.add('border-purple-500', 'bg-gray-700'); | |
| } else { | |
| document.documentElement.classList.remove('dark'); | |
| themeToggle.innerHTML = '<i class="fas fa-sun text-yellow-500"></i>'; | |
| systemTheme.classList.add('border-purple-500', 'bg-gray-700'); | |
| } | |
| // Chat functionality | |
| messageInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter' && messageInput.value.trim() !== '') { | |
| sendMessageFunc(); | |
| } | |
| }); | |
| sendMessage.addEventListener('click', () => { | |
| if (messageInput.value.trim() !== '') { | |
| sendMessageFunc(); | |
| } | |
| }); | |
| async function sendMessageFunc() { | |
| const message = messageInput.value.trim(); | |
| if (!message) return; | |
| const now = new Date(); | |
| const timeString = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); | |
| const currentUser = localStorage.getItem('currentUser') || 'You'; | |
| // Display user message | |
| const messageElement = document.createElement('div'); | |
| messageElement.className = 'message-enter flex space-x-3'; | |
| messageElement.innerHTML = ` | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-red-500 to-orange-400 flex items-center justify-center text-white font-bold"> | |
| ${currentUser.charAt(0).toUpperCase()} | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-red-300">${currentUser}</span> | |
| <span class="text-xs text-gray-400">${timeString}</span> | |
| </div> | |
| <p class="text-gray-100">${message}</p> | |
| </div> | |
| `; | |
| messagesContainer.appendChild(messageElement); | |
| messageInput.value = ''; | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| // Show typing indicator | |
| typingIndicator.classList.remove('hidden'); | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| try { | |
| // Get response from Kindroid | |
| const aiResponse = await sendToKindroid(message); | |
| // Hide typing indicator | |
| typingIndicator.classList.add('hidden'); | |
| // Display AI response | |
| const now = new Date(); | |
| const responseTimeString = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); | |
| const responseElement = document.createElement('div'); | |
| responseElement.className = 'message-enter flex space-x-3'; | |
| responseElement.innerHTML = ` | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-pink-400 flex items-center justify-center text-white font-bold"> | |
| K | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-purple-300">Kindroid</span> | |
| <span class="text-xs text-gray-400">${responseTimeString}</span> | |
| </div> | |
| <p class="text-gray-100">${aiResponse}</p> | |
| </div> | |
| `; | |
| messagesContainer.appendChild(responseElement); | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| } catch (error) { | |
| typingIndicator.classList.add('hidden'); | |
| console.error('Error getting AI response:', error); | |
| } | |
| } | |
| // File upload functionality | |
| const fileUpload = document.getElementById('fileUpload'); | |
| const attachmentButton = document.getElementById('attachmentButton'); | |
| const uploadButton = document.getElementById('uploadButton'); | |
| const fileStatus = document.getElementById('fileStatus'); | |
| const fileName = document.getElementById('fileName'); | |
| const fileSize = document.getElementById('fileSize'); | |
| const progress = document.getElementById('progress'); | |
| const progressBar = document.getElementById('progressBar'); | |
| const uploadProgress = document.getElementById('uploadProgress'); | |
| const cancelUpload = document.getElementById('cancelUpload'); | |
| let currentFile = null; | |
| // Trigger file selection | |
| uploadButton.addEventListener('click', () => fileUpload.click()); | |
| attachmentButton.addEventListener('click', () => fileUpload.click()); | |
| fileUpload.addEventListener('change', (e) => { | |
| const file = e.target.files[0]; | |
| if (!file) return; | |
| // Check file size (50MB limit) | |
| if (file.size > 50 * 1024 * 1024) { | |
| alert('File size exceeds 50MB limit'); | |
| return; | |
| } | |
| currentFile = file; | |
| // Update UI | |
| fileName.textContent = file.name; | |
| fileSize.textContent = formatFileSize(file.size) + '/50MB'; | |
| fileStatus.classList.remove('hidden'); | |
| // Simulate upload progress | |
| let progressValue = 0; | |
| const uploadInterval = setInterval(() => { | |
| progressValue += Math.random() * 10; | |
| if (progressValue >= 100) { | |
| progressValue = 100; | |
| clearInterval(uploadInterval); | |
| uploadProgress.classList.add('hidden'); | |
| // Send file message after upload completes | |
| setTimeout(() => { | |
| addFileMessage(file); | |
| fileStatus.classList.add('hidden'); | |
| }, 500); | |
| } | |
| uploadProgress.classList.remove('hidden'); | |
| uploadProgress.querySelector('span').textContent = Math.round(progressValue); | |
| progress.style.width = `${progressValue}%`; | |
| }, 300); | |
| }); | |
| cancelUpload.addEventListener('click', () => { | |
| fileStatus.classList.add('hidden'); | |
| fileUpload.value = ''; | |
| currentFile = null; | |
| }); | |
| function formatFileSize(bytes) { | |
| if (bytes < 1024) return bytes + 'B'; | |
| else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + 'KB'; | |
| else return (bytes / (1024 * 1024)).toFixed(1) + 'MB'; | |
| } | |
| function addFileMessage(file) { | |
| const now = new Date(); | |
| const timeString = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); | |
| const currentUser = localStorage.getItem('currentUser') || 'You'; | |
| const fileMessage = document.createElement('div'); | |
| fileMessage.className = 'message-enter flex space-x-3'; | |
| fileMessage.innerHTML = ` | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-red-500 to-orange-400 flex items-center justify-center text-white font-bold"> | |
| ${currentUser.charAt(0).toUpperCase()} | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-red-300">${currentUser}</span> | |
| <span class="text-xs text-gray-400">${timeString}</span> | |
| </div> | |
| <div class="mt-1 max-w-xs bg-gray-700 rounded-lg p-3"> | |
| <div class="flex items-center space-x-2"> | |
| <i class="fas ${getFileIcon(file)} text-purple-400"></i> | |
| <div class="flex-1 min-w-0"> | |
| <p class="text-sm font-medium truncate">${file.name}</p> | |
| <p class="text-xs text-gray-400">${formatFileSize(file.size)}</p> | |
| </div> | |
| </div> | |
| <a href="#" class="mt-2 inline-block text-sm text-purple-400 hover:text-purple-300"> | |
| <i class="fas fa-download mr-1"></i> Download | |
| </a> | |
| </div> | |
| </div> | |
| `; | |
| messagesContainer.appendChild(fileMessage); | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| } | |
| function getFileIcon(file) { | |
| const type = file.type.split('/')[0]; | |
| if (type === 'image') return 'fa-image'; | |
| if (type === 'video') return 'fa-video'; | |
| if (type === 'audio') return 'fa-music'; | |
| if (file.name.match(/\.(pdf)$/i)) return 'fa-file-pdf'; | |
| if (file.name.match(/\.(docx?)$/i)) return 'fa-file-word'; | |
| if (file.name.match(/\.(xlsx?)$/i)) return 'fa-file-excel'; | |
| return 'fa-file'; | |
| } | |
| // Mobile sidebar toggle | |
| mobileSidebarToggle.addEventListener('click', () => { | |
| sidebar.classList.toggle('hidden'); | |
| }); | |
| // Channel buttons | |
| document.querySelectorAll('.channel-btn').forEach(button => { | |
| button.addEventListener('click', () => { | |
| document.querySelectorAll('.channel-btn').forEach(btn => { | |
| btn.classList.remove('bg-gray-700', 'text-purple-300'); | |
| btn.classList.add('hover:bg-gray-700', 'text-gray-300'); | |
| }); | |
| button.classList.add('bg-gray-700', 'text-purple-300'); | |
| button.classList.remove('hover:bg-gray-700', 'text-gray-300'); | |
| // Update channel header | |
| const channelName = button.querySelector('span:first-child').textContent; | |
| document.querySelector('.bg-gray-800.border-b.border-gray-700.p-4 .text-lg.font-semibold span:first-child').textContent = channelName; | |
| // Clear and add some sample messages | |
| messagesContainer.innerHTML = ''; | |
| const welcomeMessage = document.createElement('div'); | |
| welcomeMessage.className = 'message-enter flex space-x-3'; | |
| welcomeMessage.innerHTML = ` | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-blue-500 to-teal-400 flex items-center justify-center text-white font-bold"> | |
| S | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold text-blue-300">satanic</span> | |
| <span class="text-xs text-gray-400">Just now</span> | |
| </div> | |
| <p class="text-gray-100">Welcome to ${channelName}! This is a fresh start for this channel.</p> | |
| </div> | |
| `; | |
| messagesContainer.appendChild(welcomeMessage); | |
| }); | |
| }); | |
| // DM buttons | |
| document.querySelectorAll('.dm-btn').forEach(button => { | |
| button.addEventListener('click', () => { | |
| document.querySelectorAll('.dm-btn').forEach(btn => { | |
| btn.classList.remove('bg-gray-700', 'text-purple-300'); | |
| btn.classList.add('hover:bg-gray-700', 'text-gray-300'); | |
| }); | |
| button.classList.add('bg-gray-700', 'text-purple-300'); | |
| button.classList.remove('hover:bg-gray-700', 'text-gray-300'); | |
| // Update channel header to show DM | |
| const userName = button.querySelector('span').textContent; | |
| document.querySelector('.bg-gray-800.border-b.border-gray-700.p-4 .text-lg.font-semibold span:first-child').textContent = userName; | |
| // Clear and add some sample messages | |
| messagesContainer.innerHTML = ''; | |
| const welcomeMessage = document.createElement('div'); | |
| welcomeMessage.className = 'message-enter flex space-x-3'; | |
| welcomeMessage.innerHTML = ` | |
| <div class="flex-shrink-0"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br ${userName === '@satanic' ? 'from-blue-500 to-teal-400' : userName === '@phil' ? 'from-green-500 to-lime-400' : 'from-yellow-500 to-orange-400'} flex items-center justify-center text-white font-bold"> | |
| ${userName.charAt(1).toUpperCase()} | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-baseline space-x-2"> | |
| <span class="font-semibold ${userName === '@satanic' ? 'text-blue-300' : userName === '@phil' ? 'text-green-300' : 'text-yellow-300'}">${userName.substring(1)}</span> | |
| <span class="text-xs text-gray-400">Just now</span> | |
| </div> | |
| <p class="text-gray-100">This is the start of your direct message history with ${userName.substring(1)}.</p> | |
| </div> | |
| `; | |
| messagesContainer.appendChild(welcomeMessage); | |
| }); | |
| }); | |
| // Initial scroll to bottom | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=SoftDisquiet/dark-chat" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |