Исправлены create UI, PWA-иконки, tooltip A2HS и breakpoint админ-меню 1015px.
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
+35
-37
@@ -178,7 +178,8 @@ html[data-theme="light"] body {
|
||||
50% { filter: saturate(1.2); transform: scale(1.04); }
|
||||
}
|
||||
|
||||
.top-actions { display: flex; gap: 0.5rem; }
|
||||
.top-actions { display: flex; gap: 0.5rem; overflow: visible; position: relative; z-index: 5; }
|
||||
.topbar { overflow: visible; }
|
||||
|
||||
.icon-btn {
|
||||
min-width: 42px;
|
||||
@@ -271,15 +272,22 @@ html[data-theme="dark"] .icon-btn:hover {
|
||||
overflow: visible;
|
||||
}
|
||||
#install-app .ui-tooltip {
|
||||
top: calc(100% + 0.5rem);
|
||||
bottom: auto;
|
||||
left: 50%;
|
||||
right: auto;
|
||||
transform: translateX(-50%) translateY(4px);
|
||||
transform: translateX(-50%) translateY(-4px);
|
||||
white-space: nowrap;
|
||||
}
|
||||
#install-app .ui-tooltip::after {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
right: auto;
|
||||
transform: translateX(-50%);
|
||||
border: 5px solid transparent;
|
||||
border-bottom-color: var(--line);
|
||||
border-top-color: transparent;
|
||||
}
|
||||
#install-app:hover .ui-tooltip,
|
||||
#install-app:focus-visible .ui-tooltip {
|
||||
@@ -287,6 +295,25 @@ html[data-theme="dark"] .icon-btn:hover {
|
||||
visibility: visible;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.datetime-split {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
.datetime-split input {
|
||||
min-width: 0;
|
||||
}
|
||||
.field-label {
|
||||
display: block;
|
||||
margin-bottom: 0.35rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.datetime-split {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.composer, .success-panel, .result-panel {
|
||||
display: grid;
|
||||
@@ -834,51 +861,22 @@ body.busy-open { overflow: hidden; }
|
||||
}
|
||||
|
||||
.file-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.4rem; }
|
||||
.file-list li,
|
||||
.file-list-item {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(5.5rem, 9rem) auto;
|
||||
gap: 0.45rem;
|
||||
.file-list li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
padding: 0.55rem 0.75rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.file-label-input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 0.35rem 0.5rem;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
.file-list button {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--danger);
|
||||
cursor: pointer;
|
||||
}
|
||||
.template-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem;
|
||||
margin: 0 0 0.35rem;
|
||||
}
|
||||
.template-chip {
|
||||
border: 1px solid var(--line);
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
border-radius: 999px;
|
||||
padding: 0.3rem 0.7rem;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
.template-chip:hover,
|
||||
.template-chip:focus-visible {
|
||||
color: var(--accent-2);
|
||||
border-color: rgba(75, 134, 240, 0.4);
|
||||
outline: none;
|
||||
}
|
||||
.success-meta-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -1519,7 +1517,7 @@ html[data-theme="light"] .admin-nav {
|
||||
box-shadow: 0 8px 24px rgba(20, 40, 70, 0.08);
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
@media (max-width: 1015px) {
|
||||
.admin-top {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
@@ -1617,7 +1615,7 @@ html[data-theme="light"] .admin-nav {
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 861px) {
|
||||
@media (min-width: 1016px) {
|
||||
.admin-top > .brand {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@@ -4,7 +4,7 @@
|
||||
const nav = document.getElementById("admin-nav");
|
||||
if (!top || !toggle || !nav) return;
|
||||
|
||||
const mq = window.matchMedia("(max-width: 860px)");
|
||||
const mq = window.matchMedia("(max-width: 1015px)");
|
||||
|
||||
const syncLabel = () => {
|
||||
const open = top.classList.contains("is-nav-open");
|
||||
|
||||
+17
-57
@@ -1,14 +1,12 @@
|
||||
(() => {
|
||||
const t = (k, vars) => window.WrappedI18n.t(k, vars);
|
||||
/** @type {{ file: File, label: string }[]} */
|
||||
/** @type {File[]} */
|
||||
const files = [];
|
||||
let settings = null;
|
||||
let captchaWidgetId = null;
|
||||
|
||||
const els = {
|
||||
text: document.getElementById("payload-text"),
|
||||
textLabel: document.getElementById("text-label"),
|
||||
templateChips: document.getElementById("template-chips"),
|
||||
lang: document.getElementById("text-language"),
|
||||
langChip: document.getElementById("lang-chip"),
|
||||
langChipText: document.getElementById("lang-chip-text"),
|
||||
@@ -18,7 +16,8 @@
|
||||
editor: document.getElementById("code-editor"),
|
||||
ttl: document.getElementById("ttl-seconds"),
|
||||
maxOpens: document.getElementById("max-opens"),
|
||||
availableFrom: document.getElementById("available-from"),
|
||||
availableFromDate: document.getElementById("available-from-date"),
|
||||
availableFromTime: document.getElementById("available-from-time"),
|
||||
password: document.getElementById("password"),
|
||||
generatePassword: document.getElementById("generate-password"),
|
||||
dropzone: document.getElementById("dropzone"),
|
||||
@@ -114,7 +113,7 @@
|
||||
|
||||
function estimatePayloadBytes() {
|
||||
const textBytes = new TextEncoder().encode(els.text?.value || "").length;
|
||||
const fileBytes = files.reduce((sum, entry) => sum + (Number(entry.file.size) || 0), 0);
|
||||
const fileBytes = files.reduce((sum, f) => sum + (Number(f.size) || 0), 0);
|
||||
return textBytes + fileBytes;
|
||||
}
|
||||
|
||||
@@ -142,21 +141,9 @@
|
||||
|
||||
function renderFiles() {
|
||||
els.fileList.innerHTML = "";
|
||||
files.forEach((entry, idx) => {
|
||||
const f = entry.file;
|
||||
files.forEach((f, idx) => {
|
||||
const li = document.createElement("li");
|
||||
li.className = "file-list-item";
|
||||
const meta = document.createElement("span");
|
||||
meta.innerHTML = `${escapeHtml(f.name)} <small>(${escapeHtml(f.type || "file")} · ${window.WrappedUI.formatBytes(f.size)})</small>`;
|
||||
const labelInput = document.createElement("input");
|
||||
labelInput.type = "text";
|
||||
labelInput.className = "file-label-input";
|
||||
labelInput.maxLength = 120;
|
||||
labelInput.placeholder = t("create.itemLabelPlaceholder");
|
||||
labelInput.value = entry.label || "";
|
||||
labelInput.addEventListener("input", () => {
|
||||
entry.label = labelInput.value;
|
||||
});
|
||||
li.innerHTML = `<span>${escapeHtml(f.name)} <small>(${escapeHtml(f.type || "file")} · ${window.WrappedUI.formatBytes(f.size)})</small></span>`;
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
btn.textContent = "×";
|
||||
@@ -164,8 +151,6 @@
|
||||
files.splice(idx, 1);
|
||||
renderFiles();
|
||||
});
|
||||
li.appendChild(meta);
|
||||
li.appendChild(labelInput);
|
||||
li.appendChild(btn);
|
||||
els.fileList.appendChild(li);
|
||||
});
|
||||
@@ -186,7 +171,7 @@
|
||||
showError(t("create.mimeDenied") + `: ${f.type || f.name}`);
|
||||
continue;
|
||||
}
|
||||
files.push({ file: f, label: "" });
|
||||
files.push(f);
|
||||
}
|
||||
renderFiles();
|
||||
}
|
||||
@@ -245,31 +230,11 @@
|
||||
.join("");
|
||||
}
|
||||
|
||||
function renderTemplates() {
|
||||
if (!els.templateChips) return;
|
||||
els.templateChips.innerHTML = "";
|
||||
const keys = [
|
||||
{ id: "access", key: "create.tpl.access" },
|
||||
{ id: "code", key: "create.tpl.code" },
|
||||
{ id: "fileNote", key: "create.tpl.fileNote" },
|
||||
];
|
||||
for (const item of keys) {
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
btn.className = "template-chip";
|
||||
btn.textContent = t(`create.tpl.${item.id}.name`);
|
||||
btn.addEventListener("click", () => {
|
||||
els.text.value = t(`create.tpl.${item.id}.body`);
|
||||
refreshHighlight();
|
||||
refreshSizeMeter();
|
||||
});
|
||||
els.templateChips.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function datetimeLocalToIso(value) {
|
||||
if (!value) return null;
|
||||
const d = new Date(value);
|
||||
function availableFromToIso() {
|
||||
const date = (els.availableFromDate?.value || "").trim();
|
||||
if (!date) return null;
|
||||
const time = (els.availableFromTime?.value || "").trim() || "00:00";
|
||||
const d = new Date(`${date}T${time}`);
|
||||
if (Number.isNaN(d.getTime())) return null;
|
||||
return d.toISOString();
|
||||
}
|
||||
@@ -351,7 +316,6 @@
|
||||
settings = await resp.json();
|
||||
fillTtl();
|
||||
fillMaxOpens();
|
||||
renderTemplates();
|
||||
loadCaptcha();
|
||||
setLanguage("plaintext", { silent: true });
|
||||
refreshHighlight();
|
||||
@@ -525,18 +489,15 @@
|
||||
const items = [];
|
||||
const contentTypes = [];
|
||||
if (text.trim()) {
|
||||
const textItem = {
|
||||
items.push({
|
||||
type: "text",
|
||||
language: els.lang.value,
|
||||
content: text,
|
||||
};
|
||||
const label = (els.textLabel?.value || "").trim();
|
||||
if (label) textItem.label = label.slice(0, 120);
|
||||
items.push(textItem);
|
||||
});
|
||||
contentTypes.push("text/plain");
|
||||
}
|
||||
for (const entry of files) {
|
||||
const item = await window.WrappedCrypto.fileToItem(entry.file, entry.label);
|
||||
for (const f of files) {
|
||||
const item = await window.WrappedCrypto.fileToItem(f);
|
||||
items.push(item);
|
||||
contentTypes.push(item.mime);
|
||||
}
|
||||
@@ -550,7 +511,7 @@
|
||||
|
||||
const password = els.password.value || "";
|
||||
const maxOpens = Number(els.maxOpens?.value || 1);
|
||||
const availableFromIso = datetimeLocalToIso(els.availableFrom?.value || "");
|
||||
const availableFromIso = availableFromToIso();
|
||||
els.wrapBtn.disabled = true;
|
||||
window.WrappedUI.showBusy(t("create.working"));
|
||||
try {
|
||||
@@ -638,7 +599,6 @@
|
||||
window.WrappedI18n.onChange(() => {
|
||||
fillTtl();
|
||||
fillMaxOpens();
|
||||
renderTemplates();
|
||||
refreshExpiresMeta();
|
||||
refreshSuccessBadges();
|
||||
refreshSizeMeter();
|
||||
|
||||
@@ -8,10 +8,28 @@
|
||||
"theme_color": "#0b1020",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/static/favicon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"src": "/static/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/static/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/static/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/static/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -14,11 +14,6 @@
|
||||
</div>
|
||||
|
||||
<label class="sr-only" for="payload-text" data-i18n="create.text">Text</label>
|
||||
<div class="template-chips" id="template-chips" role="group" aria-label="Templates"></div>
|
||||
<div class="field">
|
||||
<label for="text-label" data-i18n="create.itemLabel">Label (optional)</label>
|
||||
<input id="text-label" type="text" maxlength="120" data-i18n-placeholder="create.itemLabelPlaceholder" placeholder="e.g. Instructions" />
|
||||
</div>
|
||||
<div class="code-editor" id="code-editor">
|
||||
<pre class="code-highlight" aria-hidden="true"><code id="code-highlight" class="hljs"></code></pre>
|
||||
<textarea id="payload-text" class="code-input" spellcheck="false" data-i18n-placeholder="create.textPlaceholder" placeholder="Paste secrets, configs, notes…"></textarea>
|
||||
@@ -43,8 +38,11 @@
|
||||
</div>
|
||||
<div class="grid-2">
|
||||
<div class="field">
|
||||
<label for="available-from" data-i18n="create.availableFrom">Available from (optional)</label>
|
||||
<input id="available-from" type="datetime-local" />
|
||||
<span class="field-label" data-i18n="create.availableFrom">Available from (optional)</span>
|
||||
<div class="datetime-split">
|
||||
<input id="available-from-date" type="date" aria-label="Date" />
|
||||
<input id="available-from-time" type="time" step="60" aria-label="Time" />
|
||||
</div>
|
||||
<p class="hint" data-i18n="create.availableFromHint">Empty = available immediately</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
|
||||
Reference in New Issue
Block a user