Update -> refactor and optimize UI , code ,...

This commit is contained in:
2026-04-10 11:35:25 +03:30
parent 3327207f05
commit 0de951fd91
20 changed files with 1085 additions and 282 deletions

View File

@@ -1,83 +1,512 @@
* {
/* ─── Reset & Base ─── */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: monospace;
}
:root {
--bg: #080e1a;
--surface: #0d1526;
--surface-2: #111d33;
--border: #1e2f4a;
--border-soft: #172137;
--accent: #3b9eff;
--accent-glow: rgba(59,158,255,0.18);
--accent-dark: #1a6fd4;
--text: #dce8f8;
--text-muted: #5f7da0;
--text-dim: #3a5272;
--success: #22c55e;
--error: #f43f5e;
--error-bg: rgba(244,63,94,0.1);
--radius: 12px;
--radius-sm: 8px;
--font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
--font-sans: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
--shadow: 0 4px 24px rgba(0,0,0,0.4);
--shadow-lg: 0 8px 48px rgba(0,0,0,0.6);
}
html { font-size: 15px; }
body {
background: #0f172a;
color: #e2e8f0;
padding: 40px;
background: var(--bg);
color: var(--text);
font-family: var(--font-sans);
min-height: 100vh;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
/* container */
.container {
max-width: 900px;
margin: auto;
/* ─── Page Layout ─── */
.page-wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
max-width: 760px;
margin: 0 auto;
padding: 0 1.25rem;
}
/* title */
h1 {
margin-bottom: 20px;
font-size: 28px;
/* ─── Header ─── */
.site-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.4rem 0;
border-bottom: 1px solid var(--border-soft);
margin-bottom: 2.5rem;
}
/* textarea */
textarea {
width: 100%;
min-height: 300px;
background: #020617;
border: 1px solid #334155;
color: #e2e8f0;
padding: 12px;
resize: vertical;
font-size: 14px;
border-radius: 6px;
}
.usepassword,
select {
background: #020617;
border: 1px solid #334155;
color: #e2e8f0;
padding: 8px;
border-radius: 6px;
margin-top: 10px;
}
/* button */
button {
background: #38bdf8;
border: none;
color: #020617;
padding: 10px 16px;
margin-top: 15px;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
}
button:hover {
background: #0ea5e9;
}
/* paste display */
.paste-box {
background: #020617;
border: 1px solid #334155;
padding: 15px;
margin-top: 20px;
border-radius: 6px;
overflow-x: auto;
}
/* link */
a {
color: #38bdf8;
.logo {
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: 700;
font-size: 1.05rem;
letter-spacing: -0.01em;
color: var(--text);
text-decoration: none;
}
a:hover {
text-decoration: underline;
.logo svg { color: var(--accent); }
.header-badge {
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--accent);
background: var(--accent-glow);
border: 1px solid rgba(59,158,255,0.25);
padding: 0.28rem 0.65rem;
border-radius: 999px;
}
.btn-new-paste {
font-size: 0.82rem;
font-weight: 600;
color: var(--text);
background: var(--surface-2);
border: 1px solid var(--border);
padding: 0.45rem 1rem;
border-radius: var(--radius-sm);
text-decoration: none;
transition: border-color 0.18s, background 0.18s;
}
.btn-new-paste:hover {
border-color: var(--accent);
background: var(--accent-glow);
text-decoration: none;
}
/* ─── Main Card ─── */
.main-card {
flex: 1;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 2rem 2.25rem;
box-shadow: var(--shadow);
}
.card-header {
margin-bottom: 1.75rem;
}
.card-header h1 {
font-size: 1.45rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--text);
margin-bottom: 0.3rem;
}
.card-header p {
font-size: 0.875rem;
color: var(--text-muted);
}
/* ─── Form Fields ─── */
.field { margin-bottom: 1rem; }
.textarea-wrapper { position: relative; }
textarea {
width: 100%;
min-height: 280px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text);
font-family: var(--font-mono);
font-size: 0.875rem;
line-height: 1.7;
padding: 1rem 1.1rem 2.5rem;
resize: vertical;
outline: none;
transition: border-color 0.18s, box-shadow 0.18s;
tab-size: 4;
}
textarea:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-glow);
}
textarea::placeholder { color: var(--text-dim); }
.char-counter {
position: absolute;
bottom: 0.6rem;
right: 0.85rem;
font-size: 0.72rem;
color: var(--text-dim);
font-family: var(--font-mono);
pointer-events: none;
}
/* ─── Options Row ─── */
.options-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-bottom: 1.25rem;
}
.field-group {
display: flex;
flex-direction: column;
gap: 0.45rem;
}
.field-group label {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.78rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-muted);
}
select,
input[type="password"],
input[type="text"] {
width: 100%;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text);
font-family: var(--font-sans);
font-size: 0.875rem;
padding: 0.6rem 0.85rem;
outline: none;
transition: border-color 0.18s, box-shadow 0.18s;
appearance: none;
-webkit-appearance: none;
}
select {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%235f7da0' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.75rem center;
padding-right: 2.2rem;
}
select:focus,
input[type="password"]:focus,
input[type="text"]:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-glow);
}
select option { background: var(--surface-2); }
/* ─── Buttons ─── */
.btn-primary {
display: inline-flex;
align-items: center;
gap: 0.5rem;
background: var(--accent);
color: #fff;
border: none;
border-radius: var(--radius-sm);
padding: 0.7rem 1.4rem;
font-family: var(--font-sans);
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
text-decoration: none;
transition: background 0.18s, transform 0.1s, box-shadow 0.18s;
}
.btn-primary:hover {
background: var(--accent-dark);
box-shadow: 0 0 20px var(--accent-glow);
text-decoration: none;
}
.btn-primary:active { transform: scale(0.98); }
.btn-primary:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-icon {
display: inline-flex;
align-items: center;
gap: 0.4rem;
background: var(--surface-2);
color: var(--text-muted);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 0.4rem 0.85rem;
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
transition: color 0.18s, border-color 0.18s, background 0.18s;
}
.btn-icon:hover {
color: var(--accent);
border-color: var(--accent);
background: var(--accent-glow);
}
/* ─── Result Box ─── */
.result-box {
margin-top: 1.5rem;
background: var(--surface-2);
border: 1px solid var(--border);
border-left: 3px solid var(--success);
border-radius: var(--radius-sm);
padding: 1.25rem 1.4rem;
}
.result-box[hidden] { display: none; }
.result-header {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.9rem;
font-weight: 600;
color: var(--success);
margin-bottom: 1rem;
}
.result-link-row {
display: flex;
gap: 0.5rem;
margin-bottom: 0.85rem;
}
.result-link-row input[type="text"] {
flex: 1;
font-family: var(--font-mono);
font-size: 0.8rem;
color: var(--text-muted);
cursor: text;
}
.btn-copy {
display: inline-flex;
align-items: center;
gap: 0.4rem;
background: var(--surface);
color: var(--text);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 0.5rem 1rem;
font-size: 0.82rem;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
transition: background 0.18s, border-color 0.18s, color 0.18s;
}
.btn-copy:hover {
border-color: var(--accent);
color: var(--accent);
}
.btn-copy.copied {
color: var(--success);
border-color: var(--success);
}
.result-open-link {
display: inline-flex;
align-items: center;
gap: 0.3rem;
font-size: 0.8rem;
color: var(--text-muted);
text-decoration: none;
transition: color 0.18s;
}
.result-open-link:hover {
color: var(--accent);
text-decoration: none;
}
/* ─── Paste View ─── */
.paste-meta {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1.25rem;
}
.meta-badge {
display: inline-flex;
align-items: center;
gap: 0.35rem;
font-size: 0.75rem;
font-weight: 600;
color: var(--text-muted);
background: var(--surface-2);
border: 1px solid var(--border);
padding: 0.28rem 0.65rem;
border-radius: 999px;
}
.paste-box {
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
overflow: hidden;
}
.paste-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.6rem 0.85rem;
border-bottom: 1px solid var(--border);
background: var(--surface-2);
}
.paste-toolbar-title {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-dim);
}
#pasteContent {
font-family: var(--font-mono);
font-size: 0.875rem;
line-height: 1.75;
color: var(--text);
padding: 1.25rem 1.4rem;
white-space: pre-wrap;
word-break: break-word;
overflow-x: auto;
margin: 0;
}
/* ─── Password Prompt ─── */
.lock-icon {
display: flex;
align-items: center;
justify-content: center;
width: 56px;
height: 56px;
background: var(--accent-glow);
border: 1px solid rgba(59,158,255,0.3);
border-radius: 14px;
margin-bottom: 1.25rem;
color: var(--accent);
}
.password-form { max-width: 380px; }
.input-password {
width: 100%;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text);
font-size: 0.9rem;
padding: 0.7rem 0.95rem;
outline: none;
margin-bottom: 1rem;
transition: border-color 0.18s, box-shadow 0.18s;
}
.input-password:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-glow);
}
/* ─── Alerts ─── */
.alert {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
border-radius: var(--radius-sm);
font-size: 0.85rem;
font-weight: 500;
margin-bottom: 1rem;
}
.alert-error {
background: var(--error-bg);
border: 1px solid rgba(244,63,94,0.3);
color: var(--error);
}
/* ─── Error Page ─── */
.error-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 4rem 2rem;
min-height: 320px;
}
.error-code {
font-size: 5rem;
font-weight: 800;
letter-spacing: -0.04em;
color: var(--border);
line-height: 1;
margin-bottom: 0.75rem;
}
.error-message {
font-size: 1rem;
color: var(--text-muted);
max-width: 340px;
}
/* ─── Footer ─── */
.site-footer {
padding: 1.5rem 0;
margin-top: 2rem;
text-align: center;
font-size: 0.75rem;
color: var(--text-dim);
border-top: 1px solid var(--border-soft);
}
/* ─── Submit button loading state ─── */
.btn-primary.loading { opacity: 0.7; pointer-events: none; }
/* ─── Responsive ─── */
@media (max-width: 560px) {
.main-card { padding: 1.5rem 1.25rem; }
.options-row { grid-template-columns: 1fr; }
.result-link-row { flex-direction: column; }
.btn-copy { width: 100%; justify-content: center; }
}

