@@ 1,1 0,0 @@
-<!DOCTYPE html><html><head><title>kana.guru - Convert romaji to hiragana/katakana</title><meta charset=utf-8><meta name=viewport content="width=device-width, initial-scale=1"><link rel=icon href=favicon.svg><link rel=stylesheet href=style.css><script type=module src=kana.js></script><body><div><h2>かな.グル <span id=copyright> © <span id=copyright-year></span> Gabriel Sanches / <a href=https://git.sr.ht/~gbrlsnchs/kana-guru>source code</a> </span></h2><h3>Options</h3><div><input id=katakana type=checkbox><label for=katakana>Start with katakana</label></div><div><input id=extended type=checkbox><label for=extended>Extended katakana</label></div><div><input id=punctuation type=checkbox><label for=punctuation>Parse punctuation</label></div><div><input id=force-prolongation type=checkbox><label for=force-prolongation>Force prolongation</label></div><div><input id=kana-toggle type=checkbox><label for=kana-toggle>Use @ to toggle kanas</label></div><div><input id=raw-toggle type=checkbox><label for=raw-toggle>Use # to toggle raw text</label></div><div><input id=prolongation-reset type=checkbox><label for=prolongation-reset>Use ^ to reset prolongation</label></div><div><input id=vowel-shortener type=checkbox><label for=vowel-shortener>Use _ to shorten vowel</label></div><div><input id=virtual-stop type=checkbox><label for=virtual-stop>Use % to add virtual stop</label></div><h3>Input</h3><textarea id=romaji autocomplete=off spellcheck=false></textarea><div id=output><h3>Output</h3><button id=copy>(copy)</button></div><p id=result></div>>
\ No newline at end of file
@@ 1,1 0,0 @@
-let result = ""; const inputs = { romaji: document.getElementById("romaji"), katakana: document.getElementById("katakana"), extended: document.getElementById("extended"), punctuation: document.getElementById("punctuation"), forceProlongation: document.getElementById("force-prolongation"), kanaToggle: document.getElementById("kana-toggle"), rawToggle: document.getElementById("raw-toggle"), prolongationReset: document.getElementById("prolongation-reset"), vowelShortener: document.getElementById("vowel-shortener"), virtualStop: document.getElementById("virtual-stop"), }; const output = document.getElementById("result"); const loading = document.getElementById("loading"); const copy = document.getElementById("copy"); const encodeString = (value) => { const buffer = new TextEncoder().encode(value); const ptr = allocString(buffer.length + 1); const slice = new Uint8Array(memory.buffer, ptr, buffer.length + 1); slice.set(buffer); slice[buffer.length] = 0; return ptr; }; const decodeString = (ptr, len) => { const slice = new Uint8Array(memory.buffer, ptr, len); return new TextDecoder().decode(slice); }; const parseCheckbox = (el) => { if (!el) { return false; } return el.checked; }; const parseAscii = (el, char) => { return parseCheckbox(el) ? char.charCodeAt(0) : 0; }; const convert = () => { setTimeout(() => {}, 0); const ptr = encodeString(inputs.romaji.value); transliterate( ptr, parseCheckbox(inputs.katakana), parseCheckbox(inputs.extended), parseCheckbox(inputs.punctuation), parseCheckbox(inputs.forceProlongation), parseAscii(inputs.kanaToggle, "@"), parseAscii(inputs.rawToggle, "#"), parseAscii(inputs.prolongationReset, "^"), parseAscii(inputs.vowelShortener, "_"), parseAscii(inputs.virtualStop, "%"), ); freeString(ptr); }; const initialYear = 2023; const currentYear = new Date().getUTCFullYear(); const copyright = document.getElementById("copyright-year"); copyright.innerText = initialYear === currentYear ? initialYear : `${initialYear}-${currentYear}`; const { instance: { exports: { memory, allocString, freeString, transliterate }, }, } = await WebAssembly.instantiateStreaming(fetch("kana.wasm"), { env: { handleResult(ptr, len) { output.innerText = len > 0 ? decodeString(ptr, len) : ""; }, }, }); for (let [key, value] of Object.entries(inputs)) { value.addEventListener(key === "romaji" ? "keyup" : "input", () => { convert(); }); } copy.addEventListener("click", () => { navigator.clipboard.writeText(output.innerText || output.textContent); });>
\ No newline at end of file
@@ 1,1 0,0 @@
-:root { --bg-color: #1d1f21; --fg-color: #c5c8c6; --gray: #373b41; --copy: #8c9440; --link: #5f819d; } @media (prefers-color-scheme: light) { :root { --bg-color: #c5c8c6; --fg-color: #1d1f21; --gray: #707880; --copy: #5e8d87; --link: #a54242; } } body { margin: 0; padding: 0; width: 100vw; display: flex; justify-content: center; background-color: var(--bg-color); color: var(--fg-color); overflow: auto; font-family: monospace; } body > div { display: flex; flex-direction: column; gap: 8px; width: 640px; padding: 16px; } @media (max-width: 640px) { body > div { width: 100vw; } } h2 { display: flex; align-items: center; justify-content: space-between; } @media (max-width: 640px) { h2 { flex-direction: column; gap: 8px; } } h2, h3 { overflow: hidden; position: relative; margin-bottom: 0; } p { margin: 0; } h3:first-of-type:after { content: ""; width: 100%; height: 1px; background: var(--gray); position: absolute; top: 50%; margin-left: 16px; } a { color: var(--gray); text-decoration: none; } a:hover { color: var(--link); text-decoration: underline; } input[type="checkbox"] { margin-right: 8px; } label:hover, input[type="checkbox"]:hover { cursor: pointer; } textarea { height: 128px; resize: none; overflow-y: scroll; font-size: inherit; border: 1px solid var(--gray); padding: 8px; } textarea, input[type="checkbox"] { background-color: var(--bg); color: var(--fg); } #copyright { color: var(--gray); font-size: 0.8rem; } #result { white-space: pre-line; overflow-wrap: anywhere; } #copy { font-family: monospace; font-size: 0.8rem; font-weight: bold; color: var(--fg-color); border: 0; background-color: var(--bg-color); padding: 0; } #copy:hover { cursor: pointer; color: var(--copy); } #output { display: flex; flex-direction: row; justify-content: space-between; align-items: end; gap: 16px; } #output > h3 { flex: 1; }>
\ No newline at end of file