Добавить копирование текста и двухосевую прокрутку в превью unwrap.
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
- одноразовая расшифровка — ciphertext удаляется с сервера после открытия
|
- одноразовая расшифровка — ciphertext удаляется с сервера после открытия
|
||||||
- опциональный пароль: Argon2-проверка до выдачи ciphertext, лимит попыток (по умолчанию 3), пустой пароль попытку не тратит
|
- опциональный пароль: Argon2-проверка до выдачи ciphertext, лимит попыток (по умолчанию 3), пустой пароль попытку не тратит
|
||||||
- подсветка синтаксиса (highlight.js), ручной выбор языка
|
- подсветка синтаксиса (highlight.js), ручной выбор языка
|
||||||
|
- после расшифровки: прокрутка текста по вертикали и горизонтали, копирование в буфер обмена
|
||||||
- вложения: drag-and-drop, выбор файлов, вставка скриншота из буфера
|
- вложения: drag-and-drop, выбор файлов, вставка скриншота из буфера
|
||||||
- спиннер с логотипом при создании и расшифровке
|
- спиннер с логотипом при создании и расшифровке
|
||||||
- RU / EN, светлая и тёмная тема
|
- RU / EN, светлая и тёмная тема
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
|
|
||||||
### Расшифровка
|
### Расшифровка
|
||||||
|
|
||||||
Одноразовое открытие: ciphertext удаляется на сервере, превью — только в текущей сессии браузера.
|
Одноразовое открытие: ciphertext удаляется на сервере, превью — только в текущей сессии браузера. Текст с подсветкой прокручивается по обеим осям; рядом — кнопки копирования и скачивания.
|
||||||
|
|
||||||
| Светлая тема | Тёмная тема |
|
| Светлая тема | Тёмная тема |
|
||||||
|:------------:|:-----------:|
|
|:------------:|:-----------:|
|
||||||
|
|||||||
+38
-6
@@ -553,7 +553,15 @@ body.busy-open { overflow: hidden; }
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
font-size: 0.9rem;
|
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;
|
flex-shrink: 0;
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
padding: 0.35rem 0.65rem;
|
padding: 0.35rem 0.65rem;
|
||||||
@@ -561,7 +569,8 @@ body.busy-open { overflow: hidden; }
|
|||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.btn.download-btn i {
|
.btn.download-btn i,
|
||||||
|
.btn.copy-btn i {
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
@@ -961,15 +970,38 @@ html[data-theme="light"] .footer-pillars li {
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: var(--input);
|
background: var(--input);
|
||||||
}
|
}
|
||||||
.item-card pre {
|
.item-card pre,
|
||||||
|
.item-card .item-text-pre {
|
||||||
margin: 0.6rem 0 0;
|
margin: 0.6rem 0 0;
|
||||||
overflow: auto;
|
max-height: min(60vh, 28rem);
|
||||||
max-height: 420px;
|
|
||||||
padding: 0.8rem;
|
padding: 0.8rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: rgba(0,0,0,0.25);
|
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 {
|
.item-card img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|||||||
+30
-6
@@ -120,6 +120,27 @@
|
|||||||
return btn;
|
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) {
|
function renderPackage(pack) {
|
||||||
els.items.innerHTML = "";
|
els.items.innerHTML = "";
|
||||||
for (const item of pack.items || []) {
|
for (const item of pack.items || []) {
|
||||||
@@ -127,23 +148,26 @@
|
|||||||
card.className = "item-card";
|
card.className = "item-card";
|
||||||
if (item.type === "text") {
|
if (item.type === "text") {
|
||||||
const lang = item.language || "plaintext";
|
const lang = item.language || "plaintext";
|
||||||
|
const text = item.content || "";
|
||||||
const head = document.createElement("div");
|
const head = document.createElement("div");
|
||||||
head.className = "item-card-head";
|
head.className = "item-card-head";
|
||||||
head.innerHTML = `<div><strong>text</strong> · <span class="mono">${lang}</span></div>`;
|
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(() => {
|
makeDownloadBtn(() => {
|
||||||
downloadBlob(
|
downloadBlob(`wrapped-${lang}.txt`, new Blob([text], { type: "text/plain" }));
|
||||||
`wrapped-${lang}.txt`,
|
|
||||||
new Blob([item.content || ""], { type: "text/plain" })
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
head.appendChild(actions);
|
||||||
card.appendChild(head);
|
card.appendChild(head);
|
||||||
const pre = document.createElement("pre");
|
const pre = document.createElement("pre");
|
||||||
|
pre.className = "item-text-pre";
|
||||||
const code = document.createElement("code");
|
const code = document.createElement("code");
|
||||||
pre.appendChild(code);
|
pre.appendChild(code);
|
||||||
card.appendChild(pre);
|
card.appendChild(pre);
|
||||||
window.WrappedHighlight.highlightElement(code, item.content || "", lang);
|
window.WrappedHighlight.highlightElement(code, text, lang);
|
||||||
} else if (item.type === "file") {
|
} else if (item.type === "file") {
|
||||||
const bytes = window.WrappedCrypto.base64ToBytes(item.data_b64);
|
const bytes = window.WrappedCrypto.base64ToBytes(item.data_b64);
|
||||||
const blob = new Blob([bytes], { type: item.mime || "application/octet-stream" });
|
const blob = new Blob([bytes], { type: item.mime || "application/octet-stream" });
|
||||||
|
|||||||
Reference in New Issue
Block a user