View File

@@ -1,38 +1,106 @@
document.addEventListener("DOMContentLoaded", () => {
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById("pasteForm");
const resultBox = document.getElementById("result");
/* ── Create-paste page ── */
const pasteForm = document.getElementById('pasteForm');
const resultBox = document.getElementById('result');
const pasteText = document.getElementById('pasteText');
const charCount = document.getElementById('charCount');
const submitBtn = document.getElementById('submitBtn');
form.addEventListener("submit", async (e) => {
e.preventDefault();
if (pasteText && charCount) {
const update = () => {
charCount.textContent = pasteText.value.length.toLocaleString();
pasteText.style.height = 'auto';
pasteText.style.height = Math.max(280, pasteText.scrollHeight) + 'px';
};
pasteText.addEventListener('input', update);
update();
}
const formData = new FormData(form);
if (pasteForm) {
pasteForm.addEventListener('submit', async (e) => {
e.preventDefault();
const response = await fetch("/index.php?action=save", {
method: "POST",
body: formData
if (!pasteText || pasteText.value.trim() === '') {
pasteText.focus();
pasteText.style.borderColor = 'var(--error)';
setTimeout(() => pasteText.style.borderColor = '', 1200);
return;
}
submitBtn.classList.add('loading');
submitBtn.querySelector('span').textContent = 'Creating...';
try {
const res = await fetch('/index.php?action=save', {
method: 'POST',
body: new FormData(pasteForm),
});
const data = await res.json();
if (!data.success) {
showError(data.message || 'Something went wrong.');
return;
}
const linkInput = document.getElementById('pasteLink');
const viewLink = document.getElementById('viewLink');
linkInput.value = data.url;
viewLink.href = data.url;
resultBox.removeAttribute('hidden');
resultBox.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
pasteText.value = '';
if (charCount) charCount.textContent = '0';
} catch {
showError('Network error. Please try again.');
} finally {
submitBtn.classList.remove('loading');
submitBtn.querySelector('span').textContent = 'Create Secure Link';
}
});
const data = await response.json();
if (!data.success) {
resultBox.innerHTML = "<div class='error'>" + data.message + "</div>";
return;
function showError(msg) {
resultBox.removeAttribute('hidden');
resultBox.style.borderLeftColor = 'var(--error)';
resultBox.innerHTML = `
<div class="alert alert-error">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
${msg}
</div>`;
}
}
resultBox.innerHTML = `
<h3>Paste Created</h3>
<input type="text" id="pasteLink" value="${data.url}" readonly style="width:100%; padding:8px;">
<button id="copyBtn">Copy Link</button>
`;
document.getElementById("copyBtn").addEventListener("click", () => {
const input = document.getElementById("pasteLink");
navigator.clipboard.writeText(input.value);
alert("Link copied!");
});
/* ── Copy link button (result box) ── */
document.addEventListener('click', (e) => {
const btn = e.target.closest('#copyLinkBtn');
if (!btn) return;
const val = document.getElementById('pasteLink')?.value;
if (!val) return;
copyToClipboard(val, btn, 'Copied!', 'Copy');
});
/* ── View-paste page: copy content ── */
const copyBtn = document.getElementById('copyBtn');
if (copyBtn) {
copyBtn.addEventListener('click', () => {
const content = document.getElementById('pasteContent')?.innerText;
if (!content) return;
copyToClipboard(content, copyBtn, 'Copied!', 'Copy');
});
}
/* ── Shared helper ── */
function copyToClipboard(text, btn, successLabel, defaultLabel) {
navigator.clipboard.writeText(text).then(() => {
const span = btn.querySelector('span') || btn;
btn.classList.add('copied');
span.textContent = successLabel;
setTimeout(() => {
btn.classList.remove('copied');
span.textContent = defaultLabel;
}, 2000);
});
}
});

View File

@@ -1,40 +1 @@
document.addEventListener("DOMContentLoaded", () => {
const textarea = document.querySelector("textarea");
const form = document.querySelector("form");
const copyBtn = document.getElementById("copyBtn");
if (textarea) {
textarea.addEventListener("input", () => {
textarea.style.height = "auto";
textarea.style.height = textarea.scrollHeight + "px";
});
}
if (form && textarea) {
form.addEventListener("submit", (e) => {
if (textarea.value.trim() === "") {
e.preventDefault();
alert("Paste cannot be empty");
}
});
}
if (copyBtn) {
copyBtn.addEventListener("click", () => {
const paste = document.getElementById("pasteContent");
if (!paste) return;
navigator.clipboard.writeText(paste.innerText)
.then(() => {
copyBtn.textContent = "Copied!";
setTimeout(() => {
copyBtn.textContent = "Copy";
}, 2000);
});
});
}
});
/* merged into app.js */