Добавить копирование текста и двухосевую прокрутку в превью unwrap.

This commit is contained in:
2026-07-23 12:25:29 +03:00
parent 6b57e2e621
commit e0eceac76c
3 changed files with 70 additions and 13 deletions
+2 -1
View File
@@ -8,6 +8,7 @@
- одноразовая расшифровка — ciphertext удаляется с сервера после открытия
- опциональный пароль: Argon2-проверка до выдачи ciphertext, лимит попыток (по умолчанию 3), пустой пароль попытку не тратит
- подсветка синтаксиса (highlight.js), ручной выбор языка
- после расшифровки: прокрутка текста по вертикали и горизонтали, копирование в буфер обмена
- вложения: drag-and-drop, выбор файлов, вставка скриншота из буфера
- спиннер с логотипом при создании и расшифровке
- RU / EN, светлая и тёмная тема
@@ -45,7 +46,7 @@
### Расшифровка
Одноразовое открытие: ciphertext удаляется на сервере, превью — только в текущей сессии браузера.
Одноразовое открытие: ciphertext удаляется на сервере, превью — только в текущей сессии браузера. Текст с подсветкой прокручивается по обеим осям; рядом — кнопки копирования и скачивания.
| Светлая тема | Тёмная тема |
|:------------:|:-----------:|
+38 -6
View File
@@ -553,7 +553,15 @@ body.busy-open { overflow: hidden; }
min-width: 0;
font-size: 0.9rem;
}
.btn.download-btn {
.item-card-actions {
display: flex;
flex-shrink: 0;
flex-wrap: wrap;
justify-content: flex-end;
gap: 0.4rem;
}
.btn.download-btn,
.btn.copy-btn {
flex-shrink: 0;
gap: 0.35rem;
padding: 0.35rem 0.65rem;
@@ -561,7 +569,8 @@ body.busy-open { overflow: hidden; }
font-size: 0.78rem;
font-weight: 600;
}
.btn.download-btn i {
.btn.download-btn i,
.btn.copy-btn i {
font-size: 0.72rem;
opacity: 0.9;
}
@@ -961,15 +970,38 @@ html[data-theme="light"] .footer-pillars li {
padding: 1rem;
background: var(--input);
}
.item-card pre {
.item-card pre,
.item-card .item-text-pre {
margin: 0.6rem 0 0;
overflow: auto;
max-height: 420px;
max-height: min(60vh, 28rem);
padding: 0.8rem;
border-radius: 8px;
background: rgba(0,0,0,0.25);
overflow-x: auto;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
tab-size: 2;
}
.item-card pre code,
.item-card .item-text-pre code {
display: block;
width: max-content;
min-width: 100%;
margin: 0;
padding: 0;
background: transparent !important;
white-space: pre;
word-break: normal;
overflow-wrap: normal;
font-family: var(--font-mono);
font-size: 0.85rem;
line-height: 1.45;
}
html[data-theme="light"] .item-card pre,
html[data-theme="light"] .item-card .item-text-pre {
background: rgba(16, 32, 56, 0.05);
}
html[data-theme="light"] .item-card pre { background: rgba(16, 32, 56, 0.05); }
.item-card img {
max-width: 100%;
border-radius: 8px;
+30 -6
View File
@@ -120,6 +120,27 @@
return btn;
}
function makeCopyBtn(getText) {
const btn = document.createElement("button");
btn.className = "btn copy-btn";
btn.type = "button";
const label = () =>
`<i class="fa-solid fa-copy" aria-hidden="true"></i><span>${t("common.copy")}</span>`;
btn.innerHTML = label();
btn.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(getText() || "");
btn.innerHTML = `<i class="fa-solid fa-check" aria-hidden="true"></i><span>${t("common.copied")}</span>`;
setTimeout(() => {
btn.innerHTML = label();
}, 1200);
} catch {
/* ignore */
}
});
return btn;
}
function renderPackage(pack) {
els.items.innerHTML = "";
for (const item of pack.items || []) {
@@ -127,23 +148,26 @@
card.className = "item-card";
if (item.type === "text") {
const lang = item.language || "plaintext";
const text = item.content || "";
const head = document.createElement("div");
head.className = "item-card-head";
head.innerHTML = `<div><strong>text</strong> · <span class="mono">${lang}</span></div>`;
head.appendChild(
const actions = document.createElement("div");
actions.className = "item-card-actions";
actions.appendChild(makeCopyBtn(() => text));
actions.appendChild(
makeDownloadBtn(() => {
downloadBlob(
`wrapped-${lang}.txt`,
new Blob([item.content || ""], { type: "text/plain" })
);
downloadBlob(`wrapped-${lang}.txt`, new Blob([text], { type: "text/plain" }));
})
);
head.appendChild(actions);
card.appendChild(head);
const pre = document.createElement("pre");
pre.className = "item-text-pre";
const code = document.createElement("code");
pre.appendChild(code);
card.appendChild(pre);
window.WrappedHighlight.highlightElement(code, item.content || "", lang);
window.WrappedHighlight.highlightElement(code, text, lang);
} else if (item.type === "file") {
const bytes = window.WrappedCrypto.base64ToBytes(item.data_b64);
const blob = new Blob([bytes], { type: item.mime || "application/octet-stream" });