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> |