Убрана кнопка A2HS и ссылка «Как проверить» из футера; ссылка в модалке оформлена карточкой.
This commit is contained in:
@@ -343,7 +343,7 @@ services:
|
|||||||
- После создания: **QR** на share-link, иконки **скачать QR (PNG)** и **Web Share** (если есть `navigator.share`) под QR; отдельные кнопки Copy для ссылки / токена / пароля; пароль не советуется слать в той же переписке.
|
- После создания: **QR** на share-link, иконки **скачать QR (PNG)** и **Web Share** (если есть `navigator.share`) под QR; отдельные кнопки Copy для ссылки / токена / пароля; пароль не советуется слать в той же переписке.
|
||||||
- Create: счётчик размера `≈ used / max`; **число открытий** 1–3 (потолок в админке); опционально **«доступно с»** (дата + время); человеческие TTL (в т.ч. «до вечера»).
|
- Create: счётчик размера `≈ used / max`; **число открытий** 1–3 (потолок в админке); опционально **«доступно с»** (дата + время); человеческие TTL (в т.ч. «до вечера»).
|
||||||
- Unwrap: Enter в поле пароля; focus+select при ошибках пароля; zip all; trust-строка; экран **ещё недоступно** до `available_from`; при N>1 ciphertext остаётся до последнего открытия.
|
- Unwrap: Enter в поле пароля; focus+select при ошибках пароля; zip all; trust-строка; экран **ещё недоступно** до `available_from`; при N>1 ciphertext остаётся до последнего открытия.
|
||||||
- Картинки: lightbox. Тема: `prefers-color-scheme` при первом визите; haptic на Copy. PWA manifest + кнопка **На экран Домой** (Chrome install / iOS подсказка).
|
- Картинки: lightbox. Тема: `prefers-color-scheme` при первом визите; haptic на Copy. PWA manifest.
|
||||||
- Страница [`/verify`](/verify) — как проверить ZK-модель.
|
- Страница [`/verify`](/verify) — как проверить ZK-модель.
|
||||||
- UI EN/RU. Статика с `?v=версия.mtime`.
|
- UI EN/RU. Статика с `?v=версия.mtime`.
|
||||||
|
|
||||||
|
|||||||
+57
-28
@@ -267,34 +267,6 @@ html[data-theme="dark"] .icon-btn:hover {
|
|||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
#install-app {
|
|
||||||
position: relative;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
#install-app .ui-tooltip {
|
|
||||||
top: calc(100% + 0.5rem);
|
|
||||||
bottom: auto;
|
|
||||||
left: 50%;
|
|
||||||
right: auto;
|
|
||||||
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 {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
.datetime-split {
|
.datetime-split {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
@@ -1141,6 +1113,63 @@ html[data-theme="light"] .about-version {
|
|||||||
font-size: 0.92rem;
|
font-size: 0.92rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
.about-verify-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
padding: 0.75rem 0.85rem;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid rgba(61, 214, 198, 0.28);
|
||||||
|
background: linear-gradient(135deg, rgba(61, 214, 198, 0.1), rgba(110, 168, 255, 0.08));
|
||||||
|
color: var(--text);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: border-color 0.15s, background 0.15s, transform 0.15s;
|
||||||
|
}
|
||||||
|
.about-verify-link:hover,
|
||||||
|
.about-verify-link:focus-visible {
|
||||||
|
border-color: rgba(110, 168, 255, 0.45);
|
||||||
|
background: linear-gradient(135deg, rgba(61, 214, 198, 0.14), rgba(110, 168, 255, 0.14));
|
||||||
|
outline: none;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
.about-verify-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 2.25rem;
|
||||||
|
height: 2.25rem;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(61, 214, 198, 0.14);
|
||||||
|
color: var(--accent);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
.about-verify-text {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.15rem;
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.about-verify-text strong {
|
||||||
|
font-size: 0.92rem;
|
||||||
|
font-weight: 650;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.about-verify-text span {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
.about-verify-arrow {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--accent-2);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
html[data-theme="light"] .about-verify-link {
|
||||||
|
border-color: rgba(47, 111, 237, 0.22);
|
||||||
|
background: linear-gradient(135deg, rgba(14, 160, 140, 0.08), rgba(47, 111, 237, 0.08));
|
||||||
|
}
|
||||||
.about-modal-panel .modal-actions {
|
.about-modal-panel .modal-actions {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-10
@@ -106,11 +106,8 @@
|
|||||||
"verify.s5.title": "Available from",
|
"verify.s5.title": "Available from",
|
||||||
"verify.s5.body": "If \"available from\" is set, unwrap is rejected until that time. After that, normal open/expiry rules apply.",
|
"verify.s5.body": "If \"available from\" is set, unwrap is rejected until that time. After that, normal open/expiry rules apply.",
|
||||||
"verify.createCta": "Create a wrap",
|
"verify.createCta": "Create a wrap",
|
||||||
"about.verifyLink": "How to verify →",
|
"about.verifyLink": "How to verify",
|
||||||
"footer.verify": "How to verify",
|
"about.verifyHint": "What the server sees and how the #key works",
|
||||||
"install.aria": "Add to Home Screen",
|
|
||||||
"install.tip": "Install Wrapped",
|
|
||||||
"install.iosTip": "Share → Add to Home Screen",
|
|
||||||
"admin.limits.maxOpens": "Max opens per wrap",
|
"admin.limits.maxOpens": "Max opens per wrap",
|
||||||
"admin.limits.maxOpensHint": "Ceiling for create UI (1–10). Default: 3.",
|
"admin.limits.maxOpensHint": "Ceiling for create UI (1–10). Default: 3.",
|
||||||
"create.ttl.default": "Default ({seconds} s)",
|
"create.ttl.default": "Default ({seconds} s)",
|
||||||
@@ -413,11 +410,8 @@
|
|||||||
"verify.s5.title": "Доступно с",
|
"verify.s5.title": "Доступно с",
|
||||||
"verify.s5.body": "Если задано «доступно с», unwrap отклоняется до этого момента. Дальше действуют обычные правила открытий и срока.",
|
"verify.s5.body": "Если задано «доступно с», unwrap отклоняется до этого момента. Дальше действуют обычные правила открытий и срока.",
|
||||||
"verify.createCta": "Создать wrap",
|
"verify.createCta": "Создать wrap",
|
||||||
"about.verifyLink": "Как проверить →",
|
"about.verifyLink": "Как проверить",
|
||||||
"footer.verify": "Как проверить",
|
"about.verifyHint": "Что видит сервер и как работает ключ в #…",
|
||||||
"install.aria": "На экран «Домой»",
|
|
||||||
"install.tip": "Установить Wrapped",
|
|
||||||
"install.iosTip": "Поделиться → На экран «Домой»",
|
|
||||||
"admin.limits.maxOpens": "Макс. открытий на wrap",
|
"admin.limits.maxOpens": "Макс. открытий на wrap",
|
||||||
"admin.limits.maxOpensHint": "Потолок для UI создания (1–10). По умолчанию: 3.",
|
"admin.limits.maxOpensHint": "Потолок для UI создания (1–10). По умолчанию: 3.",
|
||||||
"create.ttl.default": "По умолчанию ({seconds} с)",
|
"create.ttl.default": "По умолчанию ({seconds} с)",
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
(() => {
|
|
||||||
const t = (k, vars) => window.WrappedI18n?.t(k, vars) || k;
|
|
||||||
const btn = document.getElementById("install-app");
|
|
||||||
if (!btn) return;
|
|
||||||
|
|
||||||
let deferredPrompt = null;
|
|
||||||
const isIos =
|
|
||||||
/iphone|ipad|ipod/i.test(navigator.userAgent) ||
|
|
||||||
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
|
|
||||||
const isStandalone =
|
|
||||||
window.matchMedia("(display-mode: standalone)").matches ||
|
|
||||||
window.navigator.standalone === true;
|
|
||||||
|
|
||||||
function syncLabels() {
|
|
||||||
btn.setAttribute("aria-label", t("install.aria"));
|
|
||||||
const tip = btn.querySelector(".ui-tooltip");
|
|
||||||
if (tip) tip.textContent = t(isIos ? "install.iosTip" : "install.tip");
|
|
||||||
}
|
|
||||||
|
|
||||||
function showBtn() {
|
|
||||||
if (isStandalone) {
|
|
||||||
btn.classList.add("hidden");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
btn.classList.remove("hidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("beforeinstallprompt", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
deferredPrompt = e;
|
|
||||||
showBtn();
|
|
||||||
syncLabels();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isIos && !isStandalone) {
|
|
||||||
showBtn();
|
|
||||||
}
|
|
||||||
|
|
||||||
btn.addEventListener("click", async () => {
|
|
||||||
if (deferredPrompt) {
|
|
||||||
deferredPrompt.prompt();
|
|
||||||
try {
|
|
||||||
await deferredPrompt.userChoice;
|
|
||||||
} catch {
|
|
||||||
/* ignore */
|
|
||||||
}
|
|
||||||
deferredPrompt = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isIos) {
|
|
||||||
window.WrappedUI?.showBusy?.(t("install.iosTip"));
|
|
||||||
setTimeout(() => window.WrappedUI?.hideBusy?.(), 2200);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (window.WrappedI18n?.onChange) {
|
|
||||||
window.WrappedI18n.onChange(syncLabels);
|
|
||||||
}
|
|
||||||
syncLabels();
|
|
||||||
})();
|
|
||||||
+10
-8
@@ -31,11 +31,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="top-actions">
|
<div class="top-actions">
|
||||||
<button type="button" class="icon-btn hidden" id="install-app" aria-describedby="install-app-tip">
|
|
||||||
<i class="fa-solid fa-mobile-screen-button" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only" data-i18n="install.aria">Add to Home Screen</span>
|
|
||||||
<span class="ui-tooltip" id="install-app-tip" role="tooltip" data-i18n="install.tip">Add to Home Screen</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="icon-btn" id="lang-toggle" title="Language" aria-label="Language">
|
<button type="button" class="icon-btn" id="lang-toggle" title="Language" aria-label="Language">
|
||||||
<span id="lang-label">RU</span>
|
<span id="lang-label">RU</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -55,7 +50,6 @@
|
|||||||
<p class="footer-copy">
|
<p class="footer-copy">
|
||||||
© <span data-i18n="footer.copy.author">Сергей Антропов</span>
|
© <span data-i18n="footer.copy.author">Сергей Антропов</span>
|
||||||
· <a href="https://devops.org.ru" target="_blank" rel="noopener noreferrer">devops.org.ru</a>
|
· <a href="https://devops.org.ru" target="_blank" rel="noopener noreferrer">devops.org.ru</a>
|
||||||
· <a href="/verify" data-i18n="footer.verify">How to verify</a>
|
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
@@ -71,7 +65,16 @@
|
|||||||
<p data-i18n="about.p2">Можно отправить заметку или код, а также вложения: документы, архивы, скриншоты (drag-and-drop, выбор с диска или вставка из буфера). И текст, и файлы шифруются в браузере до загрузки — на сервер уходит только ciphertext.</p>
|
<p data-i18n="about.p2">Можно отправить заметку или код, а также вложения: документы, архивы, скриншоты (drag-and-drop, выбор с диска или вставка из буфера). И текст, и файлы шифруются в браузере до загрузки — на сервер уходит только ciphertext.</p>
|
||||||
<p data-i18n="about.p3">Сервер никогда не видит plaintext: зашифрованные данные лежат на сервере до тех пор, пока получатель не откроет ссылку с ключом и не расшифрует пакет.</p>
|
<p data-i18n="about.p3">Сервер никогда не видит plaintext: зашифрованные данные лежат на сервере до тех пор, пока получатель не откроет ссылку с ключом и не расшифрует пакет.</p>
|
||||||
<p data-i18n="about.p4">После успешной расшифровки копия на сервере уничтожается. Ключ шифрования живёт во фрагменте URL (#…) и не уходит на сервер вместе с запросом страницы. При желании wrap можно дополнительно защитить паролем.</p>
|
<p data-i18n="about.p4">После успешной расшифровки копия на сервере уничтожается. Ключ шифрования живёт во фрагменте URL (#…) и не уходит на сервер вместе с запросом страницы. При желании wrap можно дополнительно защитить паролем.</p>
|
||||||
<p><a href="/verify" data-i18n="about.verifyLink">How to verify →</a></p>
|
<a class="about-verify-link" href="/verify">
|
||||||
|
<span class="about-verify-icon" aria-hidden="true">
|
||||||
|
<i class="fa-solid fa-shield-halved"></i>
|
||||||
|
</span>
|
||||||
|
<span class="about-verify-text">
|
||||||
|
<strong data-i18n="about.verifyLink">Как проверить</strong>
|
||||||
|
<span data-i18n="about.verifyHint">Что видит сервер и как работает ключ в #…</span>
|
||||||
|
</span>
|
||||||
|
<i class="fa-solid fa-arrow-right about-verify-arrow" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-actions">
|
<div class="modal-actions">
|
||||||
<button type="button" class="btn primary" data-about-close data-i18n="about.close">Понятно</button>
|
<button type="button" class="btn primary" data-about-close data-i18n="about.close">Понятно</button>
|
||||||
@@ -84,7 +87,6 @@
|
|||||||
<script src="{{ static_url('js/theme.js') }}"></script>
|
<script src="{{ static_url('js/theme.js') }}"></script>
|
||||||
<script src="{{ static_url('js/ui.js') }}"></script>
|
<script src="{{ static_url('js/ui.js') }}"></script>
|
||||||
<script src="{{ static_url('js/about.js') }}"></script>
|
<script src="{{ static_url('js/about.js') }}"></script>
|
||||||
<script src="{{ static_url('js/install.js') }}"></script>
|
|
||||||
<script src="{{ static_url('js/highlight-ui.js') }}"></script>
|
<script src="{{ static_url('js/highlight-ui.js') }}"></script>
|
||||||
{% block scripts %}{% endblock %}
|
{% block scripts %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user