Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Text Line Copier</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| padding: 20px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .container { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(10px); | |
| border-radius: 20px; | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); | |
| padding: 40px; | |
| width: 100%; | |
| max-width: 600px; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| h1 { | |
| text-align: center; | |
| color: #333; | |
| margin-bottom: 30px; | |
| font-size: 2.2em; | |
| font-weight: 600; | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .input-section { | |
| margin-bottom: 30px; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 10px; | |
| color: #555; | |
| font-weight: 500; | |
| font-size: 1.1em; | |
| } | |
| textarea { | |
| width: 100%; | |
| height: 200px; | |
| padding: 15px; | |
| border: 2px solid #e0e0e0; | |
| border-radius: 12px; | |
| font-size: 16px; | |
| font-family: 'Courier New', monospace; | |
| resize: vertical; | |
| transition: all 0.3s ease; | |
| background: #fafafa; | |
| } | |
| textarea:focus { | |
| outline: none; | |
| border-color: #667eea; | |
| box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); | |
| background: white; | |
| } | |
| .control-section { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| } | |
| .parse-btn { | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| color: white; | |
| border: none; | |
| padding: 12px 30px; | |
| border-radius: 10px; | |
| font-size: 16px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| margin-bottom: 20px; | |
| } | |
| .parse-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3); | |
| } | |
| .copy-section { | |
| text-align: center; | |
| margin-top: 20px; | |
| } | |
| .current-line { | |
| background: #f8f9ff; | |
| border: 2px solid #e0e8ff; | |
| border-radius: 10px; | |
| padding: 15px; | |
| margin-bottom: 20px; | |
| font-family: 'Courier New', monospace; | |
| font-size: 16px; | |
| min-height: 60px; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: flex-start; | |
| color: #333; | |
| word-break: break-word; | |
| text-align: left; | |
| } | |
| .next-btn { | |
| background: linear-gradient(135deg, #4CAF50, #45a049); | |
| color: white; | |
| border: none; | |
| padding: 20px 50px; | |
| border-radius: 15px; | |
| font-size: 20px; | |
| font-weight: bold; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| margin-bottom: 15px; | |
| } | |
| .next-btn:hover:not(:disabled) { | |
| transform: translateY(-3px); | |
| box-shadow: 0 10px 25px rgba(76, 175, 80, 0.4); | |
| } | |
| .next-btn:disabled { | |
| background: #ccc; | |
| cursor: not-allowed; | |
| transform: none; | |
| box-shadow: none; | |
| } | |
| .status { | |
| margin-top: 15px; | |
| font-size: 16px; | |
| color: #666; | |
| font-weight: 500; | |
| } | |
| .success { | |
| color: #4CAF50; | |
| } | |
| .error { | |
| color: #f44336; | |
| } | |
| .info { | |
| background: #e3f2fd; | |
| border: 1px solid #bbdefb; | |
| border-radius: 8px; | |
| padding: 15px; | |
| margin-bottom: 20px; | |
| color: #1976d2; | |
| font-size: 14px; | |
| } | |
| .hidden { | |
| display: none; | |
| } | |
| @media (max-width: 480px) { | |
| .container { | |
| padding: 20px; | |
| margin: 10px; | |
| } | |
| h1 { | |
| font-size: 1.8em; | |
| } | |
| .next-btn { | |
| padding: 15px 35px; | |
| font-size: 18px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>📋 Text Line Copier</h1> | |
| <div class="info"> | |
| Paste your text below, click "Parse Text", then use the "Next" button to copy each line to your clipboard. Blank lines are used as delimiters but are not copied. | |
| </div> | |
| <div class="input-section"> | |
| <label for="textInput">Paste your text here:</label> | |
| <textarea id="textInput" placeholder="Paste your multi-line text here..."></textarea> | |
| </div> | |
| <div class="control-section"> | |
| <button class="parse-btn" onclick="parseText()">Parse Text</button> | |
| </div> | |
| <div id="copySection" class="copy-section hidden"> | |
| <div id="currentLine" class="current-line">Ready to copy first line...</div> | |
| <button id="nextBtn" class="next-btn" onclick="copyNextLine()">Next</button> | |
| <div id="status" class="status"></div> | |
| </div> | |
| </div> | |
| <script> | |
| let lines = []; | |
| let currentIndex = -1; | |
| function parseText() { | |
| const text = document.getElementById('textInput').value; | |
| if (!text) { | |
| updateStatus('Please enter some text first.', 'error'); | |
| return; | |
| } | |
| // Split by lines and filter out blank lines | |
| lines = text.split('\n').filter(line => line.trim() !== ''); | |
| currentIndex = 0; // Start at 0 to show first entry | |
| if (lines.length === 0) { | |
| updateStatus('No non-blank lines found in the text.', 'error'); | |
| return; | |
| } | |
| // Show copy section and display first line | |
| document.getElementById('copySection').classList.remove('hidden'); | |
| document.getElementById('nextBtn').disabled = false; | |
| // Copy the first line immediately after parsing | |
| copyFirstLine(); | |
| } | |
| async function copyFirstLine() { | |
| const lineToCopy = lines[0]; | |
| try { | |
| await navigator.clipboard.writeText(lineToCopy); | |
| // Display with item count and text on separate lines, left-aligned and bold header | |
| document.getElementById('currentLine').innerHTML = `<strong>Copied item 1 of ${lines.length}:</strong><br>${lineToCopy}`; | |
| updateStatus(`Copied item 1 of ${lines.length}`, 'success'); | |
| // Show next line preview or completion message | |
| if (lines.length > 1) { | |
| // Don't change the display here, wait for next button | |
| } else { | |
| // If only one item, prepare for finish | |
| setTimeout(() => { | |
| document.getElementById('currentLine').textContent = 'Click Next to finish'; | |
| }, 1000); | |
| } | |
| } catch (err) { | |
| updateStatus('Failed to copy to clipboard. Please try again.', 'error'); | |
| console.error('Copy failed:', err); | |
| } | |
| } | |
| async function copyNextLine() { | |
| currentIndex++; | |
| if (currentIndex >= lines.length) { | |
| document.getElementById('currentLine').textContent = 'No more text to copy'; | |
| document.getElementById('nextBtn').disabled = true; | |
| updateStatus('Finished! Resetting form in 3 seconds...', 'info'); | |
| // Reset form after 3 seconds | |
| setTimeout(() => { | |
| resetForm(); | |
| }, 3000); | |
| return; | |
| } | |
| const lineToCopy = lines[currentIndex]; | |
| try { | |
| await navigator.clipboard.writeText(lineToCopy); | |
| // Display with item count and text on separate lines, left-aligned and bold header | |
| document.getElementById('currentLine').innerHTML = `<strong>Copied item ${currentIndex + 1} of ${lines.length}:</strong><br>${lineToCopy}`; | |
| updateStatus(`Copied item ${currentIndex + 1} of ${lines.length}`, 'success'); | |
| // No preview of next line, just show current copied item | |
| } catch (err) { | |
| updateStatus('Failed to copy to clipboard. Please try again.', 'error'); | |
| console.error('Copy failed:', err); | |
| } | |
| } | |
| function resetForm() { | |
| // Clear the textarea | |
| document.getElementById('textInput').value = ''; | |
| // Hide the copy section | |
| document.getElementById('copySection').classList.add('hidden'); | |
| // Reset variables | |
| lines = []; | |
| currentIndex = -1; | |
| // Clear status | |
| document.getElementById('status').textContent = ''; | |
| // Reset current line display | |
| document.getElementById('currentLine').textContent = 'Ready to copy first line...'; | |
| // Re-enable next button | |
| document.getElementById('nextBtn').disabled = false; | |
| } | |
| function updateStatus(message, type) { | |
| const statusEl = document.getElementById('status'); | |
| statusEl.textContent = message; | |
| statusEl.className = `status ${type}`; | |
| } | |
| // Allow Enter key to parse text when in textarea | |
| document.getElementById('textInput').addEventListener('keydown', function(e) { | |
| if (e.ctrlKey && e.key === 'Enter') { | |
| parseText(); | |
| } | |
| }); | |
| // Allow spacebar or Enter to trigger next button | |
| document.addEventListener('keydown', function(e) { | |
| const nextBtn = document.getElementById('nextBtn'); | |
| if ((e.code === 'Space' || e.key === 'Enter') && !nextBtn.disabled && !nextBtn.classList.contains('hidden')) { | |
| e.preventDefault(); | |
| copyNextLine(); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </htmla |