| <!DOCTYPE html> |
| <html lang="vi"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>CVNSS 4.0 ⇄ Chữ Quốc ngữ</title> |
| <style> |
| body { |
| font-family: Segoe UI, Arial, Helvetica, sans-serif; |
| background: #f4f6f8; |
| margin: 30px; |
| text-align: center; |
| color: #333; |
| } |
| h1 { |
| margin-bottom: 18px; |
| font-size: 26px; |
| color: #2c3e50; |
| } |
| .wrap { |
| display: flex; |
| gap: 24px; |
| flex-wrap: wrap; |
| justify-content: center; |
| margin-bottom: 14px; |
| } |
| textarea { |
| width: 400px; |
| height: 210px; |
| padding: 12px; |
| font-size: 16px; |
| border: 1px solid #dcdcdc; |
| border-radius: 8px; |
| resize: vertical; |
| box-shadow: 0 1px 3px rgba(0,0,0,0.06); |
| box-sizing: border-box; |
| } |
| textarea:focus { |
| border-color: #3498db; |
| box-shadow: 0 0 0 2px rgba(52,152,219,0.12); |
| outline: none; |
| } |
| .controls { |
| display: flex; |
| gap: 12px; |
| justify-content: center; |
| margin-top: 6px; |
| } |
| button, .mode-select { |
| padding: 8px 18px; |
| font-size: 15px; |
| border-radius: 6px; |
| cursor: pointer; |
| border: 1px solid #dcdcdc; |
| } |
| button { |
| color: #fff; |
| background-color: #3498db; |
| border: none; |
| min-width: 90px; |
| transition: filter 0.15s; |
| } |
| button:hover { filter: brightness(1.1);} |
| button:active { filter: brightness(0.98);} |
| .reset { background: #e74c3c;} |
| .mode-select { background: #fff; min-width: 180px;} |
| .mode-select:focus { |
| border-color: #3498db; |
| box-shadow: 0 0 0 2px rgba(52,152,219,0.09); |
| outline: none; |
| } |
| .status-message { |
| margin-top: 12px; |
| font-size: 13px; |
| min-height: 20px; |
| } |
| .status-success { color: #27ae60;} |
| .status-error { color: #c0392b;} |
| </style> |
| </head> |
| <body> |
| <h1>CVNSS 4.0 ⇄ Chữ Quốc ngữ</h1> |
|
|
| <div class="wrap"> |
| <textarea id="inputText" placeholder="Nhập văn bản (CVNSS hoặc CQN)"></textarea> |
| <textarea id="outputText" placeholder="Kết quả chuyển đổi" readonly></textarea> |
| </div> |
|
|
| <div class="controls"> |
| <select id="mode" class="mode-select"> |
| <option value="cvn">CVNSS 4.0 → Chữ Quốc ngữ</option> |
| <option value="cqn">Chữ Quốc ngữ → CVNSS 4.0</option> |
| </select> |
| <button onclick="copyText()">Sao chép</button> |
| <button class="reset" onclick="resetAll()">Đặt lại</button> |
| </div> |
| <div id="statusMessage" class="status-message"></div> |
|
|
| <script src="cvnss4.0-converter.js"></script> |
| <script> |
| const inputBox = document.getElementById("inputText"); |
| const outputBox = document.getElementById("outputText"); |
| const modeSelect = document.getElementById("mode"); |
| const statusMessageEl = document.getElementById("statusMessage"); |
| |
| function convertText() { |
| const input = inputBox.value; |
| const mode = modeSelect.value; |
| if (!input.trim()) { |
| outputBox.value = ""; |
| return; |
| } |
| try { |
| const result = CVNSSConverter.convert(input, mode); |
| |
| outputBox.value = mode === "cvn" ? result.cqn : result.cvn; |
| } catch (e) { |
| outputBox.value = ""; |
| showStatus("Lỗi chuyển đổi: " + e.message, "error"); |
| } |
| } |
| |
| inputBox.addEventListener("input", convertText); |
| modeSelect.addEventListener("change", convertText); |
| |
| async function copyText() { |
| if (!outputBox.value.trim()) { |
| showStatus("Không có nội dung để sao chép.", "error"); |
| return; |
| } |
| try { |
| await navigator.clipboard.writeText(outputBox.value); |
| showStatus("Đã sao chép vào clipboard!", "success"); |
| } catch { |
| outputBox.select(); |
| document.execCommand("copy"); |
| showStatus("Đã sao chép (cách cũ)!", "success"); |
| } |
| } |
| |
| function resetAll() { |
| inputBox.value = ""; |
| outputBox.value = ""; |
| modeSelect.value = "cvn"; |
| statusMessageEl.textContent = ""; |
| inputBox.focus(); |
| } |
| |
| function showStatus(message, type="success") { |
| statusMessageEl.textContent = message; |
| statusMessageEl.className = `status-message status-${type}`; |
| setTimeout(() => { statusMessageEl.textContent = ""; }, 2000); |
| } |
| </script> |
| </body> |
| </html> |
|
|