bro.landing/scripts/prerender-multi.js

170 lines
7.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable @typescript-eslint/no-require-imports */
/* eslint-disable no-undef */
const fs = require('fs');
const path = require('path');
// Контент для главной страницы
const homeContent = `
<div>
<div style="max-height: 250px;">
<div>Loading...</div>
</div>
<h3><center>Сайт в разработке</center></h3>
</div>
`.trim();
// Функция для генерации полного HTML из terma.md
const generateTermsContent = () => {
const termaPath = path.resolve(__dirname, '../terma.md');
const termaText = fs.readFileSync(termaPath, 'utf-8');
// Парсим markdown в HTML с сохранением структуры
let html = '<div style="background: #f7fafc; min-height: 100vh; padding: 32px 0;">';
html += '<div style="max-width: 1200px; margin: 0 auto; background: white; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); border-radius: 8px; padding: 60px 80px; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">';
const lines = termaText.split('\n');
let inList = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (!line) {
if (inList) {
html += '</ul>';
inList = false;
}
continue;
}
// Заголовок H1
if (i === 0) {
html += '<div style="text-align: center; margin-bottom: 40px;">';
html += `<h1 style="font-size: 2.5em; color: #2563eb; margin-bottom: 8px; font-weight: 700;">${line}</h1>`;
continue;
}
// Дата обновления
if (line.includes('Последнее обновление')) {
html += `<p style="color: #6b7280; font-size: 0.875em;">${line}</p>`;
html += '</div><hr style="border: 0; border-top: 1px solid #e5e7eb; margin: 24px 0;">';
continue;
}
// Основные разделы (начинаются с цифры и точки без подразделов)
if (/^\d+\.\s+[А-Яа-я]/.test(line)) {
if (inList) {
html += '</ul>';
inList = false;
}
const text = line.replace(/^\d+\.\s+/, '');
html += `<h2 style="font-size: 1.875em; color: #1e40af; margin-top: 40px; margin-bottom: 16px; font-weight: 600;">${line}</h2>`;
continue;
}
// Подразделы (например, 2.1., 3.2.)
if (/^\d+\.\d+\.\s+/.test(line)) {
if (inList) {
html += '</ul>';
inList = false;
}
html += `<h3 style="font-size: 1.25em; color: #374151; margin-top: 24px; margin-bottom: 12px; font-weight: 600;">${line}</h3>`;
continue;
}
// Списки (начинаются с заглавной буквы или содержат "—")
if (line.includes('—') || (i > 0 && lines[i-1].includes('через:')) || (i > 0 && lines[i-1].includes('обязуется:')) || (i > 0 && lines[i-1].includes('собирает:')) || (i > 0 && lines[i-1].includes('ответственности за:'))) {
if (!inList) {
html += '<ul style="list-style-type: disc; padding-left: 32px; margin: 12px 0;">';
inList = true;
}
// Обработка ссылок
let processedLine = line
.replace(/https?:\/\/[^\s,)]+/g, (url) => {
const cleanUrl = url.replace(/\s*,?\s*$/, '');
return `<a href="${cleanUrl}" style="color: #3b82f6; text-decoration: underline;">${cleanUrl}</a>`;
})
.replace(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g,
'<a href="mailto:$1" style="color: #3b82f6; text-decoration: underline;">$1</a>');
html += `<li style="margin: 8px 0; line-height: 1.75;">${processedLine}</li>`;
continue;
}
// Обычные параграфы
if (inList && !line.includes('—')) {
html += '</ul>';
inList = false;
}
// Обработка жирного текста и ссылок
let processedLine = line
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
.replace(/https?:\/\/[^\s,)]+/g, (url) => {
const cleanUrl = url.replace(/\s*,?\s*$/, '');
return `<a href="${cleanUrl}" style="color: #3b82f6; text-decoration: underline;">${cleanUrl}</a>`;
})
.replace(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g,
'<a href="mailto:$1" style="color: #3b82f6; text-decoration: underline;">$1</a>');
html += `<p style="margin: 12px 0; line-height: 1.75; color: #374151;">${processedLine}</p>`;
}
if (inList) {
html += '</ul>';
}
// Footer
html += '<hr style="border: 0; border-top: 1px solid #e5e7eb; margin: 48px 0 24px 0;">';
html += '<p style="text-align: center; color: #6b7280; font-size: 0.875em;">© 2025 BROJS.RU. Все права защищены.</p>';
html += '</div></div>';
return html;
};
const prerender = () => {
try {
console.log('🚀 Начинаем мульти-страничный пре-рендеринг...');
const distPath = path.resolve(__dirname, '../dist');
const indexPath = path.join(distPath, 'index.html');
// Читаем основной HTML
let indexHtml = fs.readFileSync(indexPath, 'utf-8');
// 1. Обрабатываем главную страницу
const searchString = '<div id="app"></div>';
if (indexHtml.includes(searchString)) {
indexHtml = indexHtml.replace(searchString, `<div id="app">${homeContent}</div>`);
fs.writeFileSync(indexPath, indexHtml, 'utf-8');
console.log('✅ index.html обновлен');
}
// 2. Генерируем полный контент для terms.html из terma.md
console.log('📝 Генерируем полный HTML из terma.md...');
const termsContent = generateTermsContent();
// 3. Создаем terms.html на основе index.html
let termsHtml = indexHtml
.replace(homeContent, termsContent)
.replace('<title>bro-js admin</title>', '<title>Пользовательское соглашение - BROJS.RU</title>')
.replace(
'</head>',
'<meta name="description" content="Полное пользовательское соглашение для платформы обучения фронтенд-разработке BROJS.RU. Условия использования, обработка персональных данных, права и обязанности сторон." /></head>'
);
const termsPath = path.join(distPath, 'terms.html');
fs.writeFileSync(termsPath, termsHtml, 'utf-8');
console.log('✅ terms.html создан с полным контентом');
console.log('🎉 Пре-рендеринг завершен успешно!');
console.log('📄 Созданы файлы: index.html, terms.html');
console.log('💡 terms.html содержит полный текст соглашения для SEO');
} catch (error) {
console.error('❌ Ошибка при пре-рендеринге:', error);
process.exit(1);
}
};
prerender();