| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Modern Text Processor</title> |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet"> |
| <script> |
| tailwind.config = { |
| theme: { |
| extend: { |
| fontFamily: { |
| 'inter': ['Inter', 'sans-serif'], |
| 'space': ['Space Grotesk', 'sans-serif'] |
| }, |
| colors: { |
| primary: { |
| 50: '#f0f9ff', |
| 100: '#e0f2fe', |
| 200: '#bae6fd', |
| 300: '#7dd3fc', |
| 400: '#38bdf8', |
| 500: '#0ea5e9', |
| 600: '#0284c7', |
| 700: '#0369a1', |
| 800: '#075985', |
| 900: '#0c4a6e', |
| } |
| } |
| } |
| } |
| } |
| </script> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap'); |
| |
| body { |
| font-family: 'Inter', sans-serif; |
| background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); |
| min-height: 100vh; |
| } |
| |
| .output-bg { |
| background: rgba(255, 255, 255, 0.7); |
| backdrop-filter: blur(10px); |
| border: 1px solid rgba(255, 255, 255, 0.3); |
| } |
| |
| .glow-effect { |
| box-shadow: 0 0 20px rgba(2, 132, 199, 0.2); |
| } |
| |
| .textarea-focus:focus { |
| box-shadow: 0 0 0 3px rgba(2, 132, 199, 0.2); |
| } |
| |
| .transition-all { |
| transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
| } |
| </style> |
| </head> |
| <body class="font-inter"> |
| <div class="min-h-screen flex flex-col items-center justify-center p-4"> |
| <div class="max-w-2xl w-full space-y-8"> |
| |
| <div class="text-center mb-10" data-aos="fade-down"> |
| <h1 class="text-4xl md:text-5xl font-bold text-gray-800 mb-3 font-space">Text Transformer</h1> |
| <p class="text-lg text-gray-600 max-w-md mx-auto">Transform your text with modern processing capabilities</p> |
| </div> |
| |
| |
| <div class="bg-white rounded-2xl shadow-xl p-6 glow-effect" data-aos="fade-up"> |
| <div class="flex items-center justify-between mb-4"> |
| <h2 class="text-xl font-semibold text-gray-800 font-space">Input Text</h2> |
| <div class="flex space-x-2"> |
| <button id="clearBtn" class="p-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"> |
| <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /> |
| </svg> |
| </button> |
| </div> |
| </div> |
| <textarea |
| id="inputText" |
| class="w-full h-40 p-4 text-gray-700 border border-gray-200 rounded-xl focus:outline-none textarea-focus resize-none" |
| placeholder="Type or paste your text here..." |
| ></textarea> |
| <div class="flex flex-wrap gap-2 mt-4"> |
| <button id="upperCaseBtn" class="px-4 py-2 bg-primary-500 text-white rounded-lg hover:bg-primary-600 transition-all transform hover:scale-105"> |
| UPPER CASE |
| </button> |
| <button id="lowerCaseBtn" class="px-4 py-2 bg-primary-500 text-white rounded-lg hover:bg-primary-600 transition-all transform hover:scale-105"> |
| lower case |
| </button> |
| <button id="capitalizeBtn" class="px-4 py-2 bg-primary-500 text-white rounded-lg hover:bg-primary-600 transition-all transform hover:scale-105"> |
| Capitalize |
| </button> |
| <button id="reverseBtn" class="px-4 py-2 bg-primary-500 text-white rounded-lg hover:bg-primary-600 transition-all transform hover:scale-105"> |
| Reverse |
| </button> |
| </div> |
| </div> |
| |
| |
| <div class="bg-white rounded-2xl shadow-xl p-6 output-bg" data-aos="fade-up" data-aos-delay="100"> |
| <div class="flex items-center justify-between mb-4"> |
| <h2 class="text-xl font-semibold text-gray-800 font-space">Processed Text</h2> |
| <button id="copyBtn" class="flex items-center space-x-1 px-3 py-1.5 bg-primary-100 text-primary-700 rounded-lg hover:bg-primary-200 transition-colors"> |
| <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" /> |
| </svg> |
| <span>Copy</span> |
| </button> |
| </div> |
| <div id="outputText" class="w-full h-40 p-4 text-gray-700 border border-gray-200 rounded-xl bg-gray-50 overflow-auto"> |
| <p class="text-gray-400 italic">Your processed text will appear here...</p> |
| </div> |
| <div class="mt-4 flex justify-between items-center text-sm text-gray-500"> |
| <span id="charCount">Characters: 0</span> |
| <span id="wordCount">Words: 0</span> |
| </div> |
| </div> |
| |
| |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-8" data-aos="fade-up" data-aos-delay="200"> |
| <div class="bg-white rounded-xl p-5 shadow-lg text-center"> |
| <div class="text-3xl font-bold text-primary-600 mb-2 font-space" id="totalChars">0</div> |
| <div class="text-gray-600">Total Characters</div> |
| </div> |
| <div class="bg-white rounded-xl p-5 shadow-lg text-center"> |
| <div class="text-3xl font-bold text-primary-600 mb-2 font-space" id="totalWords">0</div> |
| <div class="text-gray-600">Total Words</div> |
| </div> |
| <div class="bg-white rounded-xl p-5 shadow-lg text-center"> |
| <div class="text-3xl font-bold text-primary-600 mb-2 font-space" id="transformCount">0</div> |
| <div class="text-gray-600">Transformations</div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script> |
| <script> |
| |
| AOS.init({ |
| duration: 800, |
| easing: 'ease-out-cubic' |
| }); |
| |
| |
| const inputText = document.getElementById('inputText'); |
| const outputText = document.getElementById('outputText'); |
| const charCount = document.getElementById('charCount'); |
| const wordCount = document.getElementById('wordCount'); |
| const totalChars = document.getElementById('totalChars'); |
| const totalWords = document.getElementById('totalWords'); |
| const transformCount = document.getElementById('transformCount'); |
| |
| |
| const clearBtn = document.getElementById('clearBtn'); |
| const upperCaseBtn = document.getElementById('upperCaseBtn'); |
| const lowerCaseBtn = document.getElementById('lowerCaseBtn'); |
| const capitalizeBtn = document.getElementById('capitalizeBtn'); |
| const reverseBtn = document.getElementById('reverseBtn'); |
| const copyBtn = document.getElementById('copyBtn'); |
| |
| |
| let transformations = 0; |
| |
| |
| function updateStats(text) { |
| const chars = text.length; |
| const words = text.trim() ? text.trim().split(/\s+/).length : 0; |
| |
| charCount.textContent = `Characters: ${chars}`; |
| wordCount.textContent = `Words: ${words}`; |
| totalChars.textContent = chars; |
| totalWords.textContent = words; |
| } |
| |
| |
| function processText(processor) { |
| const text = inputText.value; |
| if (!text) return; |
| |
| const processed = processor(text); |
| outputText.innerHTML = `<p class="text-gray-800">${processed}</p>`; |
| transformations++; |
| transformCount.textContent = transformations; |
| updateStats(text); |
| } |
| |
| |
| const processors = { |
| upper: text => text.toUpperCase(), |
| lower: text => text.toLowerCase(), |
| capitalize: text => text.split(' ').map(word => |
| word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() |
| ).join(' '), |
| reverse: text => text.split('').reverse().join('') |
| }; |
| |
| |
| inputText.addEventListener('input', () => { |
| updateStats(inputText.value); |
| }); |
| |
| clearBtn.addEventListener('click', () => { |
| inputText.value = ''; |
| outputText.innerHTML = '<p class="text-gray-400 italic">Your processed text will appear here...</p>'; |
| updateStats(''); |
| }); |
| |
| upperCaseBtn.addEventListener('click', () => processText(processors.upper)); |
| lowerCaseBtn.addEventListener('click', () => processText(processors.lower)); |
| capitalizeBtn.addEventListener('click', () => processText(processors.capitalize)); |
| reverseBtn.addEventListener('click', () => processText(processors.reverse)); |
| |
| copyBtn.addEventListener('click', () => { |
| const text = outputText.innerText; |
| if (!text || text.includes('Your processed text will appear here')) return; |
| |
| navigator.clipboard.writeText(text).then(() => { |
| const originalText = copyBtn.innerHTML; |
| copyBtn.innerHTML = ` |
| <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /> |
| </svg> |
| <span>Copied!</span> |
| `; |
| setTimeout(() => { |
| copyBtn.innerHTML = originalText; |
| }, 2000); |
| }); |
| }); |
| |
| |
| updateStats(''); |
| </script> |
| </body> |
| </html> |
|
|