first commit
This commit is contained in:
Executable
+99
@@ -0,0 +1,99 @@
|
||||
// assets/js/autosave.js
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const contentTextarea = document.getElementById('content');
|
||||
const titleInput = document.getElementById('title');
|
||||
const statusSelect = document.getElementById('status');
|
||||
|
||||
// Проверяем, что это редактирование существующей главы
|
||||
// Если в URL есть параметр 'id', значит это редактирование
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const isEditMode = urlParams.has('id');
|
||||
|
||||
if (!contentTextarea || !isEditMode) {
|
||||
console.log('Автосохранение отключено: создание новой главы');
|
||||
return;
|
||||
}
|
||||
|
||||
let saveTimeout;
|
||||
let isSaving = false;
|
||||
let lastSavedContent = contentTextarea.value;
|
||||
|
||||
function showSaveMessage(message) {
|
||||
let messageEl = document.getElementById('autosave-message');
|
||||
if (!messageEl) {
|
||||
messageEl = document.createElement('div');
|
||||
messageEl.id = 'autosave-message';
|
||||
messageEl.style.cssText = 'position: fixed; top: 10px; right: 10px; padding: 8px 12px; background: #333; color: white; border-radius: 3px; z-index: 1000; font-size: 0.8rem;';
|
||||
document.body.appendChild(messageEl);
|
||||
}
|
||||
|
||||
messageEl.textContent = message;
|
||||
messageEl.style.display = 'block';
|
||||
|
||||
setTimeout(() => {
|
||||
messageEl.style.display = 'none';
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
function autoSave() {
|
||||
if (isSaving) return;
|
||||
|
||||
const currentContent = contentTextarea.value;
|
||||
const currentTitle = titleInput ? titleInput.value : '';
|
||||
const currentStatus = statusSelect ? statusSelect.value : 'draft';
|
||||
|
||||
if (currentContent === lastSavedContent) return;
|
||||
|
||||
isSaving = true;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('content', currentContent);
|
||||
formData.append('title', currentTitle);
|
||||
formData.append('status', currentStatus);
|
||||
formData.append('autosave', 'true');
|
||||
formData.append('csrf_token', document.querySelector('input[name="csrf_token"]').value);
|
||||
|
||||
fetch(window.location.href, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
lastSavedContent = currentContent;
|
||||
showSaveMessage('Сохранено: ' + new Date().toLocaleTimeString());
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Ошибка автосохранения:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
contentTextarea.addEventListener('input', function() {
|
||||
clearTimeout(saveTimeout);
|
||||
saveTimeout = setTimeout(autoSave, 2000);
|
||||
});
|
||||
|
||||
if (titleInput) {
|
||||
titleInput.addEventListener('input', function() {
|
||||
clearTimeout(saveTimeout);
|
||||
saveTimeout = setTimeout(autoSave, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
if (statusSelect) {
|
||||
statusSelect.addEventListener('change', autoSave);
|
||||
}
|
||||
|
||||
window.addEventListener('beforeunload', function(e) {
|
||||
if (contentTextarea.value !== lastSavedContent) {
|
||||
e.preventDefault();
|
||||
e.returnValue = 'У вас есть несохраненные изменения. Вы уверены, что хотите уйти?';
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Автосохранение включено для редактирования главы');
|
||||
});
|
||||
Executable
+563
@@ -0,0 +1,563 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const contentTextarea = document.getElementById('content');
|
||||
const previewForm = document.getElementById('preview-form');
|
||||
|
||||
if (!contentTextarea) return;
|
||||
|
||||
let isFullscreen = false;
|
||||
let originalStyles = {};
|
||||
let isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
|
||||
initEditor();
|
||||
|
||||
function initEditor() {
|
||||
autoResize();
|
||||
contentTextarea.addEventListener('input', autoResize);
|
||||
contentTextarea.addEventListener('input', processDialogues);
|
||||
contentTextarea.addEventListener('keydown', handleTab);
|
||||
contentTextarea.addEventListener('input', updatePreviewContent);
|
||||
|
||||
updatePreviewContent();
|
||||
addControlButtons();
|
||||
|
||||
// На мобильных устройствах добавляем обработчик изменения ориентации
|
||||
if (isMobile) {
|
||||
window.addEventListener('orientationchange', function() {
|
||||
if (isFullscreen) {
|
||||
setTimeout(adjustForMobileKeyboard, 300);
|
||||
}
|
||||
});
|
||||
|
||||
// Обработчик для виртуальной клавиатуры
|
||||
window.addEventListener('resize', function() {
|
||||
if (isFullscreen && isMobile) {
|
||||
adjustForMobileKeyboard();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function autoResize() {
|
||||
if (isFullscreen) return;
|
||||
|
||||
contentTextarea.style.height = 'auto';
|
||||
contentTextarea.style.height = contentTextarea.scrollHeight + 'px';
|
||||
}
|
||||
|
||||
function processDialogues() {
|
||||
const lines = contentTextarea.value.split('\n');
|
||||
let changed = false;
|
||||
|
||||
const processedLines = lines.map(line => {
|
||||
if (line.trim().startsWith('- ') && line.trim().length > 2) {
|
||||
const trimmed = line.trim();
|
||||
const restOfLine = trimmed.substring(2);
|
||||
if (/^[a-zA-Zа-яА-Я]/.test(restOfLine)) {
|
||||
changed = true;
|
||||
return line.replace(trimmed, `— ${restOfLine}`);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
const cursorPos = contentTextarea.selectionStart;
|
||||
contentTextarea.value = processedLines.join('\n');
|
||||
contentTextarea.setSelectionRange(cursorPos, cursorPos);
|
||||
if (!isFullscreen) autoResize();
|
||||
}
|
||||
}
|
||||
|
||||
function handleTab(e) {
|
||||
if (e.key === 'Tab') {
|
||||
e.preventDefault();
|
||||
const start = contentTextarea.selectionStart;
|
||||
const end = contentTextarea.selectionEnd;
|
||||
|
||||
contentTextarea.value = contentTextarea.value.substring(0, start) + ' ' + contentTextarea.value.substring(end);
|
||||
contentTextarea.selectionStart = contentTextarea.selectionEnd = start + 4;
|
||||
if (!isFullscreen) autoResize();
|
||||
}
|
||||
}
|
||||
|
||||
function updatePreviewContent() {
|
||||
if (previewForm) {
|
||||
document.getElementById('preview-content').value = contentTextarea.value;
|
||||
}
|
||||
}
|
||||
|
||||
function adjustForMobileKeyboard() {
|
||||
if (!isMobile || !isFullscreen) return;
|
||||
|
||||
// На мобильных устройствах уменьшаем высоту textarea, чтобы клавиатура не перекрывала контент
|
||||
const viewportHeight = window.innerHeight;
|
||||
const keyboardHeight = viewportHeight * 0.4; // Предполагаемая высота клавиатуры (40% экрана)
|
||||
const availableHeight = viewportHeight - keyboardHeight - 80; // 80px для кнопок и отступов
|
||||
|
||||
contentTextarea.style.height = availableHeight + 'px';
|
||||
contentTextarea.style.paddingBottom = '20px';
|
||||
|
||||
// Прокручиваем к курсору
|
||||
setTimeout(() => {
|
||||
const cursorPos = contentTextarea.selectionStart;
|
||||
if (cursorPos > 0) {
|
||||
scrollToCursor();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function scrollToCursor() {
|
||||
const textarea = contentTextarea;
|
||||
const cursorPos = textarea.selectionStart;
|
||||
|
||||
// Создаем временный элемент для измерения позиции курсора
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.style.cssText = `
|
||||
position: absolute;
|
||||
top: -1000px;
|
||||
left: -1000px;
|
||||
width: ${textarea.clientWidth}px;
|
||||
padding: ${textarea.style.padding};
|
||||
font: ${getComputedStyle(textarea).font};
|
||||
line-height: ${textarea.style.lineHeight};
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
visibility: hidden;
|
||||
`;
|
||||
|
||||
const textBeforeCursor = textarea.value.substring(0, cursorPos);
|
||||
tempDiv.textContent = textBeforeCursor;
|
||||
|
||||
document.body.appendChild(tempDiv);
|
||||
const textHeight = tempDiv.offsetHeight;
|
||||
document.body.removeChild(tempDiv);
|
||||
|
||||
// Прокручиваем так, чтобы курсор был виден
|
||||
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 24;
|
||||
const visibleHeight = textarea.clientHeight;
|
||||
const cursorLine = Math.floor(textHeight / lineHeight);
|
||||
const visibleLines = Math.floor(visibleHeight / lineHeight);
|
||||
|
||||
const targetScroll = Math.max(0, (cursorLine - Math.floor(visibleLines / 3)) * lineHeight);
|
||||
|
||||
textarea.scrollTop = targetScroll;
|
||||
}
|
||||
|
||||
function addControlButtons() {
|
||||
const container = contentTextarea.parentElement;
|
||||
|
||||
const controlsContainer = document.createElement('div');
|
||||
controlsContainer.className = 'editor-controls';
|
||||
|
||||
const fullscreenBtn = createButton('⛶', 'Полноэкранный режим', toggleFullscreen);
|
||||
const helpBtn = createButton('❓', 'Справка по Markdown', showHelp);
|
||||
|
||||
controlsContainer.appendChild(fullscreenBtn);
|
||||
controlsContainer.appendChild(helpBtn);
|
||||
|
||||
container.insertBefore(controlsContainer, contentTextarea);
|
||||
|
||||
function toggleFullscreen() {
|
||||
if (!isFullscreen) {
|
||||
enterFullscreen();
|
||||
} else {
|
||||
exitFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
function enterFullscreen() {
|
||||
originalStyles = {
|
||||
position: contentTextarea.style.position,
|
||||
top: contentTextarea.style.top,
|
||||
left: contentTextarea.style.left,
|
||||
width: contentTextarea.style.width,
|
||||
height: contentTextarea.style.height,
|
||||
zIndex: contentTextarea.style.zIndex,
|
||||
backgroundColor: contentTextarea.style.backgroundColor,
|
||||
border: contentTextarea.style.border,
|
||||
borderRadius: contentTextarea.style.borderRadius,
|
||||
fontSize: contentTextarea.style.fontSize,
|
||||
padding: contentTextarea.style.padding,
|
||||
margin: contentTextarea.style.margin
|
||||
};
|
||||
|
||||
if (isMobile) {
|
||||
// Для мобильных - адаптивный режим с учетом клавиатуры
|
||||
const viewportHeight = window.innerHeight;
|
||||
const availableHeight = viewportHeight - 100; // Оставляем место для кнопок
|
||||
|
||||
Object.assign(contentTextarea.style, {
|
||||
position: 'fixed',
|
||||
top: '50px',
|
||||
left: '0',
|
||||
width: '100vw',
|
||||
height: availableHeight + 'px',
|
||||
zIndex: '9998',
|
||||
backgroundColor: 'white',
|
||||
border: '2px solid #007bff',
|
||||
borderRadius: '0',
|
||||
fontSize: '18px',
|
||||
padding: '15px',
|
||||
margin: '0',
|
||||
boxSizing: 'border-box',
|
||||
resize: 'none'
|
||||
});
|
||||
|
||||
// На мобильных устройствах фокусируем textarea сразу
|
||||
setTimeout(() => {
|
||||
contentTextarea.focus();
|
||||
}, 300);
|
||||
} else {
|
||||
// Для ПК - классический полноэкранный режим
|
||||
Object.assign(contentTextarea.style, {
|
||||
position: 'fixed',
|
||||
top: '5vh',
|
||||
left: '5vw',
|
||||
width: '90vw',
|
||||
height: '90vh',
|
||||
zIndex: '9998',
|
||||
backgroundColor: 'white',
|
||||
border: '2px solid #007bff',
|
||||
borderRadius: '8px',
|
||||
fontSize: '16px',
|
||||
padding: '20px',
|
||||
margin: '0',
|
||||
boxSizing: 'border-box',
|
||||
resize: 'none'
|
||||
});
|
||||
}
|
||||
|
||||
controlsContainer.style.display = 'none';
|
||||
createFullscreenControls();
|
||||
|
||||
isFullscreen = true;
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function exitFullscreen() {
|
||||
Object.assign(contentTextarea.style, originalStyles);
|
||||
|
||||
controlsContainer.style.display = 'flex';
|
||||
removeFullscreenControls();
|
||||
|
||||
isFullscreen = false;
|
||||
document.body.style.overflow = '';
|
||||
|
||||
autoResize();
|
||||
}
|
||||
|
||||
function createFullscreenControls() {
|
||||
const fullscreenControls = document.createElement('div');
|
||||
fullscreenControls.id = 'fullscreen-controls';
|
||||
|
||||
const exitBtn = createButton('❌', 'Выйти из полноэкранного режима', exitFullscreen);
|
||||
const helpBtnFullscreen = createButton('❓', 'Справка по Markdown', showHelp);
|
||||
|
||||
// Для мобильных увеличиваем кнопки и добавляем отступы
|
||||
const buttonSize = isMobile ? '60px' : '50px';
|
||||
const fontSize = isMobile ? '24px' : '20px';
|
||||
const topPosition = isMobile ? '10px' : '15px';
|
||||
|
||||
[exitBtn, helpBtnFullscreen].forEach(btn => {
|
||||
btn.style.cssText = `
|
||||
width: ${buttonSize};
|
||||
height: ${buttonSize};
|
||||
border-radius: 50%;
|
||||
border: 1px solid #ddd;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
font-size: ${fontSize};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
|
||||
transition: all 0.3s ease;
|
||||
color: #333333;
|
||||
touch-action: manipulation;
|
||||
`;
|
||||
});
|
||||
|
||||
fullscreenControls.appendChild(helpBtnFullscreen);
|
||||
fullscreenControls.appendChild(exitBtn);
|
||||
|
||||
fullscreenControls.style.cssText = `
|
||||
position: fixed;
|
||||
top: ${topPosition};
|
||||
right: 10px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
`;
|
||||
|
||||
document.body.appendChild(fullscreenControls);
|
||||
|
||||
// Предотвращаем всплытие событий от кнопок к textarea
|
||||
fullscreenControls.addEventListener('touchstart', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
fullscreenControls.addEventListener('touchend', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
function removeFullscreenControls() {
|
||||
const fullscreenControls = document.getElementById('fullscreen-controls');
|
||||
if (fullscreenControls) {
|
||||
fullscreenControls.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Выход по ESC
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape' && isFullscreen) {
|
||||
exitFullscreen();
|
||||
}
|
||||
});
|
||||
|
||||
// На мобильных устройствах добавляем обработчик для выхода по тапу вне textarea
|
||||
if (isMobile) {
|
||||
document.addEventListener('touchstart', function(e) {
|
||||
if (isFullscreen && !contentTextarea.contains(e.target) &&
|
||||
!document.getElementById('fullscreen-controls')?.contains(e.target)) {
|
||||
exitFullscreen();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Обработчик фокуса для мобильных устройств
|
||||
if (isMobile) {
|
||||
contentTextarea.addEventListener('focus', function() {
|
||||
if (isFullscreen) {
|
||||
setTimeout(adjustForMobileKeyboard, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createButton(icon, title, onClick) {
|
||||
const button = document.createElement('button');
|
||||
button.innerHTML = icon;
|
||||
button.title = title;
|
||||
button.type = 'button';
|
||||
|
||||
const buttonSize = isMobile ? '50px' : '40px';
|
||||
const fontSize = isMobile ? '20px' : '16px';
|
||||
|
||||
button.style.cssText = `
|
||||
width: ${buttonSize};
|
||||
height: ${buttonSize};
|
||||
border-radius: 50%;
|
||||
border: 1px solid #ddd;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
font-size: ${fontSize};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||
transition: all 0.3s ease;
|
||||
color: #333333;
|
||||
touch-action: manipulation;
|
||||
`;
|
||||
|
||||
button.addEventListener('mouseenter', function() {
|
||||
this.style.transform = 'scale(1.1)';
|
||||
this.style.backgroundColor = '#f8f9fa';
|
||||
this.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
|
||||
});
|
||||
|
||||
button.addEventListener('mouseleave', function() {
|
||||
this.style.transform = 'scale(1)';
|
||||
this.style.backgroundColor = 'white';
|
||||
this.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
|
||||
});
|
||||
|
||||
button.addEventListener('click', onClick);
|
||||
|
||||
// Для мобильных устройств
|
||||
button.addEventListener('touchstart', function(e) {
|
||||
e.stopPropagation();
|
||||
this.style.transform = 'scale(1.1)';
|
||||
this.style.backgroundColor = '#f8f9fa';
|
||||
this.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
|
||||
});
|
||||
|
||||
button.addEventListener('touchend', function(e) {
|
||||
e.stopPropagation();
|
||||
this.style.transform = 'scale(1)';
|
||||
this.style.backgroundColor = 'white';
|
||||
this.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
|
||||
onClick();
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
function showHelp() {
|
||||
const helpContent = `
|
||||
<div style="font-family: system-ui, sans-serif; line-height: 1.6; color: #333;">
|
||||
<h1 style="color: #007bff; margin-top: 0; border-bottom: 2px solid #007bff; padding-bottom: 10px;">Справка по Markdown</h1>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<h2 style="color: #555;">Основное форматирование</h2>
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; border-left: 4px solid #007bff;">
|
||||
<p><strong>Жирный текст:</strong> **текст** или __текст__</p>
|
||||
<p><em>Наклонный текст:</em> *текст* или _текст_</p>
|
||||
<p><u>Подчеркнутый текст:</u> <u>текст</u></p>
|
||||
<p><del>Зачеркнутый текст:</del> ~~текст~~</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<h2 style="color: #555;">Заголовки</h2>
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; border-left: 4px solid #28a745;">
|
||||
<h1 style="margin: 10px 0; font-size: 1.5em;">Заголовок 1 (# Заголовок)</h1>
|
||||
<h2 style="margin: 10px 0; font-size: 1.3em;">Заголовок 2 (## Заголовок)</h2>
|
||||
<h3 style="margin: 10px 0; font-size: 1.1em;">Заголовок 3 (### Заголовок)</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<h2 style="color: #555;">Цитаты</h2>
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; border-left: 4px solid #ffc107;">
|
||||
<blockquote style="margin: 0; padding-left: 15px; border-left: 3px solid #ddd; color: #666;">
|
||||
> Это цитата
|
||||
</blockquote>
|
||||
<blockquote style="margin: 10px 0 0 20px; padding-left: 15px; border-left: 3px solid #ddd; color: #666;">
|
||||
> > Вложенная цитата
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<h2 style="color: #555;">Диалоги</h2>
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; border-left: 4px solid #dc3545;">
|
||||
<p><strong>Автоматическое преобразование:</strong></p>
|
||||
<p><code>- Привет!</code> → <em>— Привет!</em></p>
|
||||
<p style="font-size: 0.9em; color: #666; margin-top: 5px;">
|
||||
Дефис в начале строки автоматически заменяется на тире с пробелом
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<h2 style="color: #555;">Списки</h2>
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; border-left: 4px solid #6f42c1;">
|
||||
<p><strong>Маркированный список:</strong></p>
|
||||
<ul style="margin: 10px 0; padding-left: 20px;">
|
||||
<li>- Элемент списка</li>
|
||||
<li>- Другой элемент</li>
|
||||
</ul>
|
||||
<p><strong>Нумерованный список:</strong></p>
|
||||
<ol style="margin: 10px 0; padding-left: 20px;">
|
||||
<li>1. Первый элемент</li>
|
||||
<li>2. Второй элемент</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<h2 style="color: #555;">Код</h2>
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; border-left: 4px solid #fd7e14;">
|
||||
<p><strong>Код в строке:</strong></p>
|
||||
<p><code>\`код в строке\`</code></p>
|
||||
<p><strong>Блок кода:</strong></p>
|
||||
<pre style="background: #e9ecef; padding: 10px; border-radius: 3px; overflow-x: auto; margin: 10px 0;">
|
||||
\`\`\`
|
||||
блок кода
|
||||
многострочный
|
||||
\`\`\`</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background: #e7f3ff; padding: 15px; border-radius: 5px; border-left: 4px solid #007bff; margin-top: 20px;">
|
||||
<p style="margin: 0; font-size: 0.9em;"><strong>💡 Подсказка:</strong> Используйте кнопку "👁️ Предпросмотр" чтобы увидеть как будет выглядеть готовый текст!</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const modal = document.createElement('div');
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: white;
|
||||
border: 2px solid #007bff;
|
||||
border-radius: 10px;
|
||||
padding: 25px;
|
||||
z-index: 10000;
|
||||
width: 90%;
|
||||
max-width: 700px;
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
|
||||
`;
|
||||
|
||||
const closeBtn = document.createElement('button');
|
||||
closeBtn.innerHTML = '✕';
|
||||
closeBtn.title = 'Закрыть справку';
|
||||
closeBtn.style.cssText = `
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
background: #ff4444;
|
||||
color: white;
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.3s ease;
|
||||
`;
|
||||
|
||||
closeBtn.addEventListener('mouseenter', function() {
|
||||
this.style.background = '#cc0000';
|
||||
});
|
||||
|
||||
closeBtn.addEventListener('mouseleave', function() {
|
||||
this.style.background = '#ff4444';
|
||||
});
|
||||
|
||||
closeBtn.addEventListener('click', function() {
|
||||
modal.remove();
|
||||
overlay.remove();
|
||||
});
|
||||
|
||||
modal.innerHTML = helpContent;
|
||||
modal.appendChild(closeBtn);
|
||||
|
||||
const overlay = document.createElement('div');
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 9999;
|
||||
`;
|
||||
|
||||
overlay.addEventListener('click', function() {
|
||||
modal.remove();
|
||||
overlay.remove();
|
||||
});
|
||||
|
||||
document.body.appendChild(overlay);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
const closeHandler = function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
modal.remove();
|
||||
overlay.remove();
|
||||
document.removeEventListener('keydown', closeHandler);
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', closeHandler);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user