preland#18 #19: popup ошибки загрузки и однострочный ИИ-заголовок
deploy-preland / deploy zoomstage.online (push) Successful in 55s

This commit is contained in:
Panfilov Konstantin committed 2026-10-24 10:59:20 +03:00
1 parent f4ce5afdc4
commit f30742c2fb
4 files changed
+74 -16

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
<?php
/** api#321: ошибка загрузки поверх страницы, без перестройки первого экрана. */
$uploadErrorCopy = json_encode([
'title' => Yii::t('app', 'Ошибка связи'),
'network' => Yii::t('app', 'Не удалось загрузить изображение. Проверьте подключение к интернету и попробуйте ещё раз.'),
'other' => Yii::t('app', 'Не удалось загрузить изображение'),
'fallback' => Yii::t('app', 'Попробуйте ещё раз.'),
], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
?>
<style>
.upload-error-popup{position:fixed;inset:0;z-index:10000;background:rgba(0,0,0,.65);display:flex;align-items:center;justify-content:center;padding:20px;box-sizing:border-box;overflow:auto}
.upload-error-popup[hidden]{display:none!important}
.upload-error-popup .upload-error-card{position:relative;width:100%;max-width:440px;padding:38px 32px 30px;text-align:center;border-radius:24px;border:1px solid rgba(255,255,255,.15);box-shadow:0 20px 80px #0008;background:#484848 linear-gradient(to bottom,rgba(61,135,227,.25),rgba(153,6,148,.25));color:#fff;box-sizing:border-box;font-family:Inter,sans-serif;max-height:100%;overflow:auto}
.upload-error-popup .upload-error-card:focus{outline:none}
.upload-error-popup h2{font-size:24px;line-height:1.3;font-weight:600;margin:0 0 16px;color:inherit}
.upload-error-popup p{font-size:16px;line-height:24px;color:#e5e5e7;margin:0 0 24px;overflow-wrap:anywhere;white-space:pre-line}
.upload-error-popup .upload-error-close{position:absolute;top:5px;right:5px;display:flex;align-items:center;justify-content:center;width:44px;height:44px;border:0;background:none;color:#e5e5e7;cursor:pointer;font-size:28px;line-height:1}
.upload-error-popup .upload-error-ok{min-width:160px;height:48px;border-radius:16px;padding:0 28px;font:500 16px Inter,sans-serif;color:#fff;border:0;cursor:pointer;background:linear-gradient(180deg,#3d87e3 0%,#990694 100%)}
.upload-error-popup button:focus-visible{outline:2px solid #fff;outline-offset:3px}
@media(max-width:767.98px){.upload-error-popup .upload-error-card{padding:36px 24px 24px}.upload-error-popup h2{font-size:22px}.upload-error-popup p{font-size:15px;line-height:23px;margin-bottom:22px}.upload-error-popup .upload-error-ok{width:100%}}
</style>
<div class="upload-error-popup" id="upload-error-popup" hidden role="alertdialog" aria-modal="true" aria-labelledby="upload-error-title" aria-describedby="upload-error-text">
<div class="upload-error-card" tabindex="-1">
<button class="upload-error-close" type="button" aria-label="<?= htmlspecialchars(Yii::t('app', 'Закрыть'), ENT_QUOTES, 'UTF-8') ?>">×</button>
<h2 id="upload-error-title"></h2>
<p id="upload-error-text"></p>
<button class="upload-error-ok" type="button">OK</button>
</div>
</div>
<script>
(() => {
const popup=document.getElementById('upload-error-popup');
if(!popup || window.ZoomzillaUploadError) return;
document.body.appendChild(popup);
const copy=<?= $uploadErrorCopy ?>, card=popup.querySelector('.upload-error-card');
const close=popup.querySelector('.upload-error-close'), ok=popup.querySelector('.upload-error-ok');
let previousOverflow='', previousFocus=null;
function hide(){
if(popup.hidden)return;
popup.hidden=true;document.body.style.overflow=previousOverflow;
const target=document.querySelector('#dropzone-form .dropzone-form-button') || previousFocus;
if(target && !target.disabled && target.isConnected)target.focus({preventScroll:true});
}
window.ZoomzillaUploadError={show(message,connection=false){
if(popup.hidden){previousOverflow=document.body.style.overflow;previousFocus=document.activeElement;}
popup.querySelector('h2').textContent=connection?copy.title:copy.other;
popup.querySelector('p').textContent=connection?copy.network:(message||copy.fallback);
popup.hidden=false;document.body.style.overflow='hidden';card.focus({preventScroll:true});
},hide};
close.addEventListener('click',hide);ok.addEventListener('click',hide);
popup.addEventListener('keydown',event=>{
if(event.key==='Escape'){event.preventDefault();hide();return;}
if(event.key==='Tab'){
event.preventDefault();
if(document.activeElement===close)ok.focus();else if(document.activeElement===ok)close.focus();else(event.shiftKey?ok:close).focus();
}
});
})();
</script>