156 lines
5.8 KiB
HTML
156 lines
5.8 KiB
HTML
{{template "head" .}}
|
|
{{template "topbar" .}}
|
|
<div class="deck">
|
|
<div class="pane-l-col">
|
|
<div class="float pane-l-head">
|
|
<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>
|
|
<button class="btn btn-icon" id="reguess" title="Re-detect language" type="button">⟳</button>
|
|
</div>
|
|
</div>
|
|
<div class="float 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" style="justify-content:flex-start; gap:6px; align-items:center;"><span>/</span><input type="text" id="custom" placeholder="my-snippet" style="text-align:left; flex:1; min-width:0;"></div>
|
|
</div>
|
|
<div class="float side-section" id="result-card" style="display:none">
|
|
<h3>Result</h3>
|
|
<div class="hint" id="result" style="word-break:break-all">empty</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'; });
|
|
|
|
let guessed = ''; // last auto-detected language, '' = user override
|
|
|
|
function showResult(html, isError) {
|
|
$('result').innerHTML = html;
|
|
$('result').dataset.token = isError ? '' : ($('result').dataset.token || '');
|
|
$('result-card').style.display = 'block';
|
|
}
|
|
function defaultFilename(lang) {
|
|
const names = {
|
|
python: 'Python.py', go: 'main.go', javascript: 'script.js', rust: 'main.rs',
|
|
c: 'main.c', cpp: 'main.cpp', java: 'Main.java', bash: 'script.sh',
|
|
sql: 'query.sql', yaml: 'config.yaml', json: 'data.json',
|
|
markdown: 'notes.md', text: 'Text.txt',
|
|
};
|
|
return names[lang] || '';
|
|
}
|
|
// fill default filename when title is still blank
|
|
function maybeSetDefaultTitle(lang) {
|
|
const title = $('title');
|
|
if (lang && !title.value.trim()) {
|
|
const fn = defaultFilename(lang);
|
|
if (fn) title.value = fn;
|
|
}
|
|
}
|
|
|
|
async function guessLang() {
|
|
if (!content.value.trim()) return;
|
|
try {
|
|
const res = await fetch('/api/guess-language', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({content: content.value}),
|
|
});
|
|
const data = await res.json();
|
|
if (res.ok && data.language) {
|
|
guessed = data.language;
|
|
$('language').value = data.language;
|
|
maybeSetDefaultTitle(data.language);
|
|
}
|
|
} catch(e) {}
|
|
}
|
|
|
|
// refresh button: always re-detect, even if user picked something
|
|
$('reguess').addEventListener('click', guessLang);
|
|
|
|
// auto-guess when pasting into the editor
|
|
content.addEventListener('paste', () => setTimeout(guessLang, 0));
|
|
|
|
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) {
|
|
showResult('Error: ' + (data.error || res.status), true);
|
|
return;
|
|
}
|
|
const url = location.origin + '/' + (data.custom_slug || data.id);
|
|
showResult('<a href="' + url + '">' + url + '</a>', false);
|
|
$('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" .}}
|