paste/index.html
Leo 4d896adcdb Fix bottom nav bar hidden on mobile
Use 100dvh (dynamic viewport height) so the layout accounts for mobile
browser chrome (address bar, navigation bar), with 100vh as fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 20:42:44 +02:00

348 lines
8.7 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Paste</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg-primary: #1e1e1e;
--bg-secondary: #252526;
--bg-tertiary: #333333;
--text-primary: #d4d4d4;
--text-secondary: #858585;
--accent: #007acc;
--border: #404040;
--line-num-bg: #1e1e1e;
--line-num-text: #858585;
}
body.invert {
--bg-primary: #ffffff;
--bg-secondary: #f3f3f3;
--bg-tertiary: #e0e0e0;
--text-primary: #333333;
--text-secondary: #666666;
--accent: #0066cc;
--border: #cccccc;
--line-num-bg: #f8f8f8;
--line-num-text: #999999;
}
body {
background: var(--bg-primary);
color: var(--text-primary);
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
height: 100vh;
height: 100dvh;
display: flex;
flex-direction: column;
overflow: hidden;
}
#editor-container {
flex: 1;
display: flex;
overflow: hidden;
}
#line-numbers {
background: var(--line-num-bg);
color: var(--line-num-text);
padding: 12px 8px;
text-align: right;
user-select: none;
font-size: 14px;
line-height: 1.5;
min-width: 50px;
overflow: hidden;
border-right: 1px solid var(--border);
}
#plaintext {
flex: 1;
background: var(--bg-primary);
color: var(--text-primary);
border: none;
padding: 12px;
font-family: inherit;
font-size: 14px;
line-height: 1.5;
resize: none;
outline: none;
overflow: auto;
white-space: pre;
tab-size: 4;
}
#nav {
background: var(--bg-tertiary);
padding: 8px 12px;
display: flex;
align-items: center;
gap: 10px;
border-top: 1px solid var(--border);
flex-wrap: wrap;
}
.btn {
background: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid var(--border);
padding: 6px 12px;
font-family: inherit;
font-size: 13px;
cursor: pointer;
border-radius: 3px;
}
.btn:hover {
background: var(--accent);
border-color: var(--accent);
}
#url-output {
flex: 1;
background: var(--bg-primary);
color: var(--text-primary);
border: 1px solid var(--border);
padding: 6px 10px;
font-family: inherit;
font-size: 13px;
border-radius: 3px;
min-width: 200px;
}
.url-warning {
color: #ff6b6b;
font-size: 12px;
margin-left: 8px;
}
#status {
color: var(--text-secondary);
font-size: 12px;
margin-left: auto;
}
.hidden {
display: none !important;
}
@media (max-width: 600px) {
#line-numbers {
font-size: 12px;
min-width: 36px;
padding: 10px 6px;
}
#plaintext {
font-size: 12px;
padding: 10px;
}
#nav {
padding: 8px;
gap: 8px;
}
.btn {
padding: 8px 12px;
font-size: 13px;
}
#url-output {
min-width: 0;
width: 100%;
font-size: 12px;
}
#status {
margin-left: 0;
width: 100%;
}
}
</style>
<script src="lzma.js"></script>
</head>
<body>
<div id="editor-container">
<div id="line-numbers">1</div>
<textarea id="plaintext" spellcheck="false" placeholder="Paste your text or code here..."></textarea>
</div>
<div id="nav">
<button class="btn" id="btn-generate">Generate URL</button>
<button class="btn" id="btn-copy-content">Copy Content</button>
<button class="btn" id="btn-invert">Invert Colors</button>
<input type="text" id="url-output" class="hidden" readonly placeholder="URL will appear here"/>
<button class="btn hidden" id="btn-copy-url">Copy URL</button>
<span id="url-warning" class="url-warning hidden">Warning: URL is long and may not work in all browsers</span>
<span id="status"></span>
</div>
<script>
var lzma = new LZMA("lzma_worker.js");
var URL_MAX_LENGTH = 8000;
document.addEventListener('DOMContentLoaded', function(){
loadPreferences();
document.getElementById("plaintext").focus();
var base64 = location.hash.substr(1);
if (base64.length > 0) {
setStatus("Loading...");
decompressFromURL(base64);
}
setupEventListeners();
});
function setupEventListeners() {
var textarea = document.getElementById("plaintext");
var lineNumbers = document.getElementById("line-numbers");
textarea.addEventListener('input', updateLineNumbers);
textarea.addEventListener('scroll', syncScroll);
textarea.addEventListener('keydown', handleTab);
document.getElementById("btn-generate").addEventListener('click', function(){ generateURL('raw'); });
document.getElementById("btn-copy-content").addEventListener('click', copyContent);
document.getElementById("btn-invert").addEventListener('click', toggleInvert);
document.getElementById("btn-copy-url").addEventListener('click', copyURL);
}
function updateLineNumbers() {
var textarea = document.getElementById("plaintext");
var lineNumbers = document.getElementById("line-numbers");
var lines = textarea.value.split('\n');
var nums = [];
for (var i = 1; i <= lines.length; i++) {
nums.push(i);
}
lineNumbers.innerHTML = nums.join('<br>');
}
function syncScroll() {
var textarea = document.getElementById("plaintext");
var lineNumbers = document.getElementById("line-numbers");
lineNumbers.scrollTop = textarea.scrollTop;
}
function handleTab(e) {
if (e.key === 'Tab') {
e.preventDefault();
var textarea = document.getElementById("plaintext");
var start = textarea.selectionStart;
var end = textarea.selectionEnd;
textarea.value = textarea.value.substring(0, start) + ' ' + textarea.value.substring(end);
textarea.selectionStart = textarea.selectionEnd = start + 4;
updateLineNumbers();
}
}
function decompressFromURL(base64) {
if (!fetch) {
setStatus("Browser not supported");
return;
}
fetch("data:application/octet-stream;base64," + base64)
.then(function(r) { return r.blob(); })
.then(function(blob) {
var reader = new FileReader();
reader.onload = function() {
var compressed = Array.from(new Uint8Array(reader.result));
lzma.decompress(compressed, function(plaintext, error) {
if (error) {
setStatus("Failed to decompress: " + error);
return;
}
document.getElementById("plaintext").value = plaintext;
updateLineNumbers();
setStatus("Loaded");
});
};
reader.readAsArrayBuffer(blob);
})
.catch(function(err) {
setStatus("Failed to load: " + err);
});
}
function generateURL(format) {
var plaintext = document.getElementById("plaintext").value;
if (!plaintext) {
setStatus("Nothing to encode");
return;
}
setStatus("Compressing...");
lzma.compress(plaintext, 1, function(compressed, error) {
if (error) {
setStatus("Compression failed: " + error);
return;
}
var reader = new FileReader();
reader.onload = function() {
var base64 = reader.result.substr(reader.result.indexOf(",") + 1);
var url = location.protocol + "//" + location.host + location.pathname + "#" + base64;
var urlOutput = document.getElementById("url-output");
var copyBtn = document.getElementById("btn-copy-url");
var warning = document.getElementById("url-warning");
urlOutput.value = url;
urlOutput.classList.remove("hidden");
copyBtn.classList.remove("hidden");
if (url.length > URL_MAX_LENGTH) {
warning.classList.remove("hidden");
} else {
warning.classList.add("hidden");
}
setStatus("URL generated (" + url.length + " chars)");
};
reader.readAsDataURL(new Blob([new Uint8Array(compressed)]));
});
}
function copyContent() {
var textarea = document.getElementById("plaintext");
if (!textarea.value) {
setStatus("Nothing to copy");
return;
}
navigator.clipboard.writeText(textarea.value).then(function() {
setStatus("Content copied!");
}).catch(function() {
textarea.select();
document.execCommand('copy');
setStatus("Content copied!");
});
}
function copyURL() {
var urlOutput = document.getElementById("url-output");
navigator.clipboard.writeText(urlOutput.value).then(function() {
setStatus("URL copied!");
}).catch(function() {
urlOutput.select();
document.execCommand('copy');
setStatus("URL copied!");
});
}
function toggleInvert() {
var isInverted = document.body.classList.toggle("invert");
savePreference("invert", isInverted ? "1" : "0");
setStatus(isInverted ? "Light mode" : "Dark mode");
}
function loadPreferences() {
var matches;
if (matches = /(?:^|;)invert=([01])(?:;|$)/.exec(document.cookie)) {
if (matches[1] === "1") {
document.body.classList.add("invert");
}
}
}
function savePreference(name, value) {
document.cookie = name + "=" + value + ";max-age=63072000;path=/";
}
function setStatus(msg) {
document.getElementById("status").textContent = msg;
}
</script>
</body>
</html>