Real web UI: /new editor, /history with live pagination, paste view with gutter and deletion banner, /unlock page; size in public API
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
{{template "head" .}}
|
||||
{{template "topbar" .}}
|
||||
<div class="deck">
|
||||
<div class="float pane-l">
|
||||
<div class="editor-head">
|
||||
<input id="title" placeholder="title (optional)">
|
||||
<select id="language">
|
||||
<option value="">auto</option>
|
||||
<option>go</option><option>python</option><option>javascript</option>
|
||||
<option>rust</option><option>c</option><option>cpp</option><option>java</option>
|
||||
<option>bash</option><option>sql</option><option>yaml</option><option>json</option>
|
||||
<option>markdown</option><option>text</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="editor-wrap">
|
||||
<div class="gutter" id="gutter">1</div>
|
||||
<textarea class="editor" id="content" placeholder="paste your code, text, or notes here…" spellcheck="false"></textarea>
|
||||
</div>
|
||||
<div class="created-banner" id="created"></div>
|
||||
<div class="actionbar">
|
||||
<span class="hint">Ctrl+Enter to create</span>
|
||||
<div class="spacer" style="flex:1"></div>
|
||||
<button class="btn" id="create">Create ⇧</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pane-r">
|
||||
<div class="float side-section">
|
||||
<h3>Expiry</h3>
|
||||
<div class="seg">
|
||||
<label><input type="radio" name="exp" value=""> Never</label>
|
||||
<label><input type="radio" name="exp" value="1h"> 1 hour</label>
|
||||
<label><input type="radio" name="exp" value="24h"> 1 day</label>
|
||||
<label><input type="radio" name="exp" value="168h" checked> 1 week</label>
|
||||
<label><input type="radio" name="exp" value="720h"> 30 days</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="float side-section">
|
||||
<h3>Protection</h3>
|
||||
<label class="toggle"><input type="checkbox" id="haspw"> Password lock</label>
|
||||
<input type="password" id="password" class="pwinput" placeholder="password" style="display:none; margin: 6px 8px 0; width: auto;">
|
||||
<label class="toggle"><input type="checkbox" id="burn"> Burn after read</label>
|
||||
<label class="toggle"><input type="checkbox" id="unlisted"> Unlisted</label>
|
||||
</div>
|
||||
<div class="float side-section">
|
||||
<h3>Custom URL</h3>
|
||||
<div class="row"><span>/</span><input type="text" id="custom" placeholder="my-snippet"></div>
|
||||
</div>
|
||||
<div class="float side-section">
|
||||
<h3>Result</h3>
|
||||
<div class="hint" id="result" style="word-break:break-all">—</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const $ = id => document.getElementById(id);
|
||||
const content = $('content'), gutter = $('gutter');
|
||||
|
||||
function updateGutter() {
|
||||
const lines = content.value.split('\n').length;
|
||||
let s = '';
|
||||
for (let i = 1; i <= Math.max(lines, 1); i++) s += i + '\n';
|
||||
gutter.textContent = s;
|
||||
}
|
||||
content.addEventListener('input', updateGutter);
|
||||
updateGutter();
|
||||
|
||||
$('haspw').addEventListener('change', e => { $('password').style.display = e.target.checked ? 'block' : 'none'; });
|
||||
|
||||
async function create() {
|
||||
const body = {
|
||||
content: content.value,
|
||||
title: $('title').value || null,
|
||||
language: $('language').value || null,
|
||||
custom_slug: $('custom').value || null,
|
||||
burn_after_read: $('burn').checked,
|
||||
};
|
||||
if ($('haspw').checked) body.password = $('password').value;
|
||||
const exp = document.querySelector('input[name="exp"]:checked').value;
|
||||
if (exp) body.expires_in = exp;
|
||||
|
||||
const res = await fetch('/api/pastes', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
$('result').textContent = 'Error: ' + (data.error || res.status);
|
||||
return;
|
||||
}
|
||||
const url = location.origin + '/' + (data.custom_slug || data.id);
|
||||
$('result').innerHTML = '<a href="' + url + '">' + url + '</a>';
|
||||
$('result').dataset.token = data.deletion_token || '';
|
||||
try { navigator.clipboard.writeText(url); } catch(e) {}
|
||||
// show the paste
|
||||
location.href = '/' + data.id + '?created=1&token=' + encodeURIComponent(data.deletion_token || '');
|
||||
}
|
||||
$('create').addEventListener('click', create);
|
||||
document.addEventListener('keydown', e => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); create(); }
|
||||
});
|
||||
</script>
|
||||
{{template "foot" .}}
|
||||
Reference in New Issue
Block a user