rsrc/extra/findreplace.html

6 lines
6.8 KiB
HTML

<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>find-replace</title><style>:root{--bg:#000;--control:#101010;--hover:#181818;--text:#eee;--soft:#bbb;--muted:#8e8e8e;--focus:rgba(255,255,255,.65)}*{box-sizing:border-box}html,body{min-height:100%;background:var(--bg)}body{margin:0;padding:12px;color:var(--text);font:14px/1.4 ui-monospace,SFMono-Regular,Consolas,"Liberation Mono",monospace}.app{width:min(100%,1100px);min-height:calc(100vh - 24px);margin:auto;display:grid;grid-template-columns:290px minmax(0,1fr);gap:10px}.panel{background:var(--bg)}.sidebar{padding:8px;display:flex;flex-direction:column;gap:6px;max-height:calc(100vh - 24px);overflow:auto}.field{padding:6px}.label{display:flex;justify-content:space-between;gap:8px;margin:0 0 6px;color:var(--muted);font-size:11px;letter-spacing:.06em;text-transform:lowercase}.value{color:var(--soft);letter-spacing:0}input,textarea,button{font:inherit}input{width:100%;height:32px;padding:0 9px;color:var(--text);background:var(--control);border:0;outline:0;font-size:12px}input:focus,textarea:focus{box-shadow:inset 0 0 0 1px var(--focus)}.toggle-grid{display:grid;grid-template-columns:1fr 1fr;gap:5px}.toggle{min-height:32px;padding:6px 8px;display:flex;align-items:center;justify-content:space-between;gap:6px;color:var(--soft);background:var(--control);cursor:pointer;font-size:11px;text-transform:lowercase}.toggle:hover,button:hover{color:#000;background:#eee}.toggle input{appearance:none;width:26px;height:15px;margin:0;position:relative;border:0;border-radius:99px;background:#444;cursor:pointer}.toggle input:after{content:"";position:absolute;top:2px;left:2px;width:11px;height:11px;border-radius:50%;background:#999;transition:.12s}.toggle input:checked{background:#777}.toggle input:checked:after{left:13px;background:#fff}.workspace{display:grid;grid-template-rows:minmax(440px,1fr) 140px;gap:10px;min-height:calc(100vh - 24px)}.preview,.output{position:relative;overflow:hidden}.tag{position:absolute;top:9px;left:9px;z-index:2;padding:3px 5px;color:var(--muted);background:var(--bg);font-size:11px;letter-spacing:.08em;text-transform:uppercase;pointer-events:none}.tools{position:absolute;top:8px;right:8px;z-index:2;display:flex;gap:5px}textarea{display:block;width:100%;height:100%;min-height:120px;padding:35px 11px 11px;resize:none;outline:0;color:var(--text);background:var(--bg);border:0;font:12px/1.5 ui-monospace,SFMono-Regular,Consolas,"Liberation Mono",monospace}.output textarea{padding:10px 11px 38px}button{height:27px;padding:0 9px;color:var(--soft);background:var(--control);border:0;cursor:pointer;font-size:11px}.actions{position:absolute;right:10px;bottom:10px;display:flex;gap:5px}.status{position:absolute;left:12px;bottom:14px;color:var(--muted);font-size:11px}@media(max-width:720px){body{padding:8px}.app{grid-template-columns:1fr;min-height:0}.sidebar{max-height:none}.workspace{min-height:auto;grid-template-rows:420px 140px}}@media(max-width:400px){.toggle-grid{grid-template-columns:1fr}.workspace{grid-template-rows:360px 140px}.tools{top:auto;bottom:8px}}</style></head><body><div class="app"><aside class="panel sidebar"><div class="field"><div class="label"><span>find</span><span class="value">text or pattern</span></div><input id="f" value="index.html" placeholder="Text or regex pattern" autocomplete="off" spellcheck="false"></div><div class="field"><div class="label"><span>replace with</span><span class="value">replacement</span></div><input id="r" value="app" placeholder="Replacement text" autocomplete="off" spellcheck="false"></div><div class="field"><div class="label"><span>regex flags</span><span class="value">used in regex mode</span></div><input id="g" value="g" placeholder="g, i, m, s" autocomplete="off" spellcheck="false"></div><div class="field"><div class="label"><span>options</span><span class="value">automatic output</span></div><div class="toggle-grid"><label class="toggle"><span>live update</span><input id="l" type="checkbox" checked></label><label class="toggle"><span>ignore case</span><input id="i" type="checkbox"></label><label class="toggle"><span>regex mode</span><input id="m" type="checkbox"></label></div></div><div class="field"><div class="label"><span>actions</span><span class="value">ctrl/⌘ + enter</span></div><div class="toggle-grid"><button id="x" type="button">replace all</button><button id="c" type="button">clear input</button></div></div></aside><main class="workspace"><section class="panel preview"><div class="tag">input text</div><div class="tools"><button id="u" type="button">use output</button><button id="p" type="button">copy output</button></div><textarea id="a" aria-label="Input text" placeholder="Paste text, HTML, code, or URLs here…" spellcheck="false"><a href="index.html">Home</a>
<a href="./index.html?v=1">Home</a>
<script src="index.html"></script>
<link rel="canonical" href=""></textarea></section><section class="panel output"><textarea id="o" aria-label="Output text" readonly placeholder="Your replaced text appears here…" spellcheck="false"></textarea><div id="s" class="status" role="status"></div><div class="actions"><button id="q" type="button">select all</button><button id="d" type="button">download</button></div></section></main></div><script>const $=e=>document.getElementById(e),f=$("f"),r=$("r"),g=$("g"),a=$("a"),o=$("o"),l=$("l"),i=$("i"),m=$("m"),s=$("s"),F=()=>{let e=g.value.replace(/[^dgimsuvy]/g,"");return e.includes("g")||(e+="g"),i.checked&&!e.includes("i")&&(e+="i"),[...new Set(e)].join("")},E=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),R=()=>{try{let e=m.checked?new RegExp(f.value,F()):new RegExp(E(f.value),i.checked?"gi":"g"),t=a.value.match(e)||[];o.value=a.value.replace(e,r.value),s.textContent=t.length+" match"+(t.length==1?"":"es")+" replaced",s.style.color=""}catch(e){o.value="",s.textContent="Error: "+e.message,s.style.color="#ff8080"}},L=()=>l.checked&&R();$("x").onclick=R;$("c").onclick=()=>{a.value="",o.value="",s.textContent="",a.focus()};$("p").onclick=async()=>{if(!o.value)return void(s.textContent="Nothing to copy");try{await navigator.clipboard.writeText(o.value)}catch(e){o.focus(),o.select(),document.execCommand("copy")}s.textContent="Output copied"};$("q").onclick=()=>{o.focus(),o.select(),s.textContent="Output selected"};$("u").onclick=()=>{o.value?(a.value=o.value,s.textContent="Output moved to input",L()):s.textContent="No output available"};$("d").onclick=()=>{let e=URL.createObjectURL(new Blob([o.value],{type:"text/plain;charset=utf-8"})),t=document.createElement("a");t.href=e,t.download="output.txt",t.click(),URL.revokeObjectURL(e),s.textContent="Output downloaded"};[f,r,g,a].forEach(e=>e.oninput=L),i.onchange=L,m.onchange=L,l.onchange=()=>l.checked&&R(),document.onkeydown=e=>{(e.ctrlKey||e.metaKey)&&e.key==="Enter"&&(e.preventDefault(),R())},R()</script></body></html>