Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Encode/Decode Tool</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> | |
.gradient-bg { | |
background: linear-gradient(135deg, #6b73ff 0%, #000dff 100%); | |
} | |
.text-gradient { | |
background: linear-gradient(90deg, #ff8a00, #e52e71); | |
-webkit-background-clip: text; | |
background-clip: text; | |
color: transparent; | |
} | |
.result-box { | |
min-height: 150px; | |
transition: all 0.3s ease; | |
} | |
.result-box.expanded { | |
min-height: 250px; | |
} | |
.tab-active { | |
border-bottom: 3px solid #4f46e5; | |
color: #4f46e5; | |
font-weight: 600; | |
} | |
.copy-btn { | |
transition: all 0.2s ease; | |
} | |
.copy-btn:hover { | |
transform: scale(1.05); | |
} | |
.copy-btn:active { | |
transform: scale(0.95); | |
} | |
.tooltip { | |
position: relative; | |
display: inline-block; | |
} | |
.tooltip .tooltiptext { | |
visibility: hidden; | |
width: 120px; | |
background-color: #555; | |
color: #fff; | |
text-align: center; | |
border-radius: 6px; | |
padding: 5px; | |
position: absolute; | |
z-index: 1; | |
bottom: 125%; | |
left: 50%; | |
margin-left: -60px; | |
opacity: 0; | |
transition: opacity 0.3s; | |
} | |
.tooltip:hover .tooltiptext { | |
visibility: visible; | |
opacity: 1; | |
} | |
.blink { | |
animation: blink-animation 1s steps(5, start) infinite; | |
} | |
@keyframes blink-animation { | |
to { | |
visibility: hidden; | |
} | |
} | |
</style> | |
</head> | |
<body class="bg-gray-100 min-h-screen"> | |
<div class="gradient-bg text-white py-6 shadow-lg"> | |
<div class="container mx-auto px-4"> | |
<div class="flex items-center justify-between"> | |
<div class="flex items-center space-x-3"> | |
<i class="fas fa-lock text-3xl"></i> | |
<h1 class="text-2xl md:text-3xl font-bold">Code<span class="text-yellow-300">Cipher</span></h1> | |
</div> | |
<div class="hidden md:flex space-x-4"> | |
<a href="#" class="hover:text-yellow-200 transition">Home</a> | |
<a href="#" class="hover:text-yellow-200 transition">About</a> | |
<a href="#" class="hover:text-yellow-200 transition">Tools</a> | |
</div> | |
<button class="md:hidden text-xl"> | |
<i class="fas fa-bars"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
<div class="container mx-auto px-4 py-8 max-w-6xl"> | |
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> | |
<div class="p-6"> | |
<h2 class="text-2xl font-bold text-gray-800 mb-2">Encoding & Decoding Tool</h2> | |
<p class="text-gray-600 mb-6">Convert between different encoding formats quickly and securely</p> | |
<div class="flex space-x-4 border-b mb-6"> | |
<button id="encode-tab" class="tab-active px-4 py-2">Encode</button> | |
<button id="decode-tab" class="px-4 py-2 text-gray-600 hover:text-gray-800">Decode</button> | |
</div> | |
<div class="mb-6"> | |
<label for="method" class="block text-sm font-medium text-gray-700 mb-2">Encoding Method</label> | |
<select id="method" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> | |
<option value="base64">Base64</option> | |
<option value="base32">Base32</option> | |
<option value="url">URL Encoding</option> | |
<option value="html">HTML Entities</option> | |
<option value="hex">Hexadecimal</option> | |
<option value="binary">Binary</option> | |
<option value="rot13">ROT13</option> | |
</select> | |
</div> | |
<div class="mb-6"> | |
<label for="input-text" class="block text-sm font-medium text-gray-700 mb-2">Input Text</label> | |
<div class="relative"> | |
<textarea id="input-text" rows="5" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="Enter text to encode/decode..."></textarea> | |
<div class="absolute right-2 bottom-2 flex space-x-1"> | |
<button id="sample-btn" class="tooltip bg-gray-100 text-gray-600 p-1 rounded hover:bg-gray-200"> | |
<i class="fas fa-lightbulb"></i> | |
<span class="tooltiptext">Insert Sample</span> | |
</button> | |
<button id="clear-input-btn" class="tooltip bg-gray-100 text-gray-600 p-1 rounded hover:bg-gray-200"> | |
<i class="fas fa-times"></i> | |
<span class="tooltiptext">Clear Input</span> | |
</button> | |
</div> | |
</div> | |
</div> | |
<div class="flex space-x-4 mb-6"> | |
<button id="process-btn" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white py-3 px-6 rounded-lg font-medium transition flex items-center justify-center"> | |
<i class="fas fa-cog mr-2"></i> Process | |
</button> | |
<button id="clear-btn" class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 py-3 px-6 rounded-lg font-medium transition flex items-center justify-center"> | |
<i class="fas fa-trash-alt mr-2"></i> Clear All | |
</button> | |
</div> | |
<div class="bg-gray-50 p-4 rounded-lg result-box" id="result-container"> | |
<div class="flex justify-between items-center mb-3"> | |
<h3 class="font-medium text-gray-700">Result</h3> | |
<div class="flex space-x-2"> | |
<button id="download-btn" class="tooltip copy-btn bg-green-100 text-green-600 p-2 rounded-lg hover:bg-green-200"> | |
<i class="fas fa-download"></i> | |
<span class="tooltiptext">Download Result</span> | |
</button> | |
<button id="copy-btn" class="tooltip copy-btn bg-blue-100 text-blue-600 p-2 rounded-lg hover:bg-blue-200"> | |
<i class="fas fa-copy"></i> | |
<span class="tooltiptext">Copy to Clipboard</span> | |
</button> | |
<button id="expand-btn" class="tooltip copy-btn bg-gray-200 text-gray-600 p-2 rounded-lg hover:bg-gray-300"> | |
<i class="fas fa-expand"></i> | |
<span class="tooltiptext">Expand/Collapse</span> | |
</button> | |
</div> | |
</div> | |
<div id="result" class="text-gray-800 whitespace-pre-wrap break-words"></div> | |
<div id="char-count" class="text-xs text-gray-500 mt-2 text-right"></div> | |
</div> | |
</div> | |
<div class="bg-gray-50 px-6 py-4 border-t"> | |
<h3 class="font-medium text-gray-700 mb-2">About Encoding Methods</h3> | |
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 text-sm text-gray-600"> | |
<div class="bg-white p-3 rounded-lg shadow-sm"> | |
<h4 class="font-medium text-blue-600 mb-1">Base64</h4> | |
<p>Encodes binary data to ASCII characters using 64 different characters (A-Z, a-z, 0-9, +, /). Commonly used for email attachments and embedding images in HTML.</p> | |
</div> | |
<div class="bg-white p-3 rounded-lg shadow-sm"> | |
<h4 class="font-medium text-blue-600 mb-1">Base32</h4> | |
<p>Similar to Base64 but uses 32 different characters (A-Z, 2-7). More human-readable and case-insensitive, often used in OTP tokens and file hashes.</p> | |
</div> | |
<div class="bg-white p-3 rounded-lg shadow-sm"> | |
<h4 class="font-medium text-blue-600 mb-1">URL Encoding</h4> | |
<p>Replaces unsafe ASCII characters with "%" followed by hexadecimal digits. Used in URLs to encode special characters.</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="mt-8 bg-white rounded-xl shadow-lg overflow-hidden"> | |
<div class="p-6"> | |
<div class="flex justify-between items-center mb-4"> | |
<h2 class="text-xl font-bold text-gray-800">Recent Conversions</h2> | |
<button id="clear-history-btn" class="text-sm text-red-500 hover:text-red-700 flex items-center"> | |
<i class="fas fa-trash-alt mr-1"></i> Clear History | |
</button> | |
</div> | |
<div class="overflow-x-auto"> | |
<table class="min-w-full divide-y divide-gray-200"> | |
<thead class="bg-gray-50"> | |
<tr> | |
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Method</th> | |
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Input</th> | |
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Result</th> | |
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th> | |
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th> | |
</tr> | |
</thead> | |
<tbody class="bg-white divide-y divide-gray-200" id="history-table"> | |
<!-- History items will be added here --> | |
</tbody> | |
</table> | |
</div> | |
<div class="mt-4 text-center text-sm text-gray-500" id="empty-history"> | |
No recent conversions. Start encoding/decoding to see history here. | |
</div> | |
</div> | |
</div> | |
</div> | |
<footer class="bg-gray-800 text-white py-8 mt-12"> | |
<div class="container mx-auto px-4"> | |
<div class="grid grid-cols-1 md:grid-cols-3 gap-8"> | |
<div> | |
<h3 class="text-xl font-bold mb-4">CodeCipher</h3> | |
<p class="text-gray-400">A powerful tool for all your encoding and decoding needs. Fast, secure, and easy to use.</p> | |
</div> | |
<div> | |
<h3 class="text-xl font-bold mb-4">Quick Links</h3> | |
<ul class="space-y-2"> | |
<li><a href="#" class="text-gray-400 hover:text-white transition">Home</a></li> | |
<li><a href="#" class="text-gray-400 hover:text-white transition">About</a></li> | |
<li><a href="#" class="text-gray-400 hover:text-white transition">Privacy Policy</a></li> | |
</ul> | |
</div> | |
<div> | |
<h3 class="text-xl font-bold mb-4">Connect</h3> | |
<div class="flex space-x-4"> | |
<a href="#" class="text-gray-400 hover:text-white transition text-xl"><i class="fab fa-twitter"></i></a> | |
<a href="#" class="text-gray-400 hover:text-white transition text-xl"><i class="fab fa-github"></i></a> | |
<a href="#" class="text-gray-400 hover:text-white transition text-xl"><i class="fab fa-linkedin"></i></a> | |
</div> | |
</div> | |
</div> | |
<div class="border-t border-gray-700 mt-8 pt-6 text-center text-gray-400"> | |
<p>© 2023 CodeCipher. All rights reserved.</p> | |
</div> | |
</div> | |
</footer> | |
<script> | |
// Base32 implementation | |
const Base32 = { | |
chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | |
pad: '=', | |
encode: function(input) { | |
if (!input) return ''; | |
let output = ''; | |
let buffer = 0; | |
let bitsLeft = 0; | |
for (let i = 0; i < input.length; i++) { | |
buffer = (buffer << 8) | input.charCodeAt(i); | |
bitsLeft += 8; | |
while (bitsLeft >= 5) { | |
bitsLeft -= 5; | |
output += this.chars.charAt((buffer >>> bitsLeft) & 0x1F); | |
} | |
} | |
if (bitsLeft > 0) { | |
buffer <<= (5 - bitsLeft); | |
output += this.chars.charAt(buffer & 0x1F); | |
} | |
// Add padding | |
const padCount = (8 - (output.length % 8)) % 8; | |
output += this.pad.repeat(padCount); | |
return output; | |
}, | |
decode: function(input) { | |
if (!input) return ''; | |
// Remove padding and convert to uppercase | |
input = input.replace(new RegExp(this.pad + '+$', 'g'), '').toUpperCase(); | |
let output = ''; | |
let buffer = 0; | |
let bitsLeft = 0; | |
for (let i = 0; i < input.length; i++) { | |
const index = this.chars.indexOf(input.charAt(i)); | |
if (index === -1) continue; | |
buffer = (buffer << 5) | index; | |
bitsLeft += 5; | |
if (bitsLeft >= 8) { | |
bitsLeft -= 8; | |
output += String.fromCharCode((buffer >>> bitsLeft) & 0xFF); | |
} | |
} | |
return output; | |
} | |
}; | |
document.addEventListener('DOMContentLoaded', function() { | |
// DOM elements | |
const encodeTab = document.getElementById('encode-tab'); | |
const decodeTab = document.getElementById('decode-tab'); | |
const methodSelect = document.getElementById('method'); | |
const inputText = document.getElementById('input-text'); | |
const processBtn = document.getElementById('process-btn'); | |
const clearBtn = document.getElementById('clear-btn'); | |
const clearInputBtn = document.getElementById('clear-input-btn'); | |
const sampleBtn = document.getElementById('sample-btn'); | |
const resultContainer = document.getElementById('result-container'); | |
const result = document.getElementById('result'); | |
const copyBtn = document.getElementById('copy-btn'); | |
const downloadBtn = document.getElementById('download-btn'); | |
const expandBtn = document.getElementById('expand-btn'); | |
const charCount = document.getElementById('char-count'); | |
const historyTable = document.getElementById('history-table'); | |
const emptyHistory = document.getElementById('empty-history'); | |
const clearHistoryBtn = document.getElementById('clear-history-btn'); | |
let isEncoding = true; | |
let conversionHistory = JSON.parse(localStorage.getItem('conversionHistory')) || []; | |
// Initialize | |
updateHistoryTable(); | |
updateCharCount(); | |
// Event listeners for input changes | |
inputText.addEventListener('input', updateCharCount); | |
// Tab switching | |
encodeTab.addEventListener('click', function() { | |
isEncoding = true; | |
encodeTab.classList.add('tab-active'); | |
decodeTab.classList.remove('tab-active'); | |
processBtn.innerHTML = '<i class="fas fa-cog mr-2"></i> Encode'; | |
}); | |
decodeTab.addEventListener('click', function() { | |
isEncoding = false; | |
decodeTab.classList.add('tab-active'); | |
encodeTab.classList.remove('tab-active'); | |
processBtn.innerHTML = '<i class="fas fa-cog mr-2"></i> Decode'; | |
}); | |
// Process button | |
processBtn.addEventListener('click', function() { | |
const method = methodSelect.value; | |
const text = inputText.value.trim(); | |
if (!text) { | |
showAlert('Please enter some text to process', 'error'); | |
return; | |
} | |
let processedText; | |
try { | |
if (isEncoding) { | |
processedText = encodeText(text, method); | |
} else { | |
processedText = decodeText(text, method); | |
} | |
result.textContent = processedText; | |
updateCharCount(); | |
// Add to history | |
addToHistory(method, text, processedText); | |
// Show success message | |
showAlert('Operation completed successfully!', 'success'); | |
} catch (e) { | |
result.textContent = `Error: ${e.message}`; | |
showAlert('An error occurred during processing', 'error'); | |
} | |
}); | |
// Clear buttons | |
clearBtn.addEventListener('click', function() { | |
inputText.value = ''; | |
result.textContent = ''; | |
updateCharCount(); | |
}); | |
clearInputBtn.addEventListener('click', function() { | |
inputText.value = ''; | |
updateCharCount(); | |
inputText.focus(); | |
}); | |
// Sample button | |
sampleBtn.addEventListener('click', function() { | |
const method = methodSelect.value; | |
let sampleText = ''; | |
switch(method) { | |
case 'base64': | |
case 'base32': | |
sampleText = 'Sample text to encode'; | |
break; | |
case 'url': | |
sampleText = 'https://example.com/search?q=hello world'; | |
break; | |
case 'html': | |
sampleText = '<div>Hello & Welcome</div>'; | |
break; | |
case 'hex': | |
sampleText = '48656c6c6f20576f726c64'; | |
break; | |
case 'binary': | |
sampleText = '01001000 01100101 01101100 01101100 01101111'; | |
break; | |
case 'rot13': | |
sampleText = 'Uryyb Jbeyq'; | |
break; | |
default: | |
sampleText = 'Sample text'; | |
} | |
inputText.value = sampleText; | |
updateCharCount(); | |
}); | |
// Copy button | |
copyBtn.addEventListener('click', function() { | |
if (!result.textContent) { | |
showAlert('No result to copy', 'error'); | |
return; | |
} | |
navigator.clipboard.writeText(result.textContent) | |
.then(() => { | |
const originalIcon = copyBtn.innerHTML; | |
copyBtn.innerHTML = '<i class="fas fa-check"></i>'; | |
setTimeout(() => { | |
copyBtn.innerHTML = originalIcon; | |
}, 2000); | |
showAlert('Copied to clipboard!', 'success'); | |
}) | |
.catch(err => { | |
console.error('Failed to copy text: ', err); | |
showAlert('Failed to copy to clipboard', 'error'); | |
}); | |
}); | |
// Download button | |
downloadBtn.addEventListener('click', function() { | |
if (!result.textContent) { | |
showAlert('No result to download', 'error'); | |
return; | |
} | |
const method = methodSelect.value; | |
const isEncoded = isEncoding; | |
const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); | |
let filename = `codecipher_${timestamp}`; | |
if (isEncoded) { | |
filename += `_encoded.${method}`; | |
} else { | |
filename += `_decoded.txt`; | |
} | |
const blob = new Blob([result.textContent], { type: 'text/plain' }); | |
const url = URL.createObjectURL(blob); | |
const a = document.createElement('a'); | |
a.href = url; | |
a.download = filename; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
URL.revokeObjectURL(url); | |
showAlert('Download started!', 'success'); | |
}); | |
// Expand button | |
expandBtn.addEventListener('click', function() { | |
resultContainer.classList.toggle('expanded'); | |
if (resultContainer.classList.contains('expanded')) { | |
expandBtn.innerHTML = '<i class="fas fa-compress"></i>'; | |
} else { | |
expandBtn.innerHTML = '<i class="fas fa-expand"></i>'; | |
} | |
}); | |
// Clear history button | |
clearHistoryBtn.addEventListener('click', function() { | |
if (conversionHistory.length === 0) return; | |
if (confirm('Are you sure you want to clear all history?')) { | |
conversionHistory = []; | |
localStorage.setItem('conversionHistory', JSON.stringify(conversionHistory)); | |
updateHistoryTable(); | |
showAlert('History cleared', 'success'); | |
} | |
}); | |
// Encoding/Decoding functions | |
function encodeText(text, method) { | |
switch(method) { | |
case 'base64': | |
return btoa(unescape(encodeURIComponent(text))); | |
case 'base32': | |
return Base32.encode(text); | |
case 'url': | |
return encodeURIComponent(text); | |
case 'html': | |
return text.split('').map(c => `&#${c.charCodeAt(0)};`).join(''); | |
case 'hex': | |
return text.split('').map(c => c.charCodeAt(0).toString(16)).join(' '); | |
case 'binary': | |
return text.split('').map(c => c.charCodeAt(0).toString(2).padStart(8, '0')).join(' '); | |
case 'rot13': | |
return text.replace(/[a-zA-Z]/g, function(c) { | |
return String.fromCharCode((c <= 'Z' ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26); | |
}); | |
default: | |
return text; | |
} | |
} | |
function decodeText(text, method) { | |
try { | |
switch(method) { | |
case 'base64': | |
return decodeURIComponent(escape(atob(text))); | |
case 'base32': | |
return Base32.decode(text); | |
case 'url': | |
return decodeURIComponent(text); | |
case 'html': | |
const doc = new DOMParser().parseFromString(text, 'text/html'); | |
return doc.documentElement.textContent; | |
case 'hex': | |
return text.split(' ').map(h => String.fromCharCode(parseInt(h, 16))).join(''); | |
case 'binary': | |
return text.split(' ').map(b => String.fromCharCode(parseInt(b, 2))).join(''); | |
case 'rot13': | |
return text.replace(/[a-zA-Z]/g, function(c) { | |
return String.fromCharCode((c <= 'Z' ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26); | |
}); | |
default: | |
return text; | |
} | |
} catch (e) { | |
throw new Error(`Invalid ${method} input: ${e.message}`); | |
} | |
} | |
// History functions | |
function addToHistory(method, input, output) { | |
const conversion = { | |
method: method.charAt(0).toUpperCase() + method.slice(1), | |
input: input.length > 30 ? input.substring(0, 30) + '...' : input, | |
output: output.length > 30 ? output.substring(0, 30) + '...' : output, | |
fullInput: input, | |
fullOutput: output, | |
time: new Date().toLocaleTimeString(), | |
date: new Date().toLocaleDateString() | |
}; | |
conversionHistory.unshift(conversion); | |
if (conversionHistory.length > 10) { | |
conversionHistory.pop(); | |
} | |
localStorage.setItem('conversionHistory', JSON.stringify(conversionHistory)); | |
updateHistoryTable(); | |
} | |
function updateHistoryTable() { | |
if (conversionHistory.length === 0) { | |
historyTable.innerHTML = ''; | |
emptyHistory.style.display = 'block'; | |
return; | |
} | |
emptyHistory.style.display = 'none'; | |
historyTable.innerHTML = ''; | |
conversionHistory.forEach((item, index) => { | |
const row = document.createElement('tr'); | |
row.className = 'hover:bg-gray-50'; | |
row.innerHTML = ` | |
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${item.method}</td> | |
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.input}</td> | |
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.output}</td> | |
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> | |
<div>${item.time}</div> | |
<div class="text-xs text-gray-400">${item.date}</div> | |
</td> | |
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> | |
<button class="history-action-btn p-1 text-blue-500 hover:text-blue-700" data-index="${index}"> | |
<i class="fas fa-redo"></i> | |
</button> | |
<button class="history-delete-btn p-1 text-red-500 hover:text-red-700" data-index="${index}"> | |
<i class="fas fa-trash-alt"></i> | |
</button> | |
</td> | |
`; | |
historyTable.appendChild(row); | |
}); | |
// Add event listeners to action buttons | |
document.querySelectorAll('.history-action-btn').forEach(btn => { | |
btn.addEventListener('click', function() { | |
const index = parseInt(this.getAttribute('data-index')); | |
const item = conversionHistory[index]; | |
methodSelect.value = item.method.toLowerCase(); | |
inputText.value = item.fullInput; | |
result.textContent = item.fullOutput; | |
updateCharCount(); | |
// Set to decode if the output looks encoded | |
if (item.fullOutput !== decodeText(item.fullOutput, item.method.toLowerCase())) { | |
isEncoding = false; | |
decodeTab.classList.add('tab-active'); | |
encodeTab.classList.remove('tab-active'); | |
processBtn.innerHTML = '<i class="fas fa-cog mr-2"></i> Decode'; | |
} else { | |
isEncoding = true; | |
encodeTab.classList.add('tab-active'); | |
decodeTab.classList.remove('tab-active'); | |
processBtn.innerHTML = '<i class="fas fa-cog mr-2"></i> Encode'; | |
} | |
}); | |
}); | |
document.querySelectorAll('.history-delete-btn').forEach(btn => { | |
btn.addEventListener('click', function() { | |
const index = parseInt(this.getAttribute('data-index')); | |
conversionHistory.splice(index, 1); | |
localStorage.setItem('conversionHistory', JSON.stringify(conversionHistory)); | |
updateHistoryTable(); | |
showAlert('Item removed from history', 'success'); | |
}); | |
}); | |
} | |
// Helper functions | |
function updateCharCount() { | |
const inputLength = inputText.value.length; | |
const resultLength = result.textContent.length; | |
let countText = ''; | |
if (inputLength > 0) { | |
countText += `Input: ${inputLength} chars`; | |
} | |
if (resultLength > 0) { | |
if (countText) countText += ' • '; | |
countText += `Result: ${resultLength} chars`; | |
} | |
charCount.textContent = countText; | |
} | |
function showAlert(message, type) { | |
// Remove any existing alerts | |
const existingAlert = document.querySelector('.alert-message'); | |
if (existingAlert) { | |
existingAlert.remove(); | |
} | |
const alert = document.createElement('div'); | |
alert.className = `alert-message fixed top-4 right-4 px-4 py-2 rounded-lg shadow-lg text-white ${ | |
type === 'success' ? 'bg-green-500' : 'bg-red-500' | |
} animate-bounce`; | |
alert.innerHTML = ` | |
<div class="flex items-center"> | |
<i class="fas ${type === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle'} mr-2"></i> | |
<span>${message}</span> | |
</div> | |
`; | |
document.body.appendChild(alert); | |
// Auto-remove after 3 seconds | |
setTimeout(() => { | |
alert.classList.remove('animate-bounce'); | |
alert.classList.add('opacity-0', 'transition-opacity', 'duration-300'); | |
setTimeout(() => { | |
alert.remove(); | |
}, 300); | |
}, 3000); | |
} | |
}); | |
</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=DotSlashGabut/codecipher" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